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