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