]> Git Repo - VerusCoin.git/blame - src/wallet/rpcwallet.cpp
1.0.2 release.
[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"
ae775b5b 8#include "core_io.h"
e3bc5698 9#include "init.h"
8a893c94 10#include "main.h"
51ed9ec9
BD
11#include "net.h"
12#include "netbase.h"
8a893c94 13#include "rpcserver.h"
14f888ca 14#include "timedata.h"
51ed9ec9 15#include "util.h"
b93173de 16#include "utilmoneystr.h"
51ed9ec9
BD
17#include "wallet.h"
18#include "walletdb.h"
8cb25088 19#include "primitives/transaction.h"
6962bb3d 20#include "zcbenchmarks.h"
6aae9d1a 21#include "script/interpreter.h"
51ed9ec9 22
fc72c078
S
23#include "utiltime.h"
24#include "asyncrpcoperation.h"
25#include "wallet/asyncrpcoperation_sendmany.h"
26
320f2cc7
SB
27#include "sodium.h"
28
51ed9ec9
BD
29#include <stdint.h>
30
31#include <boost/assign/list_of.hpp>
25cf6f3d 32
51ed9ec9
BD
33#include "json/json_spirit_utils.h"
34#include "json/json_spirit_value.h"
fc72c078 35#include "asyncrpcqueue.h"
e3bc5698 36
e3bc5698 37using namespace std;
fdbb537d 38using namespace json_spirit;
e3bc5698 39
2dc35992
SB
40using namespace libzcash;
41
f7cfb52d
S
42extern Array TxJoinSplitToJSON(const CTransaction& tx);
43
51ed9ec9 44int64_t nWalletUnlockTime;
e3bc5698
JG
45static CCriticalSection cs_nWalletUnlockTime;
46
c1eae280
S
47// Private method:
48Value z_getoperationstatus_IMPL(const Array&, bool);
49
bdab0cf5 50std::string HelpRequiringPassphrase()
e3bc5698 51{
b0730874 52 return pwalletMain && pwalletMain->IsCrypted()
a6099ef3 53 ? "\nRequires wallet passphrase to be set with walletpassphrase call."
e3bc5698
JG
54 : "";
55}
56
b9fb692d
JS
57bool EnsureWalletIsAvailable(bool avoidException)
58{
59 if (!pwalletMain)
60 {
61 if (!avoidException)
62 throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
63 else
64 return false;
65 }
66 return true;
67}
68
bdab0cf5 69void EnsureWalletIsUnlocked()
e3bc5698
JG
70{
71 if (pwalletMain->IsLocked())
738835d7 72 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
e3bc5698
JG
73}
74
75void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
76{
77 int confirms = wtx.GetDepthInMainChain();
78 entry.push_back(Pair("confirmations", confirms));
e07c8e91
LD
79 if (wtx.IsCoinBase())
80 entry.push_back(Pair("generated", true));
2b72d46f 81 if (confirms > 0)
e3bc5698
JG
82 {
83 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
84 entry.push_back(Pair("blockindex", wtx.nIndex));
209377a7 85 entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
e3bc5698 86 }
805344dc 87 uint256 hash = wtx.GetHash();
731b89b8
GA
88 entry.push_back(Pair("txid", hash.GetHex()));
89 Array conflicts;
90 BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
91 conflicts.push_back(conflict.GetHex());
92 entry.push_back(Pair("walletconflicts", conflicts));
d56e30ca 93 entry.push_back(Pair("time", wtx.GetTxTime()));
4b61a6a4 94 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
e3bc5698
JG
95 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
96 entry.push_back(Pair(item.first, item.second));
f7cfb52d
S
97
98 entry.push_back(Pair("vjoinsplit", TxJoinSplitToJSON(wtx)));
e3bc5698
JG
99}
100
101string AccountFromValue(const Value& value)
102{
103 string strAccount = value.get_str();
3c31eb24 104 if (strAccount != "")
7b3351ff 105 throw JSONRPCError(RPC_WALLET_ACCOUNTS_UNSUPPORTED, "Accounts are unsupported");
e3bc5698
JG
106 return strAccount;
107}
108
109Value getnewaddress(const Array& params, bool fHelp)
110{
b9fb692d
JS
111 if (!EnsureWalletIsAvailable(fHelp))
112 return Value::null;
113
e3bc5698
JG
114 if (fHelp || params.size() > 1)
115 throw runtime_error(
a6099ef3 116 "getnewaddress ( \"account\" )\n"
58c4c0bb 117 "\nReturns a new Zcash address for receiving payments.\n"
a6099ef3 118 "\nArguments:\n"
3c31eb24 119 "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 120 "\nResult:\n"
58c4c0bb 121 "\"zcashaddress\" (string) The new zcash address\n"
a6099ef3 122 "\nExamples:\n"
123 + HelpExampleCli("getnewaddress", "")
7b782f5b 124 + HelpExampleRpc("getnewaddress", "")
a6099ef3 125 );
e3bc5698 126
4401b2d7
EL
127 LOCK2(cs_main, pwalletMain->cs_wallet);
128
e3bc5698
JG
129 // Parse the account first so we don't generate a key if there's an error
130 string strAccount;
131 if (params.size() > 0)
132 strAccount = AccountFromValue(params[0]);
133
134 if (!pwalletMain->IsLocked())
135 pwalletMain->TopUpKeyPool();
136
137 // Generate a new key that is added to wallet
138 CPubKey newKey;
71ac5052 139 if (!pwalletMain->GetKeyFromPool(newKey))
738835d7 140 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e3bc5698
JG
141 CKeyID keyID = newKey.GetID();
142
a41d5fe0 143 pwalletMain->SetAddressBook(keyID, strAccount, "receive");
e3bc5698
JG
144
145 return CBitcoinAddress(keyID).ToString();
146}
147
148
149CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
150{
151 CWalletDB walletdb(pwalletMain->strWalletFile);
152
153 CAccount account;
154 walletdb.ReadAccount(strAccount, account);
155
156 bool bKeyUsed = false;
157
158 // Check if the current key has been used
159 if (account.vchPubKey.IsValid())
160 {
0be990ba 161 CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
e3bc5698
JG
162 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
163 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
164 ++it)
165 {
166 const CWalletTx& wtx = (*it).second;
167 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
168 if (txout.scriptPubKey == scriptPubKey)
169 bKeyUsed = true;
170 }
171 }
172
173 // Generate a new key
174 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
175 {
71ac5052 176 if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
738835d7 177 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e3bc5698 178
a41d5fe0 179 pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
e3bc5698
JG
180 walletdb.WriteAccount(strAccount, account);
181 }
182
183 return CBitcoinAddress(account.vchPubKey.GetID());
184}
185
186Value getaccountaddress(const Array& params, bool fHelp)
187{
b9fb692d
JS
188 if (!EnsureWalletIsAvailable(fHelp))
189 return Value::null;
190
e3bc5698
JG
191 if (fHelp || params.size() != 1)
192 throw runtime_error(
a6099ef3 193 "getaccountaddress \"account\"\n"
58c4c0bb 194 "\nDEPRECATED. Returns the current Zcash address for receiving payments to this account.\n"
a6099ef3 195 "\nArguments:\n"
3c31eb24 196 "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 197 "\nResult:\n"
58c4c0bb 198 "\"zcashaddress\" (string) The account zcash address\n"
a6099ef3 199 "\nExamples:\n"
200 + HelpExampleCli("getaccountaddress", "")
201 + HelpExampleCli("getaccountaddress", "\"\"")
202 + HelpExampleCli("getaccountaddress", "\"myaccount\"")
203 + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
204 );
e3bc5698 205
4401b2d7
EL
206 LOCK2(cs_main, pwalletMain->cs_wallet);
207
e3bc5698
JG
208 // Parse the account first so we don't generate a key if there's an error
209 string strAccount = AccountFromValue(params[0]);
210
211 Value ret;
212
213 ret = GetAccountAddress(strAccount).ToString();
e3bc5698
JG
214 return ret;
215}
216
217
e5e9904c
JG
218Value getrawchangeaddress(const Array& params, bool fHelp)
219{
b9fb692d
JS
220 if (!EnsureWalletIsAvailable(fHelp))
221 return Value::null;
222
e5e9904c
JG
223 if (fHelp || params.size() > 1)
224 throw runtime_error(
225 "getrawchangeaddress\n"
58c4c0bb 226 "\nReturns a new Zcash address, for receiving change.\n"
a6099ef3 227 "This is for use with raw transactions, NOT normal use.\n"
228 "\nResult:\n"
229 "\"address\" (string) The address\n"
230 "\nExamples:\n"
231 + HelpExampleCli("getrawchangeaddress", "")
232 + HelpExampleRpc("getrawchangeaddress", "")
233 );
e5e9904c 234
4401b2d7
EL
235 LOCK2(cs_main, pwalletMain->cs_wallet);
236
e5e9904c
JG
237 if (!pwalletMain->IsLocked())
238 pwalletMain->TopUpKeyPool();
239
240 CReserveKey reservekey(pwalletMain);
241 CPubKey vchPubKey;
242 if (!reservekey.GetReservedKey(vchPubKey))
6c37f7fd 243 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e5e9904c
JG
244
245 reservekey.KeepKey();
246
247 CKeyID keyID = vchPubKey.GetID();
248
249 return CBitcoinAddress(keyID).ToString();
250}
251
e3bc5698
JG
252
253Value setaccount(const Array& params, bool fHelp)
254{
b9fb692d
JS
255 if (!EnsureWalletIsAvailable(fHelp))
256 return Value::null;
257
e3bc5698
JG
258 if (fHelp || params.size() < 1 || params.size() > 2)
259 throw runtime_error(
58c4c0bb 260 "setaccount \"zcashaddress\" \"account\"\n"
7b782f5b 261 "\nDEPRECATED. Sets the account associated with the given address.\n"
a6099ef3 262 "\nArguments:\n"
58c4c0bb 263 "1. \"zcashaddress\" (string, required) The zcash address to be associated with an account.\n"
3c31eb24 264 "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 265 "\nExamples:\n"
266 + HelpExampleCli("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"tabby\"")
267 + HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"tabby\"")
268 );
e3bc5698 269
4401b2d7
EL
270 LOCK2(cs_main, pwalletMain->cs_wallet);
271
e3bc5698
JG
272 CBitcoinAddress address(params[0].get_str());
273 if (!address.IsValid())
58c4c0bb 274 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
e3bc5698 275
e3bc5698
JG
276 string strAccount;
277 if (params.size() > 1)
278 strAccount = AccountFromValue(params[1]);
279
31d6390f
ES
280 // Only add the account if the address is yours.
281 if (IsMine(*pwalletMain, address.Get()))
e3bc5698 282 {
31d6390f
ES
283 // Detect when changing the account of an address that is the 'unused current key' of another account:
284 if (pwalletMain->mapAddressBook.count(address.Get()))
285 {
286 string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name;
287 if (address == GetAccountAddress(strOldAccount))
288 GetAccountAddress(strOldAccount, true);
289 }
290 pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
e3bc5698 291 }
31d6390f
ES
292 else
293 throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
e3bc5698
JG
294
295 return Value::null;
296}
297
298
299Value getaccount(const Array& params, bool fHelp)
300{
b9fb692d
JS
301 if (!EnsureWalletIsAvailable(fHelp))
302 return Value::null;
303
e3bc5698
JG
304 if (fHelp || params.size() != 1)
305 throw runtime_error(
58c4c0bb 306 "getaccount \"zcashaddress\"\n"
7b782f5b 307 "\nDEPRECATED. Returns the account associated with the given address.\n"
a6099ef3 308 "\nArguments:\n"
58c4c0bb 309 "1. \"zcashaddress\" (string, required) The zcash address for account lookup.\n"
a6099ef3 310 "\nResult:\n"
311 "\"accountname\" (string) the account address\n"
312 "\nExamples:\n"
313 + HelpExampleCli("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
314 + HelpExampleRpc("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
315 );
e3bc5698 316
4401b2d7
EL
317 LOCK2(cs_main, pwalletMain->cs_wallet);
318
e3bc5698
JG
319 CBitcoinAddress address(params[0].get_str());
320 if (!address.IsValid())
58c4c0bb 321 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
e3bc5698
JG
322
323 string strAccount;
61885513
GA
324 map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
325 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty())
326 strAccount = (*mi).second.name;
e3bc5698
JG
327 return strAccount;
328}
329
330
331Value getaddressesbyaccount(const Array& params, bool fHelp)
332{
b9fb692d
JS
333 if (!EnsureWalletIsAvailable(fHelp))
334 return Value::null;
335
e3bc5698
JG
336 if (fHelp || params.size() != 1)
337 throw runtime_error(
a6099ef3 338 "getaddressesbyaccount \"account\"\n"
7b782f5b 339 "\nDEPRECATED. Returns the list of addresses for the given account.\n"
a6099ef3 340 "\nArguments:\n"
3c31eb24 341 "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 342 "\nResult:\n"
343 "[ (json array of string)\n"
58c4c0bb 344 " \"zcashaddress\" (string) a zcash address associated with the given account\n"
a6099ef3 345 " ,...\n"
346 "]\n"
347 "\nExamples:\n"
348 + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
349 + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
350 );
e3bc5698 351
4401b2d7
EL
352 LOCK2(cs_main, pwalletMain->cs_wallet);
353
e3bc5698
JG
354 string strAccount = AccountFromValue(params[0]);
355
356 // Find all addresses that have the given account
357 Array ret;
61885513 358 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
e3bc5698
JG
359 {
360 const CBitcoinAddress& address = item.first;
61885513 361 const string& strName = item.second.name;
e3bc5698
JG
362 if (strName == strAccount)
363 ret.push_back(address.ToString());
364 }
365 return ret;
366}
367
292623ad 368static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew)
b93173de 369{
25cf6f3d
PK
370 CAmount curBalance = pwalletMain->GetBalance();
371
b93173de
PJ
372 // Check amount
373 if (nValue <= 0)
4be639ea 374 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
b93173de 375
25cf6f3d 376 if (nValue > curBalance)
b93173de
PJ
377 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
378
58c4c0bb 379 // Parse Zcash address
b93173de
PJ
380 CScript scriptPubKey = GetScriptForDestination(address);
381
382 // Create and send the transaction
383 CReserveKey reservekey(pwalletMain);
384 CAmount nFeeRequired;
25cf6f3d 385 std::string strError;
292623ad
CL
386 vector<CRecipient> vecSend;
387 int nChangePosRet = -1;
388 CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
389 vecSend.push_back(recipient);
390 if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
391 if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
392 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));
393 throw JSONRPCError(RPC_WALLET_ERROR, strError);
b93173de
PJ
394 }
395 if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
396 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
397}
398
e3bc5698
JG
399Value sendtoaddress(const Array& params, bool fHelp)
400{
b9fb692d
JS
401 if (!EnsureWalletIsAvailable(fHelp))
402 return Value::null;
403
292623ad 404 if (fHelp || params.size() < 2 || params.size() > 5)
e3bc5698 405 throw runtime_error(
58c4c0bb 406 "sendtoaddress \"zcashaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
e743678d 407 "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
a6099ef3 408 + HelpRequiringPassphrase() +
409 "\nArguments:\n"
58c4c0bb 410 "1. \"zcashaddress\" (string, required) The zcash address to send to.\n"
a6099ef3 411 "2. \"amount\" (numeric, required) The amount in btc to send. eg 0.1\n"
412 "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
413 " This is not part of the transaction, just kept in your wallet.\n"
414 "4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
415 " to which you're sending the transaction. This is not part of the \n"
416 " transaction, just kept in your wallet.\n"
292623ad 417 "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
58c4c0bb 418 " The recipient will receive less zcash than you enter in the amount field.\n"
a6099ef3 419 "\nResult:\n"
b5ef85c7 420 "\"transactionid\" (string) The transaction id.\n"
a6099ef3 421 "\nExamples:\n"
422 + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
423 + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"donation\" \"seans outpost\"")
292623ad 424 + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"\" \"\" true")
a6099ef3 425 + HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
426 );
e3bc5698 427
4401b2d7
EL
428 LOCK2(cs_main, pwalletMain->cs_wallet);
429
e3bc5698
JG
430 CBitcoinAddress address(params[0].get_str());
431 if (!address.IsValid())
58c4c0bb 432 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
e3bc5698
JG
433
434 // Amount
a372168e 435 CAmount nAmount = AmountFromValue(params[1]);
e3bc5698
JG
436
437 // Wallet comments
438 CWalletTx wtx;
439 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
440 wtx.mapValue["comment"] = params[2].get_str();
441 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
442 wtx.mapValue["to"] = params[3].get_str();
443
292623ad
CL
444 bool fSubtractFeeFromAmount = false;
445 if (params.size() > 4)
446 fSubtractFeeFromAmount = params[4].get_bool();
447
f914c7a1 448 EnsureWalletIsUnlocked();
e3bc5698 449
292623ad 450 SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, wtx);
e3bc5698 451
805344dc 452 return wtx.GetHash().GetHex();
e3bc5698
JG
453}
454
22dfd735 455Value listaddressgroupings(const Array& params, bool fHelp)
456{
b9fb692d
JS
457 if (!EnsureWalletIsAvailable(fHelp))
458 return Value::null;
459
22dfd735 460 if (fHelp)
b1093efa
GM
461 throw runtime_error(
462 "listaddressgroupings\n"
a6099ef3 463 "\nLists groups of addresses which have had their common ownership\n"
b1093efa 464 "made public by common use as inputs or as the resulting change\n"
a6099ef3 465 "in past transactions\n"
466 "\nResult:\n"
467 "[\n"
468 " [\n"
469 " [\n"
58c4c0bb 470 " \"zcashaddress\", (string) The zcash address\n"
a6099ef3 471 " amount, (numeric) The amount in btc\n"
7b782f5b 472 " \"account\" (string, optional) The account (DEPRECATED)\n"
a6099ef3 473 " ]\n"
474 " ,...\n"
475 " ]\n"
476 " ,...\n"
477 "]\n"
478 "\nExamples:\n"
479 + HelpExampleCli("listaddressgroupings", "")
480 + HelpExampleRpc("listaddressgroupings", "")
481 );
22dfd735 482
4401b2d7
EL
483 LOCK2(cs_main, pwalletMain->cs_wallet);
484
22dfd735 485 Array jsonGroupings;
a372168e 486 map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
b1093efa 487 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
22dfd735 488 {
489 Array jsonGrouping;
b1093efa 490 BOOST_FOREACH(CTxDestination address, grouping)
22dfd735 491 {
492 Array addressInfo;
b1093efa 493 addressInfo.push_back(CBitcoinAddress(address).ToString());
22dfd735 494 addressInfo.push_back(ValueFromAmount(balances[address]));
495 {
22dfd735 496 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
61885513 497 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
22dfd735 498 }
499 jsonGrouping.push_back(addressInfo);
500 }
501 jsonGroupings.push_back(jsonGrouping);
502 }
503 return jsonGroupings;
504}
505
e3bc5698
JG
506Value signmessage(const Array& params, bool fHelp)
507{
b9fb692d
JS
508 if (!EnsureWalletIsAvailable(fHelp))
509 return Value::null;
510
e3bc5698
JG
511 if (fHelp || params.size() != 2)
512 throw runtime_error(
58c4c0bb 513 "signmessage \"zcashaddress\" \"message\"\n"
a6099ef3 514 "\nSign a message with the private key of an address"
515 + HelpRequiringPassphrase() + "\n"
516 "\nArguments:\n"
58c4c0bb 517 "1. \"zcashaddress\" (string, required) The zcash address to use for the private key.\n"
a6099ef3 518 "2. \"message\" (string, required) The message to create a signature of.\n"
519 "\nResult:\n"
520 "\"signature\" (string) The signature of the message encoded in base 64\n"
521 "\nExamples:\n"
522 "\nUnlock the wallet for 30 seconds\n"
523 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
524 "\nCreate the signature\n"
525 + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
526 "\nVerify the signature\n"
527 + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
528 "\nAs json rpc\n"
529 + HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"my message\"")
530 );
e3bc5698 531
4401b2d7
EL
532 LOCK2(cs_main, pwalletMain->cs_wallet);
533
e3bc5698
JG
534 EnsureWalletIsUnlocked();
535
536 string strAddress = params[0].get_str();
537 string strMessage = params[1].get_str();
538
539 CBitcoinAddress addr(strAddress);
540 if (!addr.IsValid())
738835d7 541 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
e3bc5698
JG
542
543 CKeyID keyID;
544 if (!addr.GetKeyID(keyID))
738835d7 545 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
e3bc5698
JG
546
547 CKey key;
548 if (!pwalletMain->GetKey(keyID, key))
738835d7 549 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
e3bc5698 550
8980a509 551 CHashWriter ss(SER_GETHASH, 0);
e3bc5698
JG
552 ss << strMessageMagic;
553 ss << strMessage;
554
555 vector<unsigned char> vchSig;
8980a509 556 if (!key.SignCompact(ss.GetHash(), vchSig))
738835d7 557 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
e3bc5698
JG
558
559 return EncodeBase64(&vchSig[0], vchSig.size());
560}
561
e3bc5698
JG
562Value getreceivedbyaddress(const Array& params, bool fHelp)
563{
b9fb692d
JS
564 if (!EnsureWalletIsAvailable(fHelp))
565 return Value::null;
566
e3bc5698
JG
567 if (fHelp || params.size() < 1 || params.size() > 2)
568 throw runtime_error(
58c4c0bb
SB
569 "getreceivedbyaddress \"zcashaddress\" ( minconf )\n"
570 "\nReturns the total amount received by the given zcashaddress in transactions with at least minconf confirmations.\n"
a6099ef3 571 "\nArguments:\n"
58c4c0bb 572 "1. \"zcashaddress\" (string, required) The zcash address for transactions.\n"
a6099ef3 573 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
574 "\nResult:\n"
575 "amount (numeric) The total amount in btc received at this address.\n"
576 "\nExamples:\n"
577 "\nThe amount from transactions with at least 1 confirmation\n"
578 + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"") +
579 "\nThe amount including unconfirmed transactions, zero confirmations\n"
580 + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" 0") +
581 "\nThe amount with at least 6 confirmation, very safe\n"
582 + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" 6") +
583 "\nAs a json rpc call\n"
584 + HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", 6")
585 );
e3bc5698 586
4401b2d7
EL
587 LOCK2(cs_main, pwalletMain->cs_wallet);
588
e3bc5698
JG
589 // Bitcoin address
590 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
e3bc5698 591 if (!address.IsValid())
58c4c0bb 592 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
0be990ba 593 CScript scriptPubKey = GetScriptForDestination(address.Get());
e3bc5698
JG
594 if (!IsMine(*pwalletMain,scriptPubKey))
595 return (double)0.0;
596
597 // Minimum confirmations
598 int nMinDepth = 1;
599 if (params.size() > 1)
600 nMinDepth = params[1].get_int();
601
602 // Tally
a372168e 603 CAmount nAmount = 0;
e3bc5698
JG
604 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
605 {
606 const CWalletTx& wtx = (*it).second;
75a4d512 607 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
608 continue;
609
610 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
611 if (txout.scriptPubKey == scriptPubKey)
612 if (wtx.GetDepthInMainChain() >= nMinDepth)
613 nAmount += txout.nValue;
614 }
615
616 return ValueFromAmount(nAmount);
617}
618
619
e3bc5698
JG
620Value getreceivedbyaccount(const Array& params, bool fHelp)
621{
b9fb692d
JS
622 if (!EnsureWalletIsAvailable(fHelp))
623 return Value::null;
624
e3bc5698
JG
625 if (fHelp || params.size() < 1 || params.size() > 2)
626 throw runtime_error(
a6099ef3 627 "getreceivedbyaccount \"account\" ( minconf )\n"
7b782f5b 628 "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
a6099ef3 629 "\nArguments:\n"
3c31eb24 630 "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 631 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
632 "\nResult:\n"
633 "amount (numeric) The total amount in btc received for this account.\n"
634 "\nExamples:\n"
635 "\nAmount received by the default account with at least 1 confirmation\n"
636 + HelpExampleCli("getreceivedbyaccount", "\"\"") +
637 "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
638 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
639 "\nThe amount with at least 6 confirmation, very safe\n"
640 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
641 "\nAs a json rpc call\n"
642 + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
643 );
e3bc5698 644
4401b2d7
EL
645 LOCK2(cs_main, pwalletMain->cs_wallet);
646
e3bc5698
JG
647 // Minimum confirmations
648 int nMinDepth = 1;
649 if (params.size() > 1)
650 nMinDepth = params[1].get_int();
651
652 // Get the set of pub keys assigned to account
653 string strAccount = AccountFromValue(params[0]);
3624356e 654 set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
e3bc5698
JG
655
656 // Tally
a372168e 657 CAmount nAmount = 0;
e3bc5698
JG
658 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
659 {
660 const CWalletTx& wtx = (*it).second;
75a4d512 661 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
662 continue;
663
664 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
665 {
666 CTxDestination address;
667 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
668 if (wtx.GetDepthInMainChain() >= nMinDepth)
669 nAmount += txout.nValue;
670 }
671 }
672
673 return (double)nAmount / (double)COIN;
674}
675
676
a372168e 677CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
e3bc5698 678{
a372168e 679 CAmount nBalance = 0;
e3bc5698
JG
680
681 // Tally wallet transactions
682 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
683 {
684 const CWalletTx& wtx = (*it).second;
75a4d512 685 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
e3bc5698
JG
686 continue;
687
a372168e 688 CAmount nReceived, nSent, nFee;
d4640d7d 689 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
e3bc5698
JG
690
691 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
692 nBalance += nReceived;
e07c8e91 693 nBalance -= nSent + nFee;
e3bc5698
JG
694 }
695
696 // Tally internal accounting entries
697 nBalance += walletdb.GetAccountCreditDebit(strAccount);
698
699 return nBalance;
700}
701
a372168e 702CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
e3bc5698
JG
703{
704 CWalletDB walletdb(pwalletMain->strWalletFile);
d4640d7d 705 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
e3bc5698
JG
706}
707
708
709Value getbalance(const Array& params, bool fHelp)
710{
b9fb692d
JS
711 if (!EnsureWalletIsAvailable(fHelp))
712 return Value::null;
713
d4640d7d 714 if (fHelp || params.size() > 3)
e3bc5698 715 throw runtime_error(
d4640d7d 716 "getbalance ( \"account\" minconf includeWatchonly )\n"
3c31eb24 717 "\nReturns the server's total available balance.\n"
a6099ef3 718 "\nArguments:\n"
715e5bbe 719 "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 720 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
d4640d7d 721 "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
a6099ef3 722 "\nResult:\n"
723 "amount (numeric) The total amount in btc received for this account.\n"
724 "\nExamples:\n"
7b782f5b 725 "\nThe total amount in the wallet\n"
a6099ef3 726 + HelpExampleCli("getbalance", "") +
7b782f5b 727 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3cf1f436 728 + HelpExampleCli("getbalance", "\"*\" 6") +
a6099ef3 729 "\nAs a json rpc call\n"
7b782f5b 730 + HelpExampleRpc("getbalance", "\"*\", 6")
a6099ef3 731 );
e3bc5698 732
4401b2d7
EL
733 LOCK2(cs_main, pwalletMain->cs_wallet);
734
e3bc5698
JG
735 if (params.size() == 0)
736 return ValueFromAmount(pwalletMain->GetBalance());
737
738 int nMinDepth = 1;
739 if (params.size() > 1)
740 nMinDepth = params[1].get_int();
a3e192a3 741 isminefilter filter = ISMINE_SPENDABLE;
a5c6c5d6
J
742 if(params.size() > 2)
743 if(params[2].get_bool())
a3e192a3 744 filter = filter | ISMINE_WATCH_ONLY;
e3bc5698
JG
745
746 if (params[0].get_str() == "*") {
747 // Calculate total balance a different way from GetBalance()
748 // (GetBalance() sums up all unspent TxOuts)
c9fd9078 749 // getbalance and "getbalance * 1 true" should return the same number
a372168e 750 CAmount nBalance = 0;
e3bc5698
JG
751 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
752 {
753 const CWalletTx& wtx = (*it).second;
c9fd9078 754 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
e3bc5698
JG
755 continue;
756
a372168e 757 CAmount allFee;
e3bc5698 758 string strSentAccount;
1b4568cb
CL
759 list<COutputEntry> listReceived;
760 list<COutputEntry> listSent;
d4640d7d 761 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
e3bc5698
JG
762 if (wtx.GetDepthInMainChain() >= nMinDepth)
763 {
1b4568cb
CL
764 BOOST_FOREACH(const COutputEntry& r, listReceived)
765 nBalance += r.amount;
e3bc5698 766 }
1b4568cb
CL
767 BOOST_FOREACH(const COutputEntry& s, listSent)
768 nBalance -= s.amount;
e3bc5698 769 nBalance -= allFee;
e3bc5698
JG
770 }
771 return ValueFromAmount(nBalance);
772 }
773
774 string strAccount = AccountFromValue(params[0]);
775
a372168e 776 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
e3bc5698
JG
777
778 return ValueFromAmount(nBalance);
779}
780
6027b460
MB
781Value getunconfirmedbalance(const Array &params, bool fHelp)
782{
b9fb692d
JS
783 if (!EnsureWalletIsAvailable(fHelp))
784 return Value::null;
785
6027b460
MB
786 if (fHelp || params.size() > 0)
787 throw runtime_error(
788 "getunconfirmedbalance\n"
789 "Returns the server's total unconfirmed balance\n");
4401b2d7
EL
790
791 LOCK2(cs_main, pwalletMain->cs_wallet);
792
6027b460
MB
793 return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
794}
795
e3bc5698
JG
796
797Value movecmd(const Array& params, bool fHelp)
798{
b9fb692d
JS
799 if (!EnsureWalletIsAvailable(fHelp))
800 return Value::null;
801
e3bc5698
JG
802 if (fHelp || params.size() < 3 || params.size() > 5)
803 throw runtime_error(
a6099ef3 804 "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
7b782f5b 805 "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
a6099ef3 806 "\nArguments:\n"
3c31eb24
JG
807 "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"
808 "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"
a6099ef3 809 "3. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
810 "4. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
811 "\nResult:\n"
45bfa137 812 "true|false (boolean) true if successful.\n"
a6099ef3 813 "\nExamples:\n"
814 "\nMove 0.01 btc from the default account to the account named tabby\n"
815 + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
816 "\nMove 0.01 btc timotei to akiko with a comment and funds have 6 confirmations\n"
817 + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
818 "\nAs a json rpc call\n"
819 + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
820 );
e3bc5698 821
4401b2d7
EL
822 LOCK2(cs_main, pwalletMain->cs_wallet);
823
e3bc5698
JG
824 string strFrom = AccountFromValue(params[0]);
825 string strTo = AccountFromValue(params[1]);
a372168e 826 CAmount nAmount = AmountFromValue(params[2]);
e3bc5698
JG
827 if (params.size() > 3)
828 // unused parameter, used to be nMinDepth, keep type-checking it though
829 (void)params[3].get_int();
830 string strComment;
831 if (params.size() > 4)
832 strComment = params[4].get_str();
833
834 CWalletDB walletdb(pwalletMain->strWalletFile);
835 if (!walletdb.TxnBegin())
738835d7 836 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
e3bc5698 837
51ed9ec9 838 int64_t nNow = GetAdjustedTime();
e3bc5698
JG
839
840 // Debit
841 CAccountingEntry debit;
4291e8fe 842 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
e3bc5698
JG
843 debit.strAccount = strFrom;
844 debit.nCreditDebit = -nAmount;
845 debit.nTime = nNow;
846 debit.strOtherAccount = strTo;
847 debit.strComment = strComment;
848 walletdb.WriteAccountingEntry(debit);
849
850 // Credit
851 CAccountingEntry credit;
4291e8fe 852 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
e3bc5698
JG
853 credit.strAccount = strTo;
854 credit.nCreditDebit = nAmount;
855 credit.nTime = nNow;
856 credit.strOtherAccount = strFrom;
857 credit.strComment = strComment;
858 walletdb.WriteAccountingEntry(credit);
859
860 if (!walletdb.TxnCommit())
738835d7 861 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
e3bc5698
JG
862
863 return true;
864}
865
866
867Value sendfrom(const Array& params, bool fHelp)
868{
b9fb692d
JS
869 if (!EnsureWalletIsAvailable(fHelp))
870 return Value::null;
871
e3bc5698
JG
872 if (fHelp || params.size() < 3 || params.size() > 6)
873 throw runtime_error(
58c4c0bb
SB
874 "sendfrom \"fromaccount\" \"tozcashaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
875 "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a zcash address.\n"
a6099ef3 876 "The amount is a real and is rounded to the nearest 0.00000001."
877 + HelpRequiringPassphrase() + "\n"
878 "\nArguments:\n"
3c31eb24 879 "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"
58c4c0bb 880 "2. \"tozcashaddress\" (string, required) The zcash address to send funds to.\n"
a6099ef3 881 "3. amount (numeric, required) The amount in btc. (transaction fee is added on top).\n"
882 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
883 "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
884 " This is not part of the transaction, just kept in your wallet.\n"
885 "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n"
886 " to which you're sending the transaction. This is not part of the transaction, \n"
887 " it is just kept in your wallet.\n"
888 "\nResult:\n"
b5ef85c7 889 "\"transactionid\" (string) The transaction id.\n"
a6099ef3 890 "\nExamples:\n"
891 "\nSend 0.01 btc from the default account to the address, must have at least 1 confirmation\n"
892 + HelpExampleCli("sendfrom", "\"\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
893 "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
894 + HelpExampleCli("sendfrom", "\"tabby\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01 6 \"donation\" \"seans outpost\"") +
895 "\nAs a json rpc call\n"
896 + HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
897 );
e3bc5698 898
4401b2d7
EL
899 LOCK2(cs_main, pwalletMain->cs_wallet);
900
e3bc5698
JG
901 string strAccount = AccountFromValue(params[0]);
902 CBitcoinAddress address(params[1].get_str());
903 if (!address.IsValid())
58c4c0bb 904 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
a372168e 905 CAmount nAmount = AmountFromValue(params[2]);
e3bc5698
JG
906 int nMinDepth = 1;
907 if (params.size() > 3)
908 nMinDepth = params[3].get_int();
909
910 CWalletTx wtx;
911 wtx.strFromAccount = strAccount;
912 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
913 wtx.mapValue["comment"] = params[4].get_str();
914 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
915 wtx.mapValue["to"] = params[5].get_str();
916
917 EnsureWalletIsUnlocked();
918
919 // Check funds
a372168e 920 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
e3bc5698 921 if (nAmount > nBalance)
738835d7 922 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
e3bc5698 923
292623ad 924 SendMoney(address.Get(), nAmount, false, wtx);
e3bc5698 925
805344dc 926 return wtx.GetHash().GetHex();
e3bc5698
JG
927}
928
929
930Value sendmany(const Array& params, bool fHelp)
931{
b9fb692d
JS
932 if (!EnsureWalletIsAvailable(fHelp))
933 return Value::null;
934
292623ad 935 if (fHelp || params.size() < 2 || params.size() > 5)
e3bc5698 936 throw runtime_error(
40a75733 937 "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
a6099ef3 938 "\nSend multiple times. Amounts are double-precision floating point numbers."
939 + HelpRequiringPassphrase() + "\n"
940 "\nArguments:\n"
3c31eb24 941 "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 942 "2. \"amounts\" (string, required) A json object with addresses and amounts\n"
943 " {\n"
58c4c0bb 944 " \"address\":amount (numeric) The zcash address is the key, the numeric amount in btc is the value\n"
a6099ef3 945 " ,...\n"
946 " }\n"
947 "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
948 "4. \"comment\" (string, optional) A comment\n"
40a75733 949 "5. subtractfeefromamount (string, optional) A json array with addresses.\n"
292623ad 950 " The fee will be equally deducted from the amount of each selected address.\n"
58c4c0bb 951 " Those recipients will receive less zcashs than you enter in their corresponding amount field.\n"
40a75733
LD
952 " If no addresses are specified here, the sender pays the fee.\n"
953 " [\n"
954 " \"address\" (string) Subtract fee from this address\n"
292623ad 955 " ,...\n"
40a75733 956 " ]\n"
a6099ef3 957 "\nResult:\n"
958 "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
b5ef85c7 959 " the number of addresses.\n"
a6099ef3 960 "\nExamples:\n"
961 "\nSend two amounts to two different addresses:\n"
7b782f5b 962 + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
a6099ef3 963 "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
7b782f5b 964 + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
292623ad 965 "\nSend two amounts to two different addresses, subtract fee from amount:\n"
40a75733 966 + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\",\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
a6099ef3 967 "\nAs a json rpc call\n"
7b782f5b 968 + HelpExampleRpc("sendmany", "\"\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
a6099ef3 969 );
e3bc5698 970
4401b2d7
EL
971 LOCK2(cs_main, pwalletMain->cs_wallet);
972
e3bc5698
JG
973 string strAccount = AccountFromValue(params[0]);
974 Object sendTo = params[1].get_obj();
975 int nMinDepth = 1;
976 if (params.size() > 2)
977 nMinDepth = params[2].get_int();
978
979 CWalletTx wtx;
980 wtx.strFromAccount = strAccount;
981 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
982 wtx.mapValue["comment"] = params[3].get_str();
983
40a75733 984 Array subtractFeeFromAmount;
292623ad 985 if (params.size() > 4)
40a75733 986 subtractFeeFromAmount = params[4].get_array();
292623ad 987
e3bc5698 988 set<CBitcoinAddress> setAddress;
292623ad 989 vector<CRecipient> vecSend;
e3bc5698 990
a372168e 991 CAmount totalAmount = 0;
e3bc5698
JG
992 BOOST_FOREACH(const Pair& s, sendTo)
993 {
994 CBitcoinAddress address(s.name_);
995 if (!address.IsValid())
58c4c0bb 996 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+s.name_);
e3bc5698
JG
997
998 if (setAddress.count(address))
738835d7 999 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
e3bc5698
JG
1000 setAddress.insert(address);
1001
0be990ba 1002 CScript scriptPubKey = GetScriptForDestination(address.Get());
a372168e 1003 CAmount nAmount = AmountFromValue(s.value_);
e3bc5698
JG
1004 totalAmount += nAmount;
1005
292623ad 1006 bool fSubtractFeeFromAmount = false;
40a75733
LD
1007 BOOST_FOREACH(const Value& addr, subtractFeeFromAmount)
1008 if (addr.get_str() == s.name_)
292623ad
CL
1009 fSubtractFeeFromAmount = true;
1010
1011 CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
1012 vecSend.push_back(recipient);
e3bc5698
JG
1013 }
1014
1015 EnsureWalletIsUnlocked();
1016
1017 // Check funds
a372168e 1018 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
e3bc5698 1019 if (totalAmount > nBalance)
738835d7 1020 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
e3bc5698
JG
1021
1022 // Send
1023 CReserveKey keyChange(pwalletMain);
a372168e 1024 CAmount nFeeRequired = 0;
292623ad 1025 int nChangePosRet = -1;
1f00f4e9 1026 string strFailReason;
292623ad 1027 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
e3bc5698 1028 if (!fCreated)
1f00f4e9 1029 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
e3bc5698 1030 if (!pwalletMain->CommitTransaction(wtx, keyChange))
738835d7 1031 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
e3bc5698 1032
805344dc 1033 return wtx.GetHash().GetHex();
e3bc5698
JG
1034}
1035
723a03d2 1036// Defined in rpcmisc.cpp
787ee0c9 1037extern CScript _createmultisig_redeemScript(const Array& params);
34226be7
GA
1038
1039Value addmultisigaddress(const Array& params, bool fHelp)
1040{
b9fb692d
JS
1041 if (!EnsureWalletIsAvailable(fHelp))
1042 return Value::null;
1043
34226be7
GA
1044 if (fHelp || params.size() < 2 || params.size() > 3)
1045 {
a6099ef3 1046 string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
1047 "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
58c4c0bb 1048 "Each key is a Zcash address or hex-encoded public key.\n"
7b782f5b 1049 "If 'account' is specified (DEPRECATED), assign address to that account.\n"
a6099ef3 1050
1051 "\nArguments:\n"
1052 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
58c4c0bb 1053 "2. \"keysobject\" (string, required) A json array of zcash addresses or hex-encoded public keys\n"
a6099ef3 1054 " [\n"
58c4c0bb 1055 " \"address\" (string) zcash address or hex-encoded public key\n"
a6099ef3 1056 " ...,\n"
1057 " ]\n"
3c31eb24 1058 "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 1059
1060 "\nResult:\n"
58c4c0bb 1061 "\"zcashaddress\" (string) A zcash address associated with the keys.\n"
a6099ef3 1062
1063 "\nExamples:\n"
1064 "\nAdd a multisig address from 2 addresses\n"
1065 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
1066 "\nAs json rpc call\n"
1067 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
1068 ;
34226be7
GA
1069 throw runtime_error(msg);
1070 }
1071
4401b2d7
EL
1072 LOCK2(cs_main, pwalletMain->cs_wallet);
1073
34226be7
GA
1074 string strAccount;
1075 if (params.size() > 2)
1076 strAccount = AccountFromValue(params[2]);
e3bc5698
JG
1077
1078 // Construct using pay-to-script-hash:
787ee0c9 1079 CScript inner = _createmultisig_redeemScript(params);
066e2a14 1080 CScriptID innerID(inner);
e3bc5698
JG
1081 pwalletMain->AddCScript(inner);
1082
a41d5fe0 1083 pwalletMain->SetAddressBook(innerID, strAccount, "send");
e3bc5698
JG
1084 return CBitcoinAddress(innerID).ToString();
1085}
1086
1087
1088struct tallyitem
1089{
a372168e 1090 CAmount nAmount;
e3bc5698 1091 int nConf;
62c9b115 1092 vector<uint256> txids;
0fa2f889 1093 bool fIsWatchonly;
e3bc5698
JG
1094 tallyitem()
1095 {
1096 nAmount = 0;
1097 nConf = std::numeric_limits<int>::max();
0fa2f889 1098 fIsWatchonly = false;
e3bc5698
JG
1099 }
1100};
1101
1102Value ListReceived(const Array& params, bool fByAccounts)
1103{
1104 // Minimum confirmations
1105 int nMinDepth = 1;
1106 if (params.size() > 0)
1107 nMinDepth = params[0].get_int();
1108
1109 // Whether to include empty accounts
1110 bool fIncludeEmpty = false;
1111 if (params.size() > 1)
1112 fIncludeEmpty = params[1].get_bool();
1113
a3e192a3 1114 isminefilter filter = ISMINE_SPENDABLE;
0fa2f889
J
1115 if(params.size() > 2)
1116 if(params[2].get_bool())
a3e192a3 1117 filter = filter | ISMINE_WATCH_ONLY;
0fa2f889 1118
e3bc5698
JG
1119 // Tally
1120 map<CBitcoinAddress, tallyitem> mapTally;
1121 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1122 {
1123 const CWalletTx& wtx = (*it).second;
1124
75a4d512 1125 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
1126 continue;
1127
1128 int nDepth = wtx.GetDepthInMainChain();
1129 if (nDepth < nMinDepth)
1130 continue;
1131
1132 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1133 {
1134 CTxDestination address;
0fa2f889
J
1135 if (!ExtractDestination(txout.scriptPubKey, address))
1136 continue;
1137
1138 isminefilter mine = IsMine(*pwalletMain, address);
f28707a8 1139 if(!(mine & filter))
e3bc5698
JG
1140 continue;
1141
1142 tallyitem& item = mapTally[address];
1143 item.nAmount += txout.nValue;
1144 item.nConf = min(item.nConf, nDepth);
805344dc 1145 item.txids.push_back(wtx.GetHash());
a3e192a3 1146 if (mine & ISMINE_WATCH_ONLY)
0fa2f889 1147 item.fIsWatchonly = true;
e3bc5698
JG
1148 }
1149 }
1150
1151 // Reply
1152 Array ret;
1153 map<string, tallyitem> mapAccountTally;
61885513 1154 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
e3bc5698
JG
1155 {
1156 const CBitcoinAddress& address = item.first;
61885513 1157 const string& strAccount = item.second.name;
e3bc5698
JG
1158 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1159 if (it == mapTally.end() && !fIncludeEmpty)
1160 continue;
1161
a372168e 1162 CAmount nAmount = 0;
e3bc5698 1163 int nConf = std::numeric_limits<int>::max();
0fa2f889 1164 bool fIsWatchonly = false;
e3bc5698
JG
1165 if (it != mapTally.end())
1166 {
1167 nAmount = (*it).second.nAmount;
1168 nConf = (*it).second.nConf;
0fa2f889 1169 fIsWatchonly = (*it).second.fIsWatchonly;
e3bc5698
JG
1170 }
1171
1172 if (fByAccounts)
1173 {
1174 tallyitem& item = mapAccountTally[strAccount];
1175 item.nAmount += nAmount;
1176 item.nConf = min(item.nConf, nConf);
0fa2f889 1177 item.fIsWatchonly = fIsWatchonly;
e3bc5698
JG
1178 }
1179 else
1180 {
1181 Object obj;
0fa2f889
J
1182 if(fIsWatchonly)
1183 obj.push_back(Pair("involvesWatchonly", true));
e3bc5698
JG
1184 obj.push_back(Pair("address", address.ToString()));
1185 obj.push_back(Pair("account", strAccount));
1186 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1187 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
62c9b115 1188 Array transactions;
1a204694 1189 if (it != mapTally.end())
62c9b115 1190 {
1a204694
A
1191 BOOST_FOREACH(const uint256& item, (*it).second.txids)
1192 {
1193 transactions.push_back(item.GetHex());
1194 }
62c9b115
A
1195 }
1196 obj.push_back(Pair("txids", transactions));
e3bc5698
JG
1197 ret.push_back(obj);
1198 }
1199 }
1200
1201 if (fByAccounts)
1202 {
1203 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1204 {
a372168e 1205 CAmount nAmount = (*it).second.nAmount;
e3bc5698
JG
1206 int nConf = (*it).second.nConf;
1207 Object obj;
0fa2f889
J
1208 if((*it).second.fIsWatchonly)
1209 obj.push_back(Pair("involvesWatchonly", true));
e3bc5698
JG
1210 obj.push_back(Pair("account", (*it).first));
1211 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1212 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1213 ret.push_back(obj);
1214 }
1215 }
1216
1217 return ret;
1218}
1219
1220Value listreceivedbyaddress(const Array& params, bool fHelp)
1221{
b9fb692d
JS
1222 if (!EnsureWalletIsAvailable(fHelp))
1223 return Value::null;
1224
0fa2f889 1225 if (fHelp || params.size() > 3)
e3bc5698 1226 throw runtime_error(
0fa2f889 1227 "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
a6099ef3 1228 "\nList balances by receiving address.\n"
1229 "\nArguments:\n"
1230 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
5617267c 1231 "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n"
0fa2f889 1232 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
a6099ef3 1233
1234 "\nResult:\n"
1235 "[\n"
1236 " {\n"
8f6860a0 1237 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
a6099ef3 1238 " \"address\" : \"receivingaddress\", (string) The receiving address\n"
7b782f5b 1239 " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
a6099ef3 1240 " \"amount\" : x.xxx, (numeric) The total amount in btc received by the address\n"
1241 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1242 " }\n"
1243 " ,...\n"
1244 "]\n"
1245
1246 "\nExamples:\n"
1247 + HelpExampleCli("listreceivedbyaddress", "")
1248 + HelpExampleCli("listreceivedbyaddress", "6 true")
0fa2f889 1249 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
a6099ef3 1250 );
e3bc5698 1251
4401b2d7
EL
1252 LOCK2(cs_main, pwalletMain->cs_wallet);
1253
e3bc5698
JG
1254 return ListReceived(params, false);
1255}
1256
1257Value listreceivedbyaccount(const Array& params, bool fHelp)
1258{
b9fb692d
JS
1259 if (!EnsureWalletIsAvailable(fHelp))
1260 return Value::null;
1261
0fa2f889 1262 if (fHelp || params.size() > 3)
e3bc5698 1263 throw runtime_error(
0fa2f889 1264 "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
7b782f5b 1265 "\nDEPRECATED. List balances by account.\n"
a6099ef3 1266 "\nArguments:\n"
1267 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1268 "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
0fa2f889 1269 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
a6099ef3 1270
1271 "\nResult:\n"
1272 "[\n"
1273 " {\n"
8f6860a0 1274 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
a6099ef3 1275 " \"account\" : \"accountname\", (string) The account name of the receiving account\n"
1276 " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
1277 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1278 " }\n"
1279 " ,...\n"
1280 "]\n"
1281
1282 "\nExamples:\n"
1283 + HelpExampleCli("listreceivedbyaccount", "")
1284 + HelpExampleCli("listreceivedbyaccount", "6 true")
0fa2f889 1285 + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
a6099ef3 1286 );
e3bc5698 1287
4401b2d7
EL
1288 LOCK2(cs_main, pwalletMain->cs_wallet);
1289
e3bc5698
JG
1290 return ListReceived(params, true);
1291}
1292
cc6cfab3
LD
1293static void MaybePushAddress(Object & entry, const CTxDestination &dest)
1294{
1295 CBitcoinAddress addr;
1296 if (addr.Set(dest))
1297 entry.push_back(Pair("address", addr.ToString()));
1298}
1299
80dda36a 1300void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
e3bc5698 1301{
a372168e 1302 CAmount nFee;
e3bc5698 1303 string strSentAccount;
1b4568cb
CL
1304 list<COutputEntry> listReceived;
1305 list<COutputEntry> listSent;
e3bc5698 1306
d7d5d23b 1307 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
e3bc5698
JG
1308
1309 bool fAllAccounts = (strAccount == string("*"));
a3e192a3 1310 bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
e3bc5698 1311
e3bc5698
JG
1312 // Sent
1313 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1314 {
1b4568cb 1315 BOOST_FOREACH(const COutputEntry& s, listSent)
e3bc5698
JG
1316 {
1317 Object entry;
1b4568cb 1318 if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
952877e0 1319 entry.push_back(Pair("involvesWatchonly", true));
e3bc5698 1320 entry.push_back(Pair("account", strSentAccount));
1b4568cb 1321 MaybePushAddress(entry, s.destination);
b96f6a77 1322 entry.push_back(Pair("category", "send"));
1b4568cb
CL
1323 entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
1324 entry.push_back(Pair("vout", s.vout));
e3bc5698
JG
1325 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1326 if (fLong)
1327 WalletTxToJSON(wtx, entry);
1328 ret.push_back(entry);
1329 }
1330 }
1331
1332 // Received
1333 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1334 {
1b4568cb 1335 BOOST_FOREACH(const COutputEntry& r, listReceived)
e3bc5698
JG
1336 {
1337 string account;
1b4568cb
CL
1338 if (pwalletMain->mapAddressBook.count(r.destination))
1339 account = pwalletMain->mapAddressBook[r.destination].name;
e3bc5698
JG
1340 if (fAllAccounts || (account == strAccount))
1341 {
1342 Object entry;
1b4568cb 1343 if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
952877e0 1344 entry.push_back(Pair("involvesWatchonly", true));
e3bc5698 1345 entry.push_back(Pair("account", account));
1b4568cb 1346 MaybePushAddress(entry, r.destination);
e07c8e91
LD
1347 if (wtx.IsCoinBase())
1348 {
1349 if (wtx.GetDepthInMainChain() < 1)
1350 entry.push_back(Pair("category", "orphan"));
1351 else if (wtx.GetBlocksToMaturity() > 0)
1352 entry.push_back(Pair("category", "immature"));
1353 else
1354 entry.push_back(Pair("category", "generate"));
1355 }
1356 else
2b72d46f 1357 {
b96f6a77 1358 entry.push_back(Pair("category", "receive"));
2b72d46f 1359 }
1b4568cb
CL
1360 entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
1361 entry.push_back(Pair("vout", r.vout));
e3bc5698
JG
1362 if (fLong)
1363 WalletTxToJSON(wtx, entry);
1364 ret.push_back(entry);
1365 }
1366 }
1367 }
1368}
1369
1370void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1371{
1372 bool fAllAccounts = (strAccount == string("*"));
1373
1374 if (fAllAccounts || acentry.strAccount == strAccount)
1375 {
1376 Object entry;
1377 entry.push_back(Pair("account", acentry.strAccount));
1378 entry.push_back(Pair("category", "move"));
d56e30ca 1379 entry.push_back(Pair("time", acentry.nTime));
e3bc5698
JG
1380 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1381 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1382 entry.push_back(Pair("comment", acentry.strComment));
1383 ret.push_back(entry);
1384 }
1385}
1386
1387Value listtransactions(const Array& params, bool fHelp)
1388{
b9fb692d
JS
1389 if (!EnsureWalletIsAvailable(fHelp))
1390 return Value::null;
1391
d7d5d23b 1392 if (fHelp || params.size() > 4)
e3bc5698 1393 throw runtime_error(
d7d5d23b 1394 "listtransactions ( \"account\" count from includeWatchonly)\n"
a6099ef3 1395 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
1396 "\nArguments:\n"
7b782f5b 1397 "1. \"account\" (string, optional) DEPRECATED. The account name. Should be \"*\".\n"
a6099ef3 1398 "2. count (numeric, optional, default=10) The number of transactions to return\n"
1399 "3. from (numeric, optional, default=0) The number of transactions to skip\n"
d7d5d23b 1400 "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
a6099ef3 1401 "\nResult:\n"
1402 "[\n"
1403 " {\n"
7b782f5b 1404 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n"
a6099ef3 1405 " It will be \"\" for the default account.\n"
58c4c0bb 1406 " \"address\":\"zcashaddress\", (string) The zcash address of the transaction. Not present for \n"
a6099ef3 1407 " move transactions (category = move).\n"
1408 " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
1409 " transaction between accounts, and not associated with an address,\n"
1410 " transaction id or block. 'send' and 'receive' transactions are \n"
1411 " associated with an address, transaction id and block details\n"
1412 " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the\n"
1413 " 'move' category for moves outbound. It is positive for the 'receive' category,\n"
1414 " and for the 'move' category for inbound funds.\n"
1b4568cb 1415 " \"vout\" : n, (numeric) the vout value\n"
a6099ef3 1416 " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the \n"
1417 " 'send' category of transactions.\n"
1418 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
1419 " 'receive' category of transactions.\n"
1420 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
1421 " category of transactions.\n"
1422 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
1423 " category of transactions.\n"
b5ef85c7 1424 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
a6099ef3 1425 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1426 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
1427 " for 'send' and 'receive' category of transactions.\n"
1428 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1429 " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
1430 " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
1431 " negative amounts).\n"
1432 " }\n"
1433 "]\n"
1434
1435 "\nExamples:\n"
1436 "\nList the most recent 10 transactions in the systems\n"
1437 + HelpExampleCli("listtransactions", "") +
7b782f5b
LD
1438 "\nList transactions 100 to 120\n"
1439 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
a6099ef3 1440 "\nAs a json rpc call\n"
7b782f5b 1441 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
a6099ef3 1442 );
e3bc5698 1443
4401b2d7
EL
1444 LOCK2(cs_main, pwalletMain->cs_wallet);
1445
e3bc5698
JG
1446 string strAccount = "*";
1447 if (params.size() > 0)
1448 strAccount = params[0].get_str();
1449 int nCount = 10;
1450 if (params.size() > 1)
1451 nCount = params[1].get_int();
1452 int nFrom = 0;
1453 if (params.size() > 2)
1454 nFrom = params[2].get_int();
a3e192a3 1455 isminefilter filter = ISMINE_SPENDABLE;
a5c6c5d6
J
1456 if(params.size() > 3)
1457 if(params[3].get_bool())
a3e192a3 1458 filter = filter | ISMINE_WATCH_ONLY;
e3bc5698
JG
1459
1460 if (nCount < 0)
738835d7 1461 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
e3bc5698 1462 if (nFrom < 0)
738835d7 1463 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
e3bc5698
JG
1464
1465 Array ret;
e3bc5698 1466
ddb709e9
LD
1467 std::list<CAccountingEntry> acentries;
1468 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
e3bc5698
JG
1469
1470 // iterate backwards until we have nCount items to return:
c3f95ef1 1471 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
e3bc5698
JG
1472 {
1473 CWalletTx *const pwtx = (*it).second.first;
1474 if (pwtx != 0)
d7d5d23b 1475 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
e3bc5698
JG
1476 CAccountingEntry *const pacentry = (*it).second.second;
1477 if (pacentry != 0)
1478 AcentryToJSON(*pacentry, strAccount, ret);
1479
1480 if ((int)ret.size() >= (nCount+nFrom)) break;
1481 }
1482 // ret is newest to oldest
1483
1484 if (nFrom > (int)ret.size())
1485 nFrom = ret.size();
1486 if ((nFrom + nCount) > (int)ret.size())
1487 nCount = ret.size() - nFrom;
1488 Array::iterator first = ret.begin();
1489 std::advance(first, nFrom);
1490 Array::iterator last = ret.begin();
1491 std::advance(last, nFrom+nCount);
1492
1493 if (last != ret.end()) ret.erase(last, ret.end());
1494 if (first != ret.begin()) ret.erase(ret.begin(), first);
1495
1496 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1497
1498 return ret;
1499}
1500
1501Value listaccounts(const Array& params, bool fHelp)
1502{
b9fb692d
JS
1503 if (!EnsureWalletIsAvailable(fHelp))
1504 return Value::null;
1505
83f3543f 1506 if (fHelp || params.size() > 2)
e3bc5698 1507 throw runtime_error(
83f3543f 1508 "listaccounts ( minconf includeWatchonly)\n"
7b782f5b 1509 "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
a6099ef3 1510 "\nArguments:\n"
5617267c 1511 "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
83f3543f 1512 "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
a6099ef3 1513 "\nResult:\n"
1514 "{ (json object where keys are account names, and values are numeric balances\n"
1515 " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
1516 " ...\n"
1517 "}\n"
1518 "\nExamples:\n"
1519 "\nList account balances where there at least 1 confirmation\n"
1520 + HelpExampleCli("listaccounts", "") +
1521 "\nList account balances including zero confirmation transactions\n"
1522 + HelpExampleCli("listaccounts", "0") +
1523 "\nList account balances for 6 or more confirmations\n"
1524 + HelpExampleCli("listaccounts", "6") +
1525 "\nAs json rpc call\n"
1526 + HelpExampleRpc("listaccounts", "6")
1527 );
e3bc5698 1528
4401b2d7
EL
1529 LOCK2(cs_main, pwalletMain->cs_wallet);
1530
e3bc5698
JG
1531 int nMinDepth = 1;
1532 if (params.size() > 0)
1533 nMinDepth = params[0].get_int();
a3e192a3 1534 isminefilter includeWatchonly = ISMINE_SPENDABLE;
a5c6c5d6
J
1535 if(params.size() > 1)
1536 if(params[1].get_bool())
a3e192a3 1537 includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
e3bc5698 1538
a372168e 1539 map<string, CAmount> mapAccountBalances;
61885513 1540 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
83f3543f 1541 if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
61885513 1542 mapAccountBalances[entry.second.name] = 0;
e3bc5698
JG
1543 }
1544
1545 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1546 {
1547 const CWalletTx& wtx = (*it).second;
a372168e 1548 CAmount nFee;
e3bc5698 1549 string strSentAccount;
1b4568cb
CL
1550 list<COutputEntry> listReceived;
1551 list<COutputEntry> listSent;
93a18a36
GA
1552 int nDepth = wtx.GetDepthInMainChain();
1553 if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
731b89b8 1554 continue;
83f3543f 1555 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
e3bc5698 1556 mapAccountBalances[strSentAccount] -= nFee;
1b4568cb
CL
1557 BOOST_FOREACH(const COutputEntry& s, listSent)
1558 mapAccountBalances[strSentAccount] -= s.amount;
93a18a36 1559 if (nDepth >= nMinDepth)
e3bc5698 1560 {
1b4568cb
CL
1561 BOOST_FOREACH(const COutputEntry& r, listReceived)
1562 if (pwalletMain->mapAddressBook.count(r.destination))
1563 mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
e3bc5698 1564 else
1b4568cb 1565 mapAccountBalances[""] += r.amount;
e3bc5698
JG
1566 }
1567 }
1568
1569 list<CAccountingEntry> acentries;
1570 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1571 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1572 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1573
1574 Object ret;
a372168e 1575 BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
e3bc5698
JG
1576 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1577 }
1578 return ret;
1579}
1580
1581Value listsinceblock(const Array& params, bool fHelp)
1582{
b9fb692d
JS
1583 if (!EnsureWalletIsAvailable(fHelp))
1584 return Value::null;
1585
e3bc5698
JG
1586 if (fHelp)
1587 throw runtime_error(
d7d5d23b 1588 "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
a6099ef3 1589 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
1590 "\nArguments:\n"
1591 "1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
1592 "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
d7d5d23b 1593 "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
a6099ef3 1594 "\nResult:\n"
1595 "{\n"
1596 " \"transactions\": [\n"
7b782f5b 1597 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
58c4c0bb 1598 " \"address\":\"zcashaddress\", (string) The zcash address of the transaction. Not present for move transactions (category = move).\n"
a6099ef3 1599 " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
1600 " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the 'move' category for moves \n"
1601 " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
1b4568cb 1602 " \"vout\" : n, (numeric) the vout value\n"
a6099ef3 1603 " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the 'send' category of transactions.\n"
1604 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
1605 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1606 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1607 " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
b5ef85c7 1608 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
a6099ef3 1609 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
1610 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
1611 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1612 " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
1613 " ],\n"
1614 " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
1615 "}\n"
1616 "\nExamples:\n"
1617 + HelpExampleCli("listsinceblock", "")
1618 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1619 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1620 );
e3bc5698 1621
4401b2d7
EL
1622 LOCK2(cs_main, pwalletMain->cs_wallet);
1623
e3bc5698
JG
1624 CBlockIndex *pindex = NULL;
1625 int target_confirms = 1;
a3e192a3 1626 isminefilter filter = ISMINE_SPENDABLE;
e3bc5698
JG
1627
1628 if (params.size() > 0)
1629 {
4f152496 1630 uint256 blockId;
e3bc5698
JG
1631
1632 blockId.SetHex(params[0].get_str());
145d5be8 1633 BlockMap::iterator it = mapBlockIndex.find(blockId);
e4daecda
PW
1634 if (it != mapBlockIndex.end())
1635 pindex = it->second;
e3bc5698
JG
1636 }
1637
1638 if (params.size() > 1)
1639 {
1640 target_confirms = params[1].get_int();
1641
1642 if (target_confirms < 1)
738835d7 1643 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
e3bc5698
JG
1644 }
1645
a5c6c5d6
J
1646 if(params.size() > 2)
1647 if(params[2].get_bool())
a3e192a3 1648 filter = filter | ISMINE_WATCH_ONLY;
a5c6c5d6 1649
4c6d41b8 1650 int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
e3bc5698
JG
1651
1652 Array transactions;
1653
1654 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1655 {
1656 CWalletTx tx = (*it).second;
1657
1658 if (depth == -1 || tx.GetDepthInMainChain() < depth)
d7d5d23b 1659 ListTransactions(tx, "*", 0, true, transactions, filter);
e3bc5698
JG
1660 }
1661
4c6d41b8 1662 CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
4f152496 1663 uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
e3bc5698
JG
1664
1665 Object ret;
1666 ret.push_back(Pair("transactions", transactions));
1667 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1668
1669 return ret;
1670}
1671
1672Value gettransaction(const Array& params, bool fHelp)
1673{
b9fb692d
JS
1674 if (!EnsureWalletIsAvailable(fHelp))
1675 return Value::null;
1676
f87ba3df 1677 if (fHelp || params.size() < 1 || params.size() > 2)
e3bc5698 1678 throw runtime_error(
57e1716d 1679 "gettransaction \"txid\" ( includeWatchonly )\n"
a6099ef3 1680 "\nGet detailed information about in-wallet transaction <txid>\n"
1681 "\nArguments:\n"
1682 "1. \"txid\" (string, required) The transaction id\n"
f87ba3df 1683 "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
a6099ef3 1684 "\nResult:\n"
1685 "{\n"
1686 " \"amount\" : x.xxx, (numeric) The transaction amount in btc\n"
1687 " \"confirmations\" : n, (numeric) The number of confirmations\n"
1688 " \"blockhash\" : \"hash\", (string) The block hash\n"
1689 " \"blockindex\" : xx, (numeric) The block index\n"
1690 " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
b5ef85c7 1691 " \"txid\" : \"transactionid\", (string) The transaction id.\n"
a6099ef3 1692 " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
1693 " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
1694 " \"details\" : [\n"
1695 " {\n"
7b782f5b 1696 " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
58c4c0bb 1697 " \"address\" : \"zcashaddress\", (string) The zcash address involved in the transaction\n"
a6099ef3 1698 " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
1699 " \"amount\" : x.xxx (numeric) The amount in btc\n"
1b4568cb 1700 " \"vout\" : n, (numeric) the vout value\n"
a6099ef3 1701 " }\n"
1702 " ,...\n"
3a1c20b7 1703 " ],\n"
f7cfb52d
S
1704 " \"vjoinsplit\" : [\n"
1705 " {\n"
1706 " \"anchor\" : \"treestateref\", (string) Merkle root of note commitment tree\n"
1707 " \"nullifiers\" : [ string, ... ] (string) Nullifiers of input notes\n"
1708 " \"commitments\" : [ string, ... ] (string) Note commitments for note outputs\n"
1709 " \"macs\" : [ string, ... ] (string) Message authentication tags\n"
1710 " \"vpub_old\" : x.xxx (numeric) The amount removed from the transparent value pool\n"
1711 " \"vpub_new\" : x.xxx, (numeric) The amount added to the transparent value pool\n"
1712 " }\n"
1713 " ,...\n"
1714 " ],\n"
3a1c20b7 1715 " \"hex\" : \"data\" (string) Raw data for transaction\n"
a6099ef3 1716 "}\n"
1717
ab45ddb5 1718 "\nExamples:\n"
a6099ef3 1719 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
57e1716d 1720 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
a6099ef3 1721 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1722 );
e3bc5698 1723
4401b2d7
EL
1724 LOCK2(cs_main, pwalletMain->cs_wallet);
1725
e3bc5698
JG
1726 uint256 hash;
1727 hash.SetHex(params[0].get_str());
1728
a3e192a3 1729 isminefilter filter = ISMINE_SPENDABLE;
f87ba3df
J
1730 if(params.size() > 1)
1731 if(params[1].get_bool())
a3e192a3 1732 filter = filter | ISMINE_WATCH_ONLY;
f87ba3df 1733
e3bc5698
JG
1734 Object entry;
1735 if (!pwalletMain->mapWallet.count(hash))
738835d7 1736 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
e3bc5698
JG
1737 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1738
ccca27a7 1739 CAmount nCredit = wtx.GetCredit(filter);
a372168e
MF
1740 CAmount nDebit = wtx.GetDebit(filter);
1741 CAmount nNet = nCredit - nDebit;
1742 CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
e3bc5698
JG
1743
1744 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
80dda36a 1745 if (wtx.IsFromMe(filter))
e3bc5698
JG
1746 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1747
1748 WalletTxToJSON(wtx, entry);
1749
1750 Array details;
f87ba3df 1751 ListTransactions(wtx, "*", 0, false, details, filter);
e3bc5698
JG
1752 entry.push_back(Pair("details", details));
1753
ae775b5b 1754 string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
3a1c20b7
WL
1755 entry.push_back(Pair("hex", strHex));
1756
e3bc5698
JG
1757 return entry;
1758}
1759
1760
1761Value backupwallet(const Array& params, bool fHelp)
1762{
b9fb692d
JS
1763 if (!EnsureWalletIsAvailable(fHelp))
1764 return Value::null;
1765
e3bc5698
JG
1766 if (fHelp || params.size() != 1)
1767 throw runtime_error(
a6099ef3 1768 "backupwallet \"destination\"\n"
1769 "\nSafely copies wallet.dat to destination, which can be a directory or a path with filename.\n"
1770 "\nArguments:\n"
1771 "1. \"destination\" (string) The destination directory or file\n"
1772 "\nExamples:\n"
1773 + HelpExampleCli("backupwallet", "\"backup.dat\"")
1774 + HelpExampleRpc("backupwallet", "\"backup.dat\"")
1775 );
e3bc5698 1776
4401b2d7
EL
1777 LOCK2(cs_main, pwalletMain->cs_wallet);
1778
e3bc5698 1779 string strDest = params[0].get_str();
ad525e9c
PK
1780 if (!BackupWallet(*pwalletMain, strDest))
1781 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
e3bc5698
JG
1782
1783 return Value::null;
1784}
1785
1786
1787Value keypoolrefill(const Array& params, bool fHelp)
1788{
b9fb692d
JS
1789 if (!EnsureWalletIsAvailable(fHelp))
1790 return Value::null;
1791
36bd46f1 1792 if (fHelp || params.size() > 1)
e3bc5698 1793 throw runtime_error(
a6099ef3 1794 "keypoolrefill ( newsize )\n"
1795 "\nFills the keypool."
1796 + HelpRequiringPassphrase() + "\n"
1797 "\nArguments\n"
1798 "1. newsize (numeric, optional, default=100) The new keypool size\n"
1799 "\nExamples:\n"
1800 + HelpExampleCli("keypoolrefill", "")
1801 + HelpExampleRpc("keypoolrefill", "")
1802 );
e3bc5698 1803
4401b2d7
EL
1804 LOCK2(cs_main, pwalletMain->cs_wallet);
1805
f914c7a1
PK
1806 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
1807 unsigned int kpSize = 0;
36bd46f1
JG
1808 if (params.size() > 0) {
1809 if (params[0].get_int() < 0)
f914c7a1
PK
1810 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
1811 kpSize = (unsigned int)params[0].get_int();
36bd46f1
JG
1812 }
1813
e3bc5698 1814 EnsureWalletIsUnlocked();
36bd46f1 1815 pwalletMain->TopUpKeyPool(kpSize);
e3bc5698 1816
36bd46f1 1817 if (pwalletMain->GetKeyPoolSize() < kpSize)
738835d7 1818 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
e3bc5698
JG
1819
1820 return Value::null;
1821}
1822
1823
92f2c1fe 1824static void LockWallet(CWallet* pWallet)
e3bc5698 1825{
92f2c1fe
GA
1826 LOCK(cs_nWalletUnlockTime);
1827 nWalletUnlockTime = 0;
1828 pWallet->Lock();
e3bc5698
JG
1829}
1830
1831Value walletpassphrase(const Array& params, bool fHelp)
1832{
b9fb692d
JS
1833 if (!EnsureWalletIsAvailable(fHelp))
1834 return Value::null;
1835
e3bc5698
JG
1836 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1837 throw runtime_error(
a6099ef3 1838 "walletpassphrase \"passphrase\" timeout\n"
1839 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
58c4c0bb 1840 "This is needed prior to performing transactions related to private keys such as sending zcash\n"
a6099ef3 1841 "\nArguments:\n"
1842 "1. \"passphrase\" (string, required) The wallet passphrase\n"
1843 "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
6c0db81c
WL
1844 "\nNote:\n"
1845 "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
1846 "time that overrides the old one.\n"
a6099ef3 1847 "\nExamples:\n"
1848 "\nunlock the wallet for 60 seconds\n"
1849 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
1850 "\nLock the wallet again (before 60 seconds)\n"
1851 + HelpExampleCli("walletlock", "") +
1852 "\nAs json rpc call\n"
1853 + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
1854 );
1855
4401b2d7
EL
1856 LOCK2(cs_main, pwalletMain->cs_wallet);
1857
e3bc5698
JG
1858 if (fHelp)
1859 return true;
1860 if (!pwalletMain->IsCrypted())
738835d7 1861 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
e3bc5698 1862
e3bc5698
JG
1863 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1864 SecureString strWalletPass;
1865 strWalletPass.reserve(100);
1866 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1867 // Alternately, find a way to make params[0] mlock()'d to begin with.
1868 strWalletPass = params[0].get_str().c_str();
1869
1870 if (strWalletPass.length() > 0)
1871 {
1872 if (!pwalletMain->Unlock(strWalletPass))
738835d7 1873 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
e3bc5698
JG
1874 }
1875 else
1876 throw runtime_error(
1877 "walletpassphrase <passphrase> <timeout>\n"
1878 "Stores the wallet decryption key in memory for <timeout> seconds.");
1879
6e263a5f 1880 // No need to check return values, because the wallet was unlocked above
1a62587e 1881 pwalletMain->UpdateNullifierNoteMap();
92f2c1fe
GA
1882 pwalletMain->TopUpKeyPool();
1883
51ed9ec9 1884 int64_t nSleepTime = params[1].get_int64();
92f2c1fe
GA
1885 LOCK(cs_nWalletUnlockTime);
1886 nWalletUnlockTime = GetTime() + nSleepTime;
1887 RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
e3bc5698
JG
1888
1889 return Value::null;
1890}
1891
1892
1893Value walletpassphrasechange(const Array& params, bool fHelp)
1894{
b9fb692d
JS
1895 if (!EnsureWalletIsAvailable(fHelp))
1896 return Value::null;
1897
e3bc5698
JG
1898 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1899 throw runtime_error(
a6099ef3 1900 "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
1901 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
1902 "\nArguments:\n"
1903 "1. \"oldpassphrase\" (string) The current passphrase\n"
1904 "2. \"newpassphrase\" (string) The new passphrase\n"
1905 "\nExamples:\n"
1906 + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
1907 + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
1908 );
1909
4401b2d7
EL
1910 LOCK2(cs_main, pwalletMain->cs_wallet);
1911
e3bc5698
JG
1912 if (fHelp)
1913 return true;
1914 if (!pwalletMain->IsCrypted())
738835d7 1915 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
e3bc5698
JG
1916
1917 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1918 // Alternately, find a way to make params[0] mlock()'d to begin with.
1919 SecureString strOldWalletPass;
1920 strOldWalletPass.reserve(100);
1921 strOldWalletPass = params[0].get_str().c_str();
1922
1923 SecureString strNewWalletPass;
1924 strNewWalletPass.reserve(100);
1925 strNewWalletPass = params[1].get_str().c_str();
1926
1927 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1928 throw runtime_error(
1929 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1930 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1931
1932 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
738835d7 1933 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
e3bc5698
JG
1934
1935 return Value::null;
1936}
1937
1938
1939Value walletlock(const Array& params, bool fHelp)
1940{
b9fb692d
JS
1941 if (!EnsureWalletIsAvailable(fHelp))
1942 return Value::null;
1943
e3bc5698
JG
1944 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1945 throw runtime_error(
1946 "walletlock\n"
a6099ef3 1947 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
e3bc5698 1948 "After calling this method, you will need to call walletpassphrase again\n"
a6099ef3 1949 "before being able to call any methods which require the wallet to be unlocked.\n"
1950 "\nExamples:\n"
1951 "\nSet the passphrase for 2 minutes to perform a transaction\n"
1952 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
1953 "\nPerform a send (requires passphrase set)\n"
1954 + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 1.0") +
1955 "\nClear the passphrase since we are done before 2 minutes is up\n"
1956 + HelpExampleCli("walletlock", "") +
1957 "\nAs json rpc call\n"
1958 + HelpExampleRpc("walletlock", "")
1959 );
1960
4401b2d7
EL
1961 LOCK2(cs_main, pwalletMain->cs_wallet);
1962
e3bc5698
JG
1963 if (fHelp)
1964 return true;
1965 if (!pwalletMain->IsCrypted())
738835d7 1966 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
e3bc5698
JG
1967
1968 {
1969 LOCK(cs_nWalletUnlockTime);
1970 pwalletMain->Lock();
1971 nWalletUnlockTime = 0;
1972 }
1973
1974 return Value::null;
1975}
1976
1977
1978Value encryptwallet(const Array& params, bool fHelp)
1979{
b9fb692d
JS
1980 if (!EnsureWalletIsAvailable(fHelp))
1981 return Value::null;
62c0aa9e
JG
1982
1983 auto fEnableWalletEncryption = GetBoolArg("-developerencryptwallet", false);
1984
1985 std::string strWalletEncryptionDisabledMsg = "";
1986 if (!fEnableWalletEncryption) {
1532cb75 1987 strWalletEncryptionDisabledMsg = "\nWARNING: Wallet encryption is DISABLED. This call always fails.\n";
62c0aa9e
JG
1988 }
1989
e3bc5698
JG
1990 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1991 throw runtime_error(
a6099ef3 1992 "encryptwallet \"passphrase\"\n"
62c0aa9e 1993 + strWalletEncryptionDisabledMsg +
a6099ef3 1994 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
1995 "After this, any calls that interact with private keys such as sending or signing \n"
1996 "will require the passphrase to be set prior the making these calls.\n"
1997 "Use the walletpassphrase call for this, and then walletlock call.\n"
1998 "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
1999 "Note that this will shutdown the server.\n"
2000 "\nArguments:\n"
2001 "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
2002 "\nExamples:\n"
2003 "\nEncrypt you wallet\n"
2004 + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
58c4c0bb 2005 "\nNow set the passphrase to use the wallet, such as for signing or sending zcash\n"
a6099ef3 2006 + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
2007 "\nNow we can so something like sign\n"
58c4c0bb 2008 + HelpExampleCli("signmessage", "\"zcashaddress\" \"test message\"") +
a6099ef3 2009 "\nNow lock the wallet again by removing the passphrase\n"
2010 + HelpExampleCli("walletlock", "") +
2011 "\nAs a json rpc call\n"
2012 + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
2013 );
2014
4401b2d7
EL
2015 LOCK2(cs_main, pwalletMain->cs_wallet);
2016
e3bc5698
JG
2017 if (fHelp)
2018 return true;
62c0aa9e 2019 if (!fEnableWalletEncryption) {
1532cb75 2020 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet encryption is disabled.");
62c0aa9e 2021 }
e3bc5698 2022 if (pwalletMain->IsCrypted())
738835d7 2023 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
e3bc5698
JG
2024
2025 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2026 // Alternately, find a way to make params[0] mlock()'d to begin with.
2027 SecureString strWalletPass;
2028 strWalletPass.reserve(100);
2029 strWalletPass = params[0].get_str().c_str();
2030
2031 if (strWalletPass.length() < 1)
2032 throw runtime_error(
2033 "encryptwallet <passphrase>\n"
2034 "Encrypts the wallet with <passphrase>.");
2035
2036 if (!pwalletMain->EncryptWallet(strWalletPass))
738835d7 2037 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
e3bc5698
JG
2038
2039 // BDB seems to have a bad habit of writing old data into
2040 // slack space in .dat files; that is bad if the old data is
331544bc 2041 // unencrypted private keys. So:
e3bc5698 2042 StartShutdown();
58c4c0bb 2043 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
2044}
2045
fdbb537d
JG
2046Value lockunspent(const Array& params, bool fHelp)
2047{
b9fb692d
JS
2048 if (!EnsureWalletIsAvailable(fHelp))
2049 return Value::null;
2050
fdbb537d
JG
2051 if (fHelp || params.size() < 1 || params.size() > 2)
2052 throw runtime_error(
a6099ef3 2053 "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
2054 "\nUpdates list of temporarily unspendable outputs.\n"
90fd8737 2055 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
58c4c0bb 2056 "A locked transaction output will not be chosen by automatic coin selection, when spending zcash.\n"
a6099ef3 2057 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2058 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
2059 "Also see the listunspent call\n"
2060 "\nArguments:\n"
2061 "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
2062 "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
2063 " [ (json array of json objects)\n"
2064 " {\n"
2065 " \"txid\":\"id\", (string) The transaction id\n"
2066 " \"vout\": n (numeric) The output number\n"
2067 " }\n"
2068 " ,...\n"
2069 " ]\n"
2070
2071 "\nResult:\n"
2072 "true|false (boolean) Whether the command was successful or not\n"
2073
2074 "\nExamples:\n"
2075 "\nList the unspent transactions\n"
2076 + HelpExampleCli("listunspent", "") +
2077 "\nLock an unspent transaction\n"
2078 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2079 "\nList the locked transactions\n"
2080 + HelpExampleCli("listlockunspent", "") +
2081 "\nUnlock the transaction again\n"
2082 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2083 "\nAs a json rpc call\n"
2084 + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
2085 );
fdbb537d 2086
4401b2d7
EL
2087 LOCK2(cs_main, pwalletMain->cs_wallet);
2088
fdbb537d 2089 if (params.size() == 1)
856e862f 2090 RPCTypeCheck(params, boost::assign::list_of(bool_type));
fdbb537d 2091 else
856e862f 2092 RPCTypeCheck(params, boost::assign::list_of(bool_type)(array_type));
fdbb537d
JG
2093
2094 bool fUnlock = params[0].get_bool();
2095
2096 if (params.size() == 1) {
2097 if (fUnlock)
2098 pwalletMain->UnlockAllCoins();
2099 return true;
2100 }
2101
2102 Array outputs = params[1].get_array();
2103 BOOST_FOREACH(Value& output, outputs)
2104 {
2105 if (output.type() != obj_type)
15117692 2106 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
fdbb537d
JG
2107 const Object& o = output.get_obj();
2108
856e862f 2109 RPCTypeCheck(o, boost::assign::map_list_of("txid", str_type)("vout", int_type));
fdbb537d
JG
2110
2111 string txid = find_value(o, "txid").get_str();
2112 if (!IsHex(txid))
15117692 2113 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
fdbb537d
JG
2114
2115 int nOutput = find_value(o, "vout").get_int();
2116 if (nOutput < 0)
15117692 2117 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
fdbb537d 2118
34cdc411 2119 COutPoint outpt(uint256S(txid), nOutput);
fdbb537d
JG
2120
2121 if (fUnlock)
2122 pwalletMain->UnlockCoin(outpt);
2123 else
2124 pwalletMain->LockCoin(outpt);
2125 }
2126
2127 return true;
2128}
2129
2130Value listlockunspent(const Array& params, bool fHelp)
2131{
b9fb692d
JS
2132 if (!EnsureWalletIsAvailable(fHelp))
2133 return Value::null;
2134
fdbb537d
JG
2135 if (fHelp || params.size() > 0)
2136 throw runtime_error(
2137 "listlockunspent\n"
a6099ef3 2138 "\nReturns list of temporarily unspendable outputs.\n"
2139 "See the lockunspent call to lock and unlock transactions for spending.\n"
2140 "\nResult:\n"
2141 "[\n"
2142 " {\n"
2143 " \"txid\" : \"transactionid\", (string) The transaction id locked\n"
2144 " \"vout\" : n (numeric) The vout value\n"
2145 " }\n"
2146 " ,...\n"
2147 "]\n"
2148 "\nExamples:\n"
2149 "\nList the unspent transactions\n"
2150 + HelpExampleCli("listunspent", "") +
2151 "\nLock an unspent transaction\n"
2152 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2153 "\nList the locked transactions\n"
2154 + HelpExampleCli("listlockunspent", "") +
2155 "\nUnlock the transaction again\n"
2156 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2157 "\nAs a json rpc call\n"
2158 + HelpExampleRpc("listlockunspent", "")
2159 );
fdbb537d 2160
4401b2d7
EL
2161 LOCK2(cs_main, pwalletMain->cs_wallet);
2162
fdbb537d
JG
2163 vector<COutPoint> vOutpts;
2164 pwalletMain->ListLockedCoins(vOutpts);
2165
2166 Array ret;
2167
2168 BOOST_FOREACH(COutPoint &outpt, vOutpts) {
2169 Object o;
2170
2171 o.push_back(Pair("txid", outpt.hash.GetHex()));
2172 o.push_back(Pair("vout", (int)outpt.n));
2173 ret.push_back(o);
2174 }
2175
2176 return ret;
2177}
2178
a943bde6
WL
2179Value settxfee(const Array& params, bool fHelp)
2180{
b9fb692d
JS
2181 if (!EnsureWalletIsAvailable(fHelp))
2182 return Value::null;
2183
a943bde6
WL
2184 if (fHelp || params.size() < 1 || params.size() > 1)
2185 throw runtime_error(
2186 "settxfee amount\n"
6943cb9b 2187 "\nSet the transaction fee per kB.\n"
a943bde6 2188 "\nArguments:\n"
6943cb9b 2189 "1. amount (numeric, required) The transaction fee in BTC/kB rounded to the nearest 0.00000001\n"
a943bde6
WL
2190 "\nResult\n"
2191 "true|false (boolean) Returns true if successful\n"
2192 "\nExamples:\n"
2193 + HelpExampleCli("settxfee", "0.00001")
2194 + HelpExampleRpc("settxfee", "0.00001")
2195 );
2196
4401b2d7
EL
2197 LOCK2(cs_main, pwalletMain->cs_wallet);
2198
a943bde6 2199 // Amount
a372168e 2200 CAmount nAmount = 0;
a943bde6
WL
2201 if (params[0].get_real() != 0.0)
2202 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
2203
c6cb21d1 2204 payTxFee = CFeeRate(nAmount, 1000);
a943bde6
WL
2205 return true;
2206}
2207
a00ebb51
DN
2208Value getwalletinfo(const Array& params, bool fHelp)
2209{
b9fb692d
JS
2210 if (!EnsureWalletIsAvailable(fHelp))
2211 return Value::null;
2212
a00ebb51
DN
2213 if (fHelp || params.size() != 0)
2214 throw runtime_error(
2215 "getwalletinfo\n"
2216 "Returns an object containing various wallet state info.\n"
2217 "\nResult:\n"
2218 "{\n"
2219 " \"walletversion\": xxxxx, (numeric) the wallet version\n"
58c4c0bb
SB
2220 " \"balance\": xxxxxxx, (numeric) the total confirmed zcash balance of the wallet\n"
2221 " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed zcash balance of the wallet\n"
8024d67d 2222 " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet\n"
a00ebb51
DN
2223 " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
2224 " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
2225 " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
2226 " \"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"
2227 "}\n"
2228 "\nExamples:\n"
2229 + HelpExampleCli("getwalletinfo", "")
2230 + HelpExampleRpc("getwalletinfo", "")
2231 );
2232
4401b2d7
EL
2233 LOCK2(cs_main, pwalletMain->cs_wallet);
2234
a00ebb51
DN
2235 Object obj;
2236 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
2237 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
8024d67d
GM
2238 obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
2239 obj.push_back(Pair("immature_balance", ValueFromAmount(pwalletMain->GetImmatureBalance())));
a00ebb51 2240 obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size()));
d56e30ca 2241 obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
a00ebb51
DN
2242 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
2243 if (pwalletMain->IsCrypted())
d56e30ca 2244 obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
a00ebb51
DN
2245 return obj;
2246}
0f5954c4
GA
2247
2248Value resendwallettransactions(const Array& params, bool fHelp)
2249{
b9fb692d
JS
2250 if (!EnsureWalletIsAvailable(fHelp))
2251 return Value::null;
2252
0f5954c4
GA
2253 if (fHelp || params.size() != 0)
2254 throw runtime_error(
2255 "resendwallettransactions\n"
2256 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
2257 "Intended only for testing; the wallet code periodically re-broadcasts\n"
2258 "automatically.\n"
2259 "Returns array of transaction ids that were re-broadcast.\n"
2260 );
2261
2262 LOCK2(cs_main, pwalletMain->cs_wallet);
2263
2264 std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
2265 Array result;
2266 BOOST_FOREACH(const uint256& txid, txids)
2267 {
2268 result.push_back(txid.ToString());
2269 }
2270 return result;
2271}
0b9dc9c8
JS
2272
2273Value listunspent(const Array& params, bool fHelp)
2274{
2275 if (!EnsureWalletIsAvailable(fHelp))
2276 return Value::null;
2277
2278 if (fHelp || params.size() > 3)
ea9e82df
JS
2279 throw runtime_error(
2280 "listunspent ( minconf maxconf [\"address\",...] )\n"
2281 "\nReturns array of unspent transaction outputs\n"
2282 "with between minconf and maxconf (inclusive) confirmations.\n"
2283 "Optionally filter to only include txouts paid to specified addresses.\n"
2284 "Results are an array of Objects, each of which has:\n"
2285 "{txid, vout, scriptPubKey, amount, confirmations}\n"
2286 "\nArguments:\n"
2287 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
2288 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
58c4c0bb 2289 "3. \"addresses\" (string) A json array of zcash addresses to filter\n"
ea9e82df 2290 " [\n"
58c4c0bb 2291 " \"address\" (string) zcash address\n"
ea9e82df
JS
2292 " ,...\n"
2293 " ]\n"
2294 "\nResult\n"
2295 "[ (array of json object)\n"
2296 " {\n"
2297 " \"txid\" : \"txid\", (string) the transaction id \n"
2298 " \"vout\" : n, (numeric) the vout value\n"
58c4c0bb 2299 " \"address\" : \"address\", (string) the zcash address\n"
ea9e82df
JS
2300 " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
2301 " \"scriptPubKey\" : \"key\", (string) the script key\n"
2302 " \"amount\" : x.xxx, (numeric) the transaction amount in btc\n"
2303 " \"confirmations\" : n (numeric) The number of confirmations\n"
2304 " }\n"
2305 " ,...\n"
2306 "]\n"
2307
2308 "\nExamples\n"
2309 + HelpExampleCli("listunspent", "")
2310 + HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2311 + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2312 );
2313
0b9dc9c8 2314 RPCTypeCheck(params, boost::assign::list_of(int_type)(int_type)(array_type));
ea9e82df 2315
0b9dc9c8
JS
2316 int nMinDepth = 1;
2317 if (params.size() > 0)
ea9e82df
JS
2318 nMinDepth = params[0].get_int();
2319
0b9dc9c8
JS
2320 int nMaxDepth = 9999999;
2321 if (params.size() > 1)
ea9e82df
JS
2322 nMaxDepth = params[1].get_int();
2323
0b9dc9c8
JS
2324 set<CBitcoinAddress> setAddress;
2325 if (params.size() > 2) {
2326 Array inputs = params[2].get_array();
2327 BOOST_FOREACH(Value& input, inputs) {
2328 CBitcoinAddress address(input.get_str());
2329 if (!address.IsValid())
58c4c0bb 2330 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+input.get_str());
0b9dc9c8 2331 if (setAddress.count(address))
ea9e82df
JS
2332 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
2333 setAddress.insert(address);
0b9dc9c8
JS
2334 }
2335 }
ea9e82df 2336
0b9dc9c8
JS
2337 Array results;
2338 vector<COutput> vecOutputs;
2339 assert(pwalletMain != NULL);
2340 LOCK2(cs_main, pwalletMain->cs_wallet);
219953ce 2341 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
0b9dc9c8
JS
2342 BOOST_FOREACH(const COutput& out, vecOutputs) {
2343 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
ea9e82df
JS
2344 continue;
2345
0b9dc9c8
JS
2346 if (setAddress.size()) {
2347 CTxDestination address;
2348 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
ea9e82df
JS
2349 continue;
2350
0b9dc9c8 2351 if (!setAddress.count(address))
ea9e82df 2352 continue;
0b9dc9c8 2353 }
ea9e82df 2354
0b9dc9c8
JS
2355 CAmount nValue = out.tx->vout[out.i].nValue;
2356 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
2357 Object entry;
805344dc 2358 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
0b9dc9c8
JS
2359 entry.push_back(Pair("vout", out.i));
2360 CTxDestination address;
2361 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
2362 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
2363 if (pwalletMain->mapAddressBook.count(address))
ea9e82df 2364 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
0b9dc9c8
JS
2365 }
2366 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
2367 if (pk.IsPayToScriptHash()) {
2368 CTxDestination address;
2369 if (ExtractDestination(pk, address)) {
8b08d953 2370 const CScriptID& hash = boost::get<CScriptID>(address);
0b9dc9c8
JS
2371 CScript redeemScript;
2372 if (pwalletMain->GetCScript(hash, redeemScript))
ea9e82df 2373 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
0b9dc9c8
JS
2374 }
2375 }
2376 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
2377 entry.push_back(Pair("confirmations",out.nDepth));
2378 entry.push_back(Pair("spendable", out.fSpendable));
2379 results.push_back(entry);
2380 }
ea9e82df 2381
0b9dc9c8 2382 return results;
c9fd9078 2383}
730790f7 2384
1737627c
SB
2385Value zc_sample_joinsplit(const json_spirit::Array& params, bool fHelp)
2386{
2387 if (fHelp) {
2388 throw runtime_error(
2389 "zcsamplejoinsplit\n"
2390 "\n"
2391 "Perform a joinsplit and return the JSDescription.\n"
2392 );
2393 }
2394
2395 LOCK(cs_main);
2396
2397 uint256 pubKeyHash;
2398 uint256 anchor = ZCIncrementalMerkleTree().root();
2399 JSDescription samplejoinsplit(*pzcashParams,
2400 pubKeyHash,
2401 anchor,
2402 {JSInput(), JSInput()},
2403 {JSOutput(), JSOutput()},
2404 0,
2405 0);
2406
2407 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2408 ss << samplejoinsplit;
2409
2410 return HexStr(ss.begin(), ss.end());
2411}
2412
6962bb3d
TH
2413Value zc_benchmark(const json_spirit::Array& params, bool fHelp)
2414{
2415 if (!EnsureWalletIsAvailable(fHelp)) {
2416 return Value::null;
2417 }
2418
2419 if (fHelp || params.size() < 2) {
2420 throw runtime_error(
2421 "zcbenchmark benchmarktype samplecount\n"
2422 "\n"
2423 "Runs a benchmark of the selected type samplecount times,\n"
2424 "returning the running times of each sample.\n"
2425 "\n"
2426 "Output: [\n"
2427 " {\n"
2428 " \"runningtime\": runningtime\n"
2429 " },\n"
2430 " {\n"
2431 " \"runningtime\": runningtime\n"
2432 " }\n"
2433 " ...\n"
2434 "]\n"
2435 );
2436 }
2437
2438 LOCK(cs_main);
2439
2440 std::string benchmarktype = params[0].get_str();
2441 int samplecount = params[1].get_int();
2442
2443 if (samplecount <= 0) {
2444 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount");
2445 }
2446
2447 std::vector<double> sample_times;
2448
2449 if (benchmarktype == "createjoinsplit") {
2450 /* Load the proving now key so that it doesn't happen as part of the
2451 * first joinsplit. */
2dc35992 2452 pzcashParams->loadProvingKey();
6962bb3d
TH
2453 }
2454
1737627c 2455 JSDescription samplejoinsplit;
2fbbde59
SB
2456
2457 if (benchmarktype == "verifyjoinsplit") {
1737627c
SB
2458 CDataStream ss(ParseHexV(params[2].get_str(), "js"), SER_NETWORK, PROTOCOL_VERSION);
2459 ss >> samplejoinsplit;
2fbbde59
SB
2460 }
2461
6962bb3d
TH
2462 for (int i = 0; i < samplecount; i++) {
2463 if (benchmarktype == "sleep") {
2464 sample_times.push_back(benchmark_sleep());
2465 } else if (benchmarktype == "parameterloading") {
2466 sample_times.push_back(benchmark_parameter_loading());
2467 } else if (benchmarktype == "createjoinsplit") {
2468 sample_times.push_back(benchmark_create_joinsplit());
2469 } else if (benchmarktype == "verifyjoinsplit") {
1737627c 2470 sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
bf8def97 2471 } else if (benchmarktype == "solveequihash") {
f7478de6 2472 if (params.size() < 3) {
9e52ca32 2473 sample_times.push_back(benchmark_solve_equihash());
f7478de6
JG
2474 } else {
2475 int nThreads = params[2].get_int();
9e52ca32
JG
2476 std::vector<double> vals = benchmark_solve_equihash_threaded(nThreads);
2477 sample_times.insert(sample_times.end(), vals.begin(), vals.end());
f7478de6 2478 }
bf8def97 2479 } else if (benchmarktype == "verifyequihash") {
a1cd1a27 2480 sample_times.push_back(benchmark_verify_equihash());
f5edc37f 2481 } else if (benchmarktype == "validatelargetx") {
9c45b501 2482 sample_times.push_back(benchmark_large_tx());
6962bb3d
TH
2483 } else {
2484 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
2485 }
2486 }
2487
2488 Array results;
9e52ca32 2489 for (auto time : sample_times) {
6962bb3d 2490 Object result;
9e52ca32 2491 result.push_back(Pair("runningtime", time));
6962bb3d
TH
2492 results.push_back(result);
2493 }
2494
2495 return results;
2496}
2497
a8ac403d
SB
2498Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
2499{
f15b9549
NW
2500 if (!EnsureWalletIsAvailable(fHelp)) {
2501 return Value::null;
2502 }
2503
2504 if (fHelp || params.size() != 2) {
2505 throw runtime_error(
eae37941 2506 "zcrawreceive zcsecretkey encryptednote\n"
f15b9549 2507 "\n"
ca0ec80b 2508 "DEPRECATED. Decrypts encryptednote and checks if the coin commitments\n"
f15b9549
NW
2509 "are in the blockchain as indicated by the \"exists\" result.\n"
2510 "\n"
2511 "Output: {\n"
2512 " \"amount\": value,\n"
4bc00dc1 2513 " \"note\": noteplaintext,\n"
f15b9549
NW
2514 " \"exists\": exists\n"
2515 "}\n"
2516 );
2517 }
2518
a8ac403d 2519 RPCTypeCheck(params, boost::assign::list_of(str_type)(str_type));
f15b9549 2520
a8ac403d
SB
2521 LOCK(cs_main);
2522
0d6864e4
SB
2523 CZCSpendingKey spendingkey(params[0].get_str());
2524 SpendingKey k = spendingkey.Get();
a8ac403d 2525
6c36a9fe
SB
2526 uint256 epk;
2527 unsigned char nonce;
2528 ZCNoteEncryption::Ciphertext ct;
2dc35992 2529 uint256 h_sig;
6c36a9fe
SB
2530
2531 {
4bc00dc1 2532 CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
6c36a9fe
SB
2533 try {
2534 ssData >> nonce;
2535 ssData >> epk;
2536 ssData >> ct;
2dc35992 2537 ssData >> h_sig;
6c36a9fe
SB
2538 } catch(const std::exception &) {
2539 throw runtime_error(
4bc00dc1 2540 "encrypted_note could not be decoded"
6c36a9fe
SB
2541 );
2542 }
2543 }
2544
2dc35992 2545 ZCNoteDecryption decryptor(k.viewing_key());
a8ac403d 2546
2dc35992
SB
2547 NotePlaintext npt = NotePlaintext::decrypt(
2548 decryptor,
2549 ct,
2550 epk,
2551 h_sig,
2552 nonce
2553 );
2554 PaymentAddress payment_addr = k.address();
2555 Note decrypted_note = npt.note(payment_addr);
a8ac403d
SB
2556
2557 assert(pwalletMain != NULL);
2dc35992 2558 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
a8ac403d 2559 uint256 anchor;
2dc35992 2560 uint256 commitment = decrypted_note.cm();
4bc00dc1 2561 pwalletMain->WitnessNoteCommitment(
2dc35992
SB
2562 {commitment},
2563 witnesses,
2564 anchor
2565 );
a8ac403d
SB
2566
2567 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2dc35992 2568 ss << npt;
a8ac403d
SB
2569
2570 Object result;
2dc35992 2571 result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value)));
4bc00dc1 2572 result.push_back(Pair("note", HexStr(ss.begin(), ss.end())));
2dc35992 2573 result.push_back(Pair("exists", (bool) witnesses[0]));
a8ac403d
SB
2574 return result;
2575}
2576
2dc35992
SB
2577
2578
b7e4abd6 2579Value zc_raw_joinsplit(const json_spirit::Array& params, bool fHelp)
730790f7 2580{
f15b9549
NW
2581 if (!EnsureWalletIsAvailable(fHelp)) {
2582 return Value::null;
2583 }
2584
2585 if (fHelp || params.size() != 5) {
2586 throw runtime_error(
eae37941 2587 "zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
4bc00dc1 2588 " inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
f15b9549
NW
2589 " outputs: a JSON object mapping {zcaddr: value, ...}\n"
2590 "\n"
ca0ec80b 2591 "DEPRECATED. Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
f15b9549
NW
2592 "Outputs are confidential between sender/receiver. The vpub_old and\n"
2593 "vpub_new values are globally public and move transparent value into\n"
2594 "or out of the confidential value store, respectively.\n"
2595 "\n"
2596 "Note: The caller is responsible for delivering the output enc1 and\n"
2597 "enc2 to the appropriate recipients, as well as signing rawtxout and\n"
2598 "ensuring it is mined. (A future RPC call will deliver the confidential\n"
2599 "payments in-band on the blockchain.)\n"
2600 "\n"
2601 "Output: {\n"
4bc00dc1
DH
2602 " \"encryptednote1\": enc1,\n"
2603 " \"encryptednote2\": enc2,\n"
f15b9549
NW
2604 " \"rawtxn\": rawtxout\n"
2605 "}\n"
2606 );
2607 }
2608
a8ac403d 2609 LOCK(cs_main);
730790f7
SB
2610
2611 CTransaction tx;
2612 if (!DecodeHexTx(tx, params[0].get_str()))
2613 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2614
2615 Object inputs = params[1].get_obj();
2616 Object outputs = params[2].get_obj();
2617
2618 CAmount vpub_old(0);
2619 CAmount vpub_new(0);
2620
2621 if (params[3].get_real() != 0.0)
2622 vpub_old = AmountFromValue(params[3]);
2623
2624 if (params[4].get_real() != 0.0)
2625 vpub_new = AmountFromValue(params[4]);
2626
b7e4abd6
SB
2627 std::vector<JSInput> vjsin;
2628 std::vector<JSOutput> vjsout;
2dc35992
SB
2629 std::vector<Note> notes;
2630 std::vector<SpendingKey> keys;
2631 std::vector<uint256> commitments;
a8ac403d 2632
730790f7
SB
2633 BOOST_FOREACH(const Pair& s, inputs)
2634 {
0d6864e4
SB
2635 CZCSpendingKey spendingkey(s.value_.get_str());
2636 SpendingKey k = spendingkey.Get();
a8ac403d 2637
2dc35992 2638 keys.push_back(k);
a8ac403d 2639
2dc35992 2640 NotePlaintext npt;
a8ac403d 2641
2dc35992 2642 {
4bc00dc1 2643 CDataStream ssData(ParseHexV(s.name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
2dc35992 2644 ssData >> npt;
a8ac403d
SB
2645 }
2646
2dc35992
SB
2647 PaymentAddress addr = k.address();
2648 Note note = npt.note(addr);
2649 notes.push_back(note);
2650 commitments.push_back(note.cm());
2651 }
2652
2653 uint256 anchor;
2654 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
4bc00dc1 2655 pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
2dc35992
SB
2656
2657 assert(witnesses.size() == notes.size());
2658 assert(notes.size() == keys.size());
2659
2660 {
2661 for (size_t i = 0; i < witnesses.size(); i++) {
2662 if (!witnesses[i]) {
2663 throw runtime_error(
b7e4abd6 2664 "joinsplit input could not be found in tree"
2dc35992
SB
2665 );
2666 }
2667
b7e4abd6 2668 vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
2dc35992 2669 }
730790f7 2670 }
730790f7 2671
b7e4abd6
SB
2672 while (vjsin.size() < ZC_NUM_JS_INPUTS) {
2673 vjsin.push_back(JSInput());
a8ac403d 2674 }
730790f7
SB
2675
2676 BOOST_FOREACH(const Pair& s, outputs)
2677 {
e104fcdd
SB
2678 CZCPaymentAddress pubaddr(s.name_);
2679 PaymentAddress addrTo = pubaddr.Get();
730790f7
SB
2680 CAmount nAmount = AmountFromValue(s.value_);
2681
b7e4abd6 2682 vjsout.push_back(JSOutput(addrTo, nAmount));
730790f7
SB
2683 }
2684
b7e4abd6
SB
2685 while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
2686 vjsout.push_back(JSOutput());
730790f7
SB
2687 }
2688
2689 // TODO
b7e4abd6
SB
2690 if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
2691 throw runtime_error("unsupported joinsplit input/output counts");
730790f7
SB
2692 }
2693
320f2cc7
SB
2694 uint256 joinSplitPubKey;
2695 unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
2696 crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
6aae9d1a
TH
2697
2698 CMutableTransaction mtx(tx);
2699 mtx.nVersion = 2;
2700 mtx.joinSplitPubKey = joinSplitPubKey;
2701
22de1602
SB
2702 JSDescription jsdesc(*pzcashParams,
2703 joinSplitPubKey,
2704 anchor,
2705 {vjsin[0], vjsin[1]},
2706 {vjsout[0], vjsout[1]},
2707 vpub_old,
2708 vpub_new);
320f2cc7 2709
22de1602 2710 assert(jsdesc.Verify(*pzcashParams, joinSplitPubKey));
730790f7 2711
22de1602 2712 mtx.vjoinsplit.push_back(jsdesc);
730790f7 2713
6aae9d1a
TH
2714 // Empty output script.
2715 CScript scriptCode;
2716 CTransaction signTx(mtx);
2717 uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
6aae9d1a
TH
2718
2719 // Add the signature
320f2cc7
SB
2720 assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
2721 dataToBeSigned.begin(), 32,
2722 joinSplitPrivKey
2723 ) == 0);
2724
2725 // Sanity check
2726 assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
2727 dataToBeSigned.begin(), 32,
2728 mtx.joinSplitPubKey.begin()
2729 ) == 0);
6aae9d1a 2730
730790f7
SB
2731 CTransaction rawTx(mtx);
2732
2733 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2734 ss << rawTx;
2735
4bc00dc1
DH
2736 std::string encryptedNote1;
2737 std::string encryptedNote2;
6c36a9fe
SB
2738 {
2739 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
2740 ss2 << ((unsigned char) 0x00);
22de1602
SB
2741 ss2 << jsdesc.ephemeralKey;
2742 ss2 << jsdesc.ciphertexts[0];
2743 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
6c36a9fe 2744
4bc00dc1 2745 encryptedNote1 = HexStr(ss2.begin(), ss2.end());
6c36a9fe
SB
2746 }
2747 {
2748 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
2749 ss2 << ((unsigned char) 0x01);
22de1602
SB
2750 ss2 << jsdesc.ephemeralKey;
2751 ss2 << jsdesc.ciphertexts[1];
2752 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
6c36a9fe 2753
4bc00dc1 2754 encryptedNote2 = HexStr(ss2.begin(), ss2.end());
6c36a9fe
SB
2755 }
2756
730790f7 2757 Object result;
4bc00dc1
DH
2758 result.push_back(Pair("encryptednote1", encryptedNote1));
2759 result.push_back(Pair("encryptednote2", encryptedNote2));
730790f7
SB
2760 result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
2761 return result;
2762}
2763
2764Value zc_raw_keygen(const json_spirit::Array& params, bool fHelp)
2765{
f15b9549
NW
2766 if (!EnsureWalletIsAvailable(fHelp)) {
2767 return Value::null;
2768 }
2769
2770 if (fHelp || params.size() != 0) {
2771 throw runtime_error(
eae37941 2772 "zcrawkeygen\n"
f15b9549 2773 "\n"
ca0ec80b 2774 "DEPRECATED. Generate a zcaddr which can send and receive confidential values.\n"
f15b9549
NW
2775 "\n"
2776 "Output: {\n"
2777 " \"zcaddress\": zcaddr,\n"
2778 " \"zcsecretkey\": zcsecretkey,\n"
2779 "}\n"
2780 );
2781 }
2782
2dc35992
SB
2783 auto k = SpendingKey::random();
2784 auto addr = k.address();
2785 auto viewing_key = k.viewing_key();
730790f7 2786
2dc35992 2787 CDataStream viewing(SER_NETWORK, PROTOCOL_VERSION);
730790f7 2788
2dc35992 2789 viewing << viewing_key;
730790f7 2790
e104fcdd 2791 CZCPaymentAddress pubaddr(addr);
0d6864e4 2792 CZCSpendingKey spendingkey(k);
2dc35992 2793 std::string viewing_hex = HexStr(viewing.begin(), viewing.end());
730790f7
SB
2794
2795 Object result;
e104fcdd 2796 result.push_back(Pair("zcaddress", pubaddr.ToString()));
0d6864e4 2797 result.push_back(Pair("zcsecretkey", spendingkey.ToString()));
2dc35992 2798 result.push_back(Pair("zcviewingkey", viewing_hex));
730790f7 2799 return result;
f15b9549 2800}
c1c45943
S
2801
2802
2803Value z_getnewaddress(const Array& params, bool fHelp)
2804{
2805 if (!EnsureWalletIsAvailable(fHelp))
2806 return Value::null;
2807
49e591eb 2808 if (fHelp || params.size() > 0)
c1c45943
S
2809 throw runtime_error(
2810 "z_getnewaddress\n"
2811 "\nReturns a new zaddr for receiving payments.\n"
2812 "\nArguments:\n"
2813 "\nResult:\n"
2814 "\"zcashaddress\" (string) The new zaddr\n"
2815 "\nExamples:\n"
2816 + HelpExampleCli("z_getnewaddress", "")
2817 + HelpExampleRpc("z_getnewaddress", "")
2818 );
2819
2820 LOCK2(cs_main, pwalletMain->cs_wallet);
2821
73699cea
S
2822 EnsureWalletIsUnlocked();
2823
c1c45943
S
2824 CZCPaymentAddress pubaddr = pwalletMain->GenerateNewZKey();
2825 std::string result = pubaddr.ToString();
2826 return result;
2827}
2828
e709997f
S
2829
2830Value z_listaddresses(const Array& params, bool fHelp)
2831{
2832 if (!EnsureWalletIsAvailable(fHelp))
2833 return Value::null;
2834
2835 if (fHelp || params.size() > 1)
2836 throw runtime_error(
2837 "z_listaddresses\n"
2838 "\nReturns the list of zaddr belonging to the wallet.\n"
2839 "\nArguments:\n"
2840 "\nResult:\n"
2841 "[ (json array of string)\n"
2842 " \"zaddr\" (string) a zaddr belonging to the wallet\n"
2843 " ,...\n"
2844 "]\n"
2845 "\nExamples:\n"
2846 + HelpExampleCli("z_listaddresses", "")
2847 + HelpExampleRpc("z_listaddresses", "")
2848 );
2849
2850 LOCK2(cs_main, pwalletMain->cs_wallet);
2851
2852 Array ret;
2853 std::set<libzcash::PaymentAddress> addresses;
2854 pwalletMain->GetPaymentAddresses(addresses);
2855 for (auto addr : addresses ) {
2856 ret.push_back(CZCPaymentAddress(addr).ToString());
2857 }
2858 return ret;
2859}
2860
dec49d1f 2861CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1) {
a0a3334c
S
2862 set<CBitcoinAddress> setAddress;
2863 vector<COutput> vecOutputs;
2864 CAmount balance = 0;
2865
2866 if (transparentAddress.length() > 0) {
2867 CBitcoinAddress taddr = CBitcoinAddress(transparentAddress);
2868 if (!taddr.IsValid()) {
2869 throw std::runtime_error("invalid transparent address");
2870 }
2871 setAddress.insert(taddr);
2872 }
2873
2874 LOCK2(cs_main, pwalletMain->cs_wallet);
2875
2876 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2877
2878 BOOST_FOREACH(const COutput& out, vecOutputs) {
2879 if (out.nDepth < minDepth) {
2880 continue;
2881 }
2882
2883 if (setAddress.size()) {
2884 CTxDestination address;
2885 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
2886 continue;
2887 }
2888
2889 if (!setAddress.count(address)) {
2890 continue;
2891 }
2892 }
2893
2894 CAmount nValue = out.tx->vout[out.i].nValue;
2895 balance += nValue;
2896 }
2897 return balance;
2898}
2899
dec49d1f 2900CAmount getBalanceZaddr(std::string address, int minDepth = 1) {
a0a3334c 2901 CAmount balance = 0;
a9743bc8 2902 std::vector<CNotePlaintextEntry> entries;
a0a3334c 2903 LOCK2(cs_main, pwalletMain->cs_wallet);
1b141933 2904 pwalletMain->GetFilteredNotes(entries, address, minDepth);
a9743bc8
S
2905 for (auto & entry : entries) {
2906 balance += CAmount(entry.plaintext.value);
a0a3334c 2907 }
a0a3334c
S
2908 return balance;
2909}
2910
2911
6c41028f
S
2912Value z_listreceivedbyaddress(const Array& params, bool fHelp)
2913{
2914 if (!EnsureWalletIsAvailable(fHelp))
2915 return Value::null;
2916
2917 if (fHelp || params.size()==0 || params.size() >2)
2918 throw runtime_error(
2919 "z_listreceivedbyaddress \"address\" ( minconf )\n"
2920 "\nReturn a list of amounts received by a zaddr belonging to the node’s wallet.\n"
2921 "\nArguments:\n"
2922 "1. \"address\" (string) The private address.\n"
2923 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
2924 "\nResult:\n"
2925 "{\n"
2926 " \"txid\": xxxxx, (string) the transaction id\n"
2927 " \"amount\": xxxxx, (numeric) the amount of value in the note\n"
2928 " \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
2929 "}\n"
2930 );
2931
2932 LOCK2(cs_main, pwalletMain->cs_wallet);
2933
2934 int nMinDepth = 1;
2935 if (params.size() > 1) {
2936 nMinDepth = params[1].get_int();
2937 }
2938 if (nMinDepth < 0) {
2939 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
2940 }
2941
2942 // Check that the from address is valid.
2943 auto fromaddress = params[0].get_str();
2944
2945 libzcash::PaymentAddress zaddr;
2946 CZCPaymentAddress address(fromaddress);
2947 try {
2948 zaddr = address.Get();
2949 } catch (std::runtime_error) {
2950 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
2951 }
2952
2953 if (!pwalletMain->HaveSpendingKey(zaddr)) {
2954 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
2955 }
2956
2957
2958 Array result;
2959 std::vector<CNotePlaintextEntry> entries;
2960 pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false);
2961 for (CNotePlaintextEntry & entry : entries) {
2962 Object obj;
2963 obj.push_back(Pair("txid",entry.jsop.hash.ToString()));
2964 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value))));
2965 std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end());
2966 obj.push_back(Pair("memo", HexStr(data)));
2967 result.push_back(obj);
2968 }
2969 return result;
2970}
2971
2972
a0a3334c
S
2973Value z_getbalance(const Array& params, bool fHelp)
2974{
2975 if (!EnsureWalletIsAvailable(fHelp))
2976 return Value::null;
2977
2978 if (fHelp || params.size()==0 || params.size() >2)
2979 throw runtime_error(
2980 "z_getbalance \"address\" ( minconf )\n"
2981 "\nReturns the balance of a taddr or zaddr belonging to the node’s wallet.\n"
2982 "\nArguments:\n"
2983 "1. \"address\" (string) The selected address. It may be a transparent or private address.\n"
2984 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
2985 "\nResult:\n"
2986 "amount (numeric) The total amount in ZEC received for this address.\n"
2987 "\nExamples:\n"
2988 "\nThe total amount received by address \"myaddress\"\n"
2989 + HelpExampleCli("z_getbalance", "\"myaddress\"") +
2990 "\nThe total amount received by address \"myaddress\" at least 5 blocks confirmed\n"
2991 + HelpExampleCli("z_getbalance", "\"myaddress\" 5") +
2992 "\nAs a json rpc call\n"
2993 + HelpExampleRpc("z_getbalance", "\"myaddress\", 5")
2994 );
2995
2996 LOCK2(cs_main, pwalletMain->cs_wallet);
2997
2998 int nMinDepth = 1;
2999 if (params.size() > 1) {
3000 nMinDepth = params[1].get_int();
3001 }
12448b64
S
3002 if (nMinDepth < 0) {
3003 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3004 }
a0a3334c
S
3005
3006 // Check that the from address is valid.
3007 auto fromaddress = params[0].get_str();
3008 bool fromTaddr = false;
3009 CBitcoinAddress taddr(fromaddress);
3010 fromTaddr = taddr.IsValid();
3011 libzcash::PaymentAddress zaddr;
3012 if (!fromTaddr) {
3013 CZCPaymentAddress address(fromaddress);
3014 try {
3015 zaddr = address.Get();
3016 } catch (std::runtime_error) {
3017 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3018 }
12448b64
S
3019 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3020 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3021 }
a0a3334c
S
3022 }
3023
3024 CAmount nBalance = 0;
3025 if (fromTaddr) {
3026 nBalance = getBalanceTaddr(fromaddress, nMinDepth);
3027 } else {
3028 nBalance = getBalanceZaddr(fromaddress, nMinDepth);
3029 }
3030
3031 return ValueFromAmount(nBalance);
3032}
3033
3034
3035Value z_gettotalbalance(const Array& params, bool fHelp)
3036{
3037 if (!EnsureWalletIsAvailable(fHelp))
3038 return Value::null;
3039
3040 if (fHelp || params.size() > 1)
3041 throw runtime_error(
3042 "z_gettotalbalance ( minconf )\n"
3043 "\nReturn the total value of funds stored in the node’s wallet.\n"
3044 "\nArguments:\n"
3045 "1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
3046 "\nResult:\n"
3047 "{\n"
3048 " \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
3049 " \"private\": xxxxx, (numeric) the total balance of private funds\n"
3050 " \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n"
3051 "}\n"
3052 "\nExamples:\n"
3053 "\nThe total amount in the wallet\n"
3054 + HelpExampleCli("z_gettotalbalance", "") +
3055 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3056 + HelpExampleCli("z_gettotalbalance", "5") +
3057 "\nAs a json rpc call\n"
3058 + HelpExampleRpc("z_gettotalbalance", "5")
3059 );
3060
3061 LOCK2(cs_main, pwalletMain->cs_wallet);
3062
3063 int nMinDepth = 1;
3064 if (params.size() == 1) {
3065 nMinDepth = params[0].get_int();
3066 }
12448b64
S
3067 if (nMinDepth < 0) {
3068 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3069 }
a0a3334c
S
3070
3071 // getbalance and "getbalance * 1 true" should return the same number
3072 // but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
3073 // pwalletMain->GetBalance() does not accept min depth parameter
3074 // so we use our own method to get balance of utxos.
3075 CAmount nBalance = getBalanceTaddr("", nMinDepth);
3076 CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth);
3077 CAmount nTotalBalance = nBalance + nPrivateBalance;
3078 Object result;
3079 result.push_back(Pair("transparent", FormatMoney(nBalance, false)));
3080 result.push_back(Pair("private", FormatMoney(nPrivateBalance, false)));
3081 result.push_back(Pair("total", FormatMoney(nTotalBalance, false)));
3082 return result;
3083}
3084
c1eae280
S
3085Value z_getoperationresult(const Array& params, bool fHelp)
3086{
3087 if (!EnsureWalletIsAvailable(fHelp))
3088 return Value::null;
3089
3090 if (fHelp || params.size() > 1)
3091 throw runtime_error(
3092 "z_getoperationresult ([\"operationid\", ... ]) \n"
3093 "\nRetrieve the result and status of an operation which has finished, and then remove the operation from memory."
3094 + HelpRequiringPassphrase() + "\n"
3095 "\nArguments:\n"
3096 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3097 "\nResult:\n"
3098 "\" [object, ...]\" (array) A list of JSON objects\n"
3099 );
3100
3101 // This call will remove finished operations
3102 return z_getoperationstatus_IMPL(params, true);
3103}
fc72c078
S
3104
3105Value z_getoperationstatus(const Array& params, bool fHelp)
3106{
3107 if (!EnsureWalletIsAvailable(fHelp))
3108 return Value::null;
3109
34f0001c 3110 if (fHelp || params.size() > 1)
fc72c078 3111 throw runtime_error(
34f0001c 3112 "z_getoperationstatus ([\"operationid\", ... ]) \n"
c1eae280 3113 "\nGet operation status and any associated result or error data. The operation will remain in memory."
fc72c078
S
3114 + HelpRequiringPassphrase() + "\n"
3115 "\nArguments:\n"
c1eae280 3116 "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 3117 "\nResult:\n"
34f0001c 3118 "\" [object, ...]\" (array) A list of JSON objects\n"
fc72c078 3119 );
c1eae280
S
3120
3121 // This call is idempotent so we don't want to remove finished operations
3122 return z_getoperationstatus_IMPL(params, false);
3123}
fc72c078 3124
c1eae280
S
3125Value z_getoperationstatus_IMPL(const Array& params, bool fRemoveFinishedOperations=false)
3126{
fc72c078
S
3127 LOCK2(cs_main, pwalletMain->cs_wallet);
3128
34f0001c
S
3129 std::set<AsyncRPCOperationId> filter;
3130 if (params.size()==1) {
3131 Array ids = params[0].get_array();
3132 for (Value & v : ids) {
3133 filter.insert(v.get_str());
3134 }
fc72c078 3135 }
34f0001c 3136 bool useFilter = (filter.size()>0);
fc72c078 3137
34f0001c
S
3138 Array ret;
3139 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3140 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3141
3142 for (auto id : ids) {
3143 if (useFilter && !filter.count(id))
3144 continue;
3145
3146 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3147 if (!operation) {
3148 continue;
3149 // It's possible that the operation was removed from the internal queue and map during this loop
3150 // throw JSONRPCError(RPC_INVALID_PARAMETER, "No operation exists for that id.");
3151 }
3152
3153 Value status = operation->getStatus();
fc72c078 3154
c1eae280
S
3155 if (fRemoveFinishedOperations) {
3156 // Caller is only interested in retrieving finished results
3157 if (operation->isSuccess() || operation->isFailed() || operation->isCancelled()) {
3158 ret.push_back(status);
3159 q->popOperationForId(id);
3160 }
3161 } else {
3162 ret.push_back(status);
34f0001c 3163 }
fc72c078
S
3164 }
3165
34f0001c 3166 return ret;
fc72c078
S
3167}
3168
3920292b
S
3169
3170// Here we define the maximum number of zaddr outputs that can be included in a transaction.
3171// If input notes are small, we might actually require more than one joinsplit per zaddr output.
3172// For now though, we assume we use one joinsplit per zaddr output (and the second output note is change).
3173// We reduce the result by 1 to ensure there is room for non-joinsplit CTransaction data.
3174#define Z_SENDMANY_MAX_ZADDR_OUTPUTS ((MAX_TX_SIZE / JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)) - 1)
3175
3176// transaction.h comment: spending taddr output requires CTxIn >= 148 bytes and typical taddr txout is 34 bytes
3177#define CTXIN_SPEND_DUST_SIZE 148
3178#define CTXOUT_REGULAR_SIZE 34
3179
fc72c078
S
3180Value z_sendmany(const Array& params, bool fHelp)
3181{
3182 if (!EnsureWalletIsAvailable(fHelp))
3183 return Value::null;
3184
3185 if (fHelp || params.size() < 2 || params.size() > 3)
3186 throw runtime_error(
3187 "z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf )\n"
fc72c078 3188 "\nSend multiple times. Amounts are double-precision floating point numbers."
b7d7b2ad 3189 "\nChange from a taddr flows to a new taddr address, while change from zaddr returns to itself."
db026807 3190 "\nWhen sending coinbase UTXOs to a zaddr, change is not alllowed. The entire value of the UTXO(s) must be consumed."
3920292b 3191 + strprintf("\nCurrently, the maximum number of zaddr outputs is %d due to transaction size limits.\n", Z_SENDMANY_MAX_ZADDR_OUTPUTS)
fc72c078
S
3192 + HelpRequiringPassphrase() + "\n"
3193 "\nArguments:\n"
3194 "1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from.\n"
3195 "2. \"amounts\" (array, required) An array of json objects representing the amounts to send.\n"
3196 " [{\n"
3197 " \"address\":address (string, required) The address is a taddr or zaddr\n"
3198 " \"amount\":amount (numeric, required) The numeric amount in ZEC is the value\n"
3199 " \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
3200 " }, ... ]\n"
3201 "3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
3202 "\nResult:\n"
3203 "\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
3204 );
3205
3206 LOCK2(cs_main, pwalletMain->cs_wallet);
3207
fc72c078
S
3208 // Check that the from address is valid.
3209 auto fromaddress = params[0].get_str();
3210 bool fromTaddr = false;
3211 CBitcoinAddress taddr(fromaddress);
3212 fromTaddr = taddr.IsValid();
3213 libzcash::PaymentAddress zaddr;
3214 if (!fromTaddr) {
3215 CZCPaymentAddress address(fromaddress);
3216 try {
3217 zaddr = address.Get();
3218 } catch (std::runtime_error) {
3219 // invalid
3220 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3221 }
3222 }
3223
dafb8161 3224 // Check that we have the spending key
fc72c078
S
3225 if (!fromTaddr) {
3226 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3227 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3228 }
3229 }
3230
fc72c078
S
3231 Array outputs = params[1].get_array();
3232
3233 if (outputs.size()==0)
3234 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
3235
3236 // Keep track of addresses to spot duplicates
3237 set<std::string> setAddress;
3238
3239 // Recipients
dafb8161
S
3240 std::vector<SendManyRecipient> taddrRecipients;
3241 std::vector<SendManyRecipient> zaddrRecipients;
fc72c078
S
3242
3243 BOOST_FOREACH(Value& output, outputs)
3244 {
3245 if (output.type() != obj_type)
3246 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
3247 const Object& o = output.get_obj();
3248
fc72c078 3249 // sanity check, report error if unknown key-value pairs
fc72c078
S
3250 for (const Pair& p : o) {
3251 std::string s = p.name_;
3252 if (s != "address" && s != "amount" && s!="memo")
3253 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown key: ")+s);
3254 }
3255
3256 string address = find_value(o, "address").get_str();
3257 bool isZaddr = false;
3258 CBitcoinAddress taddr(address);
3259 if (!taddr.IsValid()) {
3260 try {
3261 CZCPaymentAddress zaddr(address);
3262 zaddr.Get();
3263 isZaddr = true;
3264 } catch (std::runtime_error) {
3265 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
3266 }
3267 }
3268
3269 if (setAddress.count(address))
3270 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address);
3271 setAddress.insert(address);
3272
3273 Value memoValue = find_value(o, "memo");
3274 string memo;
3275 if (!memoValue.is_null()) {
3276 memo = memoValue.get_str();
3277 if (!isZaddr) {
3278 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
3279 } else if (!IsHex(memo)) {
3280 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
3281 }
6114cfe7 3282 if (memo.length() > ZC_MEMO_SIZE*2) {
dafb8161
S
3283 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
3284 }
fc72c078
S
3285 }
3286
fc72c078
S
3287 Value av = find_value(o, "amount");
3288 CAmount nAmount = AmountFromValue( av );
3289 if (nAmount < 0)
3290 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
3291
dafb8161
S
3292 if (isZaddr) {
3293 zaddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3294 } else {
3295 taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3296 }
fc72c078
S
3297 }
3298
3920292b
S
3299 // Check the number of zaddr outputs does not exceed the limit.
3300 if (zaddrRecipients.size() > Z_SENDMANY_MAX_ZADDR_OUTPUTS) {
3301 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, too many zaddr outputs");
3302 }
3303
3304 // As a sanity check, estimate and verify that the size of the transaction will be valid.
3305 // Depending on the input notes, the actual tx size may turn out to be larger and perhaps invalid.
3306 size_t txsize = 0;
3307 CMutableTransaction mtx;
3308 mtx.nVersion = 2;
3309 for (int i = 0; i < zaddrRecipients.size(); i++) {
3310 mtx.vjoinsplit.push_back(JSDescription());
3311 }
3312 CTransaction tx(mtx);
3313 txsize += tx.GetSerializeSize(SER_NETWORK, tx.nVersion);
3314 if (fromTaddr) {
3315 txsize += CTXIN_SPEND_DUST_SIZE;
3316 txsize += CTXOUT_REGULAR_SIZE; // There will probably be taddr change
3317 }
3318 txsize += CTXOUT_REGULAR_SIZE * taddrRecipients.size();
3319 if (txsize > MAX_TX_SIZE) {
3320 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Too many outputs, size of raw transaction would be larger than limit of %d bytes", MAX_TX_SIZE ));
3321 }
3322
fc72c078
S
3323 // Minimum confirmations
3324 int nMinDepth = 1;
12448b64 3325 if (params.size() > 2) {
fc72c078 3326 nMinDepth = params[2].get_int();
12448b64
S
3327 }
3328 if (nMinDepth < 0) {
3329 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3330 }
fc72c078 3331
dafb8161 3332 // Create operation and add to global queue
fc72c078 3333 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
dafb8161 3334 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(fromaddress, taddrRecipients, zaddrRecipients, nMinDepth) );
fc72c078
S
3335 q->addOperation(operation);
3336 AsyncRPCOperationId operationId = operation->getId();
3337 return operationId;
fc72c078 3338}
34f0001c
S
3339
3340
3341Value z_listoperationids(const Array& params, bool fHelp)
3342{
3343 if (!EnsureWalletIsAvailable(fHelp))
3344 return Value::null;
3345
3346 if (fHelp || params.size() > 1)
3347 throw runtime_error(
3348 "z_listoperationids\n"
3349 "\nReturns the list of operation ids currently known to the wallet.\n"
3350 "\nArguments:\n"
3351 "1. \"status\" (string, optional) Filter result by the operation's state state e.g. \"success\".\n"
3352 "\nResult:\n"
3353 "[ (json array of string)\n"
3354 " \"operationid\" (string) an operation id belonging to the wallet\n"
3355 " ,...\n"
3356 "]\n"
3357 "\nExamples:\n"
3358 + HelpExampleCli("z_listoperationids", "")
3359 + HelpExampleRpc("z_listoperationids", "")
3360 );
3361
3362 LOCK2(cs_main, pwalletMain->cs_wallet);
3363
3364 std::string filter;
3365 bool useFilter = false;
3366 if (params.size()==1) {
3367 filter = params[0].get_str();
3368 useFilter = true;
3369 }
3370
3371 Array ret;
3372 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3373 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3374 for (auto id : ids) {
3375 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3376 if (!operation) {
3377 continue;
3378 }
3379 std::string state = operation->getStateAsString();
3380 if (useFilter && filter.compare(state)!=0)
3381 continue;
3382 ret.push_back(id);
3383 }
3384
3385 return ret;
3386}
3387
This page took 0.760772 seconds and 4 git commands to generate.