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