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