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.
13 #include "rpcserver.h"
16 #include "utilmoneystr.h"
19 #include "primitives/transaction.h"
20 #include "zcbenchmarks.h"
21 #include "script/interpreter.h"
24 #include "asyncrpcoperation.h"
25 #include "wallet/asyncrpcoperation_sendmany.h"
31 #include <boost/assign/list_of.hpp>
33 #include "json/json_spirit_utils.h"
34 #include "json/json_spirit_value.h"
35 #include "asyncrpcqueue.h"
38 using namespace json_spirit;
40 using namespace libzcash;
42 extern Array TxJoinSplitToJSON(const CTransaction& tx);
44 int64_t nWalletUnlockTime;
45 static CCriticalSection cs_nWalletUnlockTime;
48 Value z_getoperationstatus_IMPL(const Array&, bool);
50 std::string HelpRequiringPassphrase()
52 return pwalletMain && pwalletMain->IsCrypted()
53 ? "\nRequires wallet passphrase to be set with walletpassphrase call."
57 bool EnsureWalletIsAvailable(bool avoidException)
62 throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
69 void EnsureWalletIsUnlocked()
71 if (pwalletMain->IsLocked())
72 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
75 uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue);
76 uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
78 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
80 //int32_t i,n,txheight; uint32_t locktime; uint64_t interest = 0;
81 int confirms = wtx.GetDepthInMainChain();
82 entry.push_back(Pair("confirmations", confirms));
84 entry.push_back(Pair("generated", true));
87 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
88 entry.push_back(Pair("blockindex", wtx.nIndex));
89 entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
91 uint256 hash = wtx.GetHash();
92 entry.push_back(Pair("txid", hash.GetHex()));
93 //n = wtx.vout.size();
95 // interest += komodo_interest(mapBlockIndex[wtx.hashBlock]->nHeight,wtx.vout[i].nValue,wtx.nLockTime,mapBlockIndex[wtx.hashBlock]->nTime);
96 //entry.push_back(Pair("interest", interest));
99 BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
100 conflicts.push_back(conflict.GetHex());
101 entry.push_back(Pair("walletconflicts", conflicts));
102 entry.push_back(Pair("time", wtx.GetTxTime()));
103 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
104 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
105 entry.push_back(Pair(item.first, item.second));
107 entry.push_back(Pair("vjoinsplit", TxJoinSplitToJSON(wtx)));
110 string AccountFromValue(const Value& value)
112 string strAccount = value.get_str();
113 if (strAccount != "")
114 throw JSONRPCError(RPC_WALLET_ACCOUNTS_UNSUPPORTED, "Accounts are unsupported");
118 Value getnewaddress(const Array& params, bool fHelp)
120 if (!EnsureWalletIsAvailable(fHelp))
123 if (fHelp || params.size() > 1)
125 "getnewaddress ( \"account\" )\n"
126 "\nReturns a new Komodo address for receiving payments.\n"
128 "1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
130 "\"zcashaddress\" (string) The new zcash address\n"
132 + HelpExampleCli("getnewaddress", "")
133 + HelpExampleRpc("getnewaddress", "")
136 LOCK2(cs_main, pwalletMain->cs_wallet);
138 // Parse the account first so we don't generate a key if there's an error
140 if (params.size() > 0)
141 strAccount = AccountFromValue(params[0]);
143 if (!pwalletMain->IsLocked())
144 pwalletMain->TopUpKeyPool();
146 // Generate a new key that is added to wallet
148 if (!pwalletMain->GetKeyFromPool(newKey))
149 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
150 CKeyID keyID = newKey.GetID();
152 pwalletMain->SetAddressBook(keyID, strAccount, "receive");
154 return CBitcoinAddress(keyID).ToString();
158 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
160 CWalletDB walletdb(pwalletMain->strWalletFile);
163 walletdb.ReadAccount(strAccount, account);
165 bool bKeyUsed = false;
167 // Check if the current key has been used
168 if (account.vchPubKey.IsValid())
170 CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
171 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
172 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
175 const CWalletTx& wtx = (*it).second;
176 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
177 if (txout.scriptPubKey == scriptPubKey)
182 // Generate a new key
183 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
185 if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
186 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
188 pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
189 walletdb.WriteAccount(strAccount, account);
192 return CBitcoinAddress(account.vchPubKey.GetID());
195 Value getaccountaddress(const Array& params, bool fHelp)
197 if (!EnsureWalletIsAvailable(fHelp))
200 if (fHelp || params.size() != 1)
202 "getaccountaddress \"account\"\n"
203 "\nDEPRECATED. Returns the current Komodo address for receiving payments to this account.\n"
205 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
207 "\"zcashaddress\" (string) The account zcash address\n"
209 + HelpExampleCli("getaccountaddress", "")
210 + HelpExampleCli("getaccountaddress", "\"\"")
211 + HelpExampleCli("getaccountaddress", "\"myaccount\"")
212 + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
215 LOCK2(cs_main, pwalletMain->cs_wallet);
217 // Parse the account first so we don't generate a key if there's an error
218 string strAccount = AccountFromValue(params[0]);
222 ret = GetAccountAddress(strAccount).ToString();
227 Value getrawchangeaddress(const Array& params, bool fHelp)
229 if (!EnsureWalletIsAvailable(fHelp))
232 if (fHelp || params.size() > 1)
234 "getrawchangeaddress\n"
235 "\nReturns a new Komodo address, for receiving change.\n"
236 "This is for use with raw transactions, NOT normal use.\n"
238 "\"address\" (string) The address\n"
240 + HelpExampleCli("getrawchangeaddress", "")
241 + HelpExampleRpc("getrawchangeaddress", "")
244 LOCK2(cs_main, pwalletMain->cs_wallet);
246 if (!pwalletMain->IsLocked())
247 pwalletMain->TopUpKeyPool();
249 CReserveKey reservekey(pwalletMain);
251 if (!reservekey.GetReservedKey(vchPubKey))
252 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
254 reservekey.KeepKey();
256 CKeyID keyID = vchPubKey.GetID();
258 return CBitcoinAddress(keyID).ToString();
262 Value setaccount(const Array& params, bool fHelp)
264 if (!EnsureWalletIsAvailable(fHelp))
267 if (fHelp || params.size() < 1 || params.size() > 2)
269 "setaccount \"zcashaddress\" \"account\"\n"
270 "\nDEPRECATED. Sets the account associated with the given address.\n"
272 "1. \"zcashaddress\" (string, required) The zcash address to be associated with an account.\n"
273 "2. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
275 + HelpExampleCli("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"tabby\"")
276 + HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"tabby\"")
279 LOCK2(cs_main, pwalletMain->cs_wallet);
281 CBitcoinAddress address(params[0].get_str());
282 if (!address.IsValid())
283 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address");
286 if (params.size() > 1)
287 strAccount = AccountFromValue(params[1]);
289 // Only add the account if the address is yours.
290 if (IsMine(*pwalletMain, address.Get()))
292 // Detect when changing the account of an address that is the 'unused current key' of another account:
293 if (pwalletMain->mapAddressBook.count(address.Get()))
295 string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name;
296 if (address == GetAccountAddress(strOldAccount))
297 GetAccountAddress(strOldAccount, true);
299 pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
302 throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
308 Value getaccount(const Array& params, bool fHelp)
310 if (!EnsureWalletIsAvailable(fHelp))
313 if (fHelp || params.size() != 1)
315 "getaccount \"zcashaddress\"\n"
316 "\nDEPRECATED. Returns the account associated with the given address.\n"
318 "1. \"zcashaddress\" (string, required) The zcash address for account lookup.\n"
320 "\"accountname\" (string) the account address\n"
322 + HelpExampleCli("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
323 + HelpExampleRpc("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
326 LOCK2(cs_main, pwalletMain->cs_wallet);
328 CBitcoinAddress address(params[0].get_str());
329 if (!address.IsValid())
330 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address");
333 map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
334 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty())
335 strAccount = (*mi).second.name;
340 Value getaddressesbyaccount(const Array& params, bool fHelp)
342 if (!EnsureWalletIsAvailable(fHelp))
345 if (fHelp || params.size() != 1)
347 "getaddressesbyaccount \"account\"\n"
348 "\nDEPRECATED. Returns the list of addresses for the given account.\n"
350 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
352 "[ (json array of string)\n"
353 " \"zcashaddress\" (string) a zcash address associated with the given account\n"
357 + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
358 + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
361 LOCK2(cs_main, pwalletMain->cs_wallet);
363 string strAccount = AccountFromValue(params[0]);
365 // Find all addresses that have the given account
367 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
369 const CBitcoinAddress& address = item.first;
370 const string& strName = item.second.name;
371 if (strName == strAccount)
372 ret.push_back(address.ToString());
377 static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew,uint8_t *opretbuf,int32_t opretlen,long int opretValue)
379 CAmount curBalance = pwalletMain->GetBalance();
383 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
385 if (nValue > curBalance)
386 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
388 // Parse Zcash address
389 CScript scriptPubKey = GetScriptForDestination(address);
391 // Create and send the transaction
392 CReserveKey reservekey(pwalletMain);
393 CAmount nFeeRequired;
394 std::string strError;
395 vector<CRecipient> vecSend;
396 int nChangePosRet = -1;
397 CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
398 vecSend.push_back(recipient);
399 if ( opretlen > 0 && opretbuf != 0 )
401 CScript opretpubkey; int32_t i; uint8_t *ptr;
402 opretpubkey.resize(opretlen);
403 ptr = (uint8_t *)opretpubkey.data();
404 for (i=0; i<opretlen; i++)
406 ptr[i] = opretbuf[i];
407 //printf("%02x",ptr[i]);
409 //printf(" opretbuf[%d]\n",opretlen);
410 CRecipient opret = { opretpubkey, opretValue, false };
411 vecSend.push_back(opret);
413 if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
414 if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
415 strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired));
416 throw JSONRPCError(RPC_WALLET_ERROR, strError);
418 if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
419 throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
422 Value sendtoaddress(const Array& params, bool fHelp)
424 if (!EnsureWalletIsAvailable(fHelp))
427 if (fHelp || params.size() < 2 || params.size() > 5)
429 "sendtoaddress \"zcashaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
430 "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
431 + HelpRequiringPassphrase() +
433 "1. \"zcashaddress\" (string, required) The zcash address to send to.\n"
434 "2. \"amount\" (numeric, required) The amount in btc to send. eg 0.1\n"
435 "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
436 " This is not part of the transaction, just kept in your wallet.\n"
437 "4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
438 " to which you're sending the transaction. This is not part of the \n"
439 " transaction, just kept in your wallet.\n"
440 "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
441 " The recipient will receive less zcash than you enter in the amount field.\n"
443 "\"transactionid\" (string) The transaction id.\n"
445 + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
446 + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"donation\" \"seans outpost\"")
447 + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"\" \"\" true")
448 + HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
451 LOCK2(cs_main, pwalletMain->cs_wallet);
453 CBitcoinAddress address(params[0].get_str());
454 if (!address.IsValid())
455 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address");
458 CAmount nAmount = AmountFromValue(params[1]);
462 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
463 wtx.mapValue["comment"] = params[2].get_str();
464 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
465 wtx.mapValue["to"] = params[3].get_str();
467 bool fSubtractFeeFromAmount = false;
468 if (params.size() > 4)
469 fSubtractFeeFromAmount = params[4].get_bool();
471 EnsureWalletIsUnlocked();
473 SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, wtx,0,0,0);
475 return wtx.GetHash().GetHex();
478 #define KOMODO_KVPROTECTED 1
479 #define KOMODO_KVBINARY 2
480 #define KOMODO_KVDURATION 1440
481 #define IGUANA_MAXSCRIPTSIZE 10001
482 uint64_t PAX_fiatdest(uint64_t *seedp,int32_t tokomodo,char *destaddr,uint8_t pubkey37[37],char *coinaddr,int32_t height,char *base,int64_t fiatoshis);
483 int32_t komodo_opreturnscript(uint8_t *script,uint8_t type,uint8_t *opret,int32_t opretlen);
484 #define CRYPTO777_KMDADDR "RXL3YXG2ceaB6C5hfJcN4fvmLH2C34knhA"
485 extern char ASSETCHAINS_SYMBOL[16];
486 int32_t komodo_is_issuer();
487 int32_t iguana_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp);
488 int32_t komodo_isrealtime(int32_t *kmdheightp);
489 int32_t pax_fiatstatus(uint64_t *available,uint64_t *deposited,uint64_t *issued,uint64_t *withdrawn,uint64_t *approved,uint64_t *redeemed,char *base);
490 int32_t komodo_kvsearch(uint256 *refpubkeyp,int32_t current_height,uint32_t *flagsp,int32_t *heightp,uint8_t value[IGUANA_MAXSCRIPTSIZE],uint8_t *key,int32_t keylen);
491 int32_t komodo_kvcmp(uint8_t *refvalue,uint16_t refvaluesize,uint8_t *value,uint16_t valuesize);
492 uint64_t komodo_kvfee(uint32_t flags,int32_t opretlen,int32_t keylen);
493 uint256 komodo_kvsig(uint8_t *buf,int32_t len,uint256 privkey);
494 int32_t komodo_kvduration(uint32_t flags);
495 uint256 komodo_kvprivkey(uint256 *pubkeyp,char *passphrase);
497 Value paxdeposit(const Array& params, bool fHelp)
499 uint64_t available,deposited,issued,withdrawn,approved,redeemed,seed,komodoshis = 0; int32_t height; char destaddr[64]; uint8_t i,pubkey37[33];
500 bool fSubtractFeeFromAmount = false;
501 if ( komodo_is_issuer() != 0 )
502 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "paxdeposit only from KMD");
503 if (!EnsureWalletIsAvailable(fHelp))
505 if (fHelp || params.size() != 3)
506 throw runtime_error("paxdeposit address fiatoshis base");
507 LOCK2(cs_main, pwalletMain->cs_wallet);
508 CBitcoinAddress address(params[0].get_str());
509 if (!address.IsValid())
510 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
511 int64_t fiatoshis = atof(params[1].get_str().c_str()) * COIN;
512 std::string base = params[2].get_str();
514 height = chainActive.Tip()->nHeight;
515 if ( pax_fiatstatus(&available,&deposited,&issued,&withdrawn,&approved,&redeemed,(char *)base.c_str()) != 0 || available < fiatoshis )
516 throw runtime_error("paxdeposit not enough available inventory");
517 komodoshis = PAX_fiatdest(&seed,0,destaddr,pubkey37,(char *)params[0].get_str().c_str(),height,(char *)base.c_str(),fiatoshis);
518 dest.append(destaddr);
519 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
520 if (!destaddress.IsValid())
521 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
523 fprintf(stderr,"%02x",pubkey37[i]);
524 fprintf(stderr," ht.%d srcaddr.(%s) %s fiatoshis.%lld -> dest.(%s) komodoshis.%llu seed.%llx\n",height,(char *)params[0].get_str().c_str(),(char *)base.c_str(),(long long)fiatoshis,destaddr,(long long)komodoshis,(long long)seed);
525 EnsureWalletIsUnlocked();
527 uint8_t opretbuf[64]; int32_t opretlen; uint64_t fee = komodoshis / 1000;
530 iguana_rwnum(1,&pubkey37[33],sizeof(height),&height);
531 opretlen = komodo_opreturnscript(opretbuf,'D',pubkey37,37);
532 SendMoney(address.Get(),fee,fSubtractFeeFromAmount,wtx,opretbuf,opretlen,komodoshis);
533 return wtx.GetHash().GetHex();
536 Value paxwithdraw(const Array& params, bool fHelp)
538 CWalletTx wtx; std::string dest; int32_t kmdheight; uint64_t seed,komodoshis = 0; char destaddr[64]; uint8_t i,pubkey37[37]; bool fSubtractFeeFromAmount = false;
539 if ( ASSETCHAINS_SYMBOL[0] == 0 )
541 if (!EnsureWalletIsAvailable(fHelp))
543 if (fHelp || params.size() != 2)
544 throw runtime_error("paxwithdraw address fiatamount");
545 if ( komodo_isrealtime(&kmdheight) == 0 )
547 LOCK2(cs_main, pwalletMain->cs_wallet);
548 CBitcoinAddress address(params[0].get_str());
549 if (!address.IsValid())
550 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
551 int64_t fiatoshis = atof(params[1].get_str().c_str()) * COIN;
552 komodoshis = PAX_fiatdest(&seed,1,destaddr,pubkey37,(char *)params[0].get_str().c_str(),kmdheight,ASSETCHAINS_SYMBOL,fiatoshis);
553 dest.append(destaddr);
554 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
555 if (!destaddress.IsValid())
556 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
558 printf("%02x",pubkey37[i]);
559 printf(" kmdheight.%d srcaddr.(%s) %s fiatoshis.%lld -> dest.(%s) komodoshis.%llu seed.%llx\n",kmdheight,(char *)params[0].get_str().c_str(),ASSETCHAINS_SYMBOL,(long long)fiatoshis,destaddr,(long long)komodoshis,(long long)seed);
560 EnsureWalletIsUnlocked();
561 uint8_t opretbuf[64]; int32_t opretlen; uint64_t fee = fiatoshis / 1000;
564 iguana_rwnum(1,&pubkey37[33],sizeof(kmdheight),&kmdheight);
565 opretlen = komodo_opreturnscript(opretbuf,'W',pubkey37,37);
566 SendMoney(destaddress.Get(),fee,fSubtractFeeFromAmount,wtx,opretbuf,opretlen,fiatoshis);
567 return wtx.GetHash().GetHex();
570 Value kvupdate(const Array& params, bool fHelp)
572 static uint256 zeroes;
573 CWalletTx wtx; Object ret;
574 uint8_t keyvalue[IGUANA_MAXSCRIPTSIZE],opretbuf[IGUANA_MAXSCRIPTSIZE]; int32_t i,coresize,haveprivkey,duration,opretlen,height; uint16_t keylen,valuesize=0,refvaluesize=0; uint8_t *key,*value=0; uint32_t flags,tmpflags; struct komodo_kv *ptr; uint64_t fee; uint256 privkey,pubkey,refpubkey,sig;
575 if (fHelp || params.size() < 2 )
576 throw runtime_error("kvupdate key value [flags] [passphrase]");
577 if (!EnsureWalletIsAvailable(fHelp))
579 if ( params.size() >= 3 )
581 flags = atoi(params[2].get_str().c_str());
582 //printf("flags.%d (%s)\n",flags,params[2].get_str().c_str());
585 memset(&sig,0,sizeof(sig));
586 memset(&privkey,0,sizeof(privkey));
587 memset(&pubkey,0,sizeof(pubkey));
588 if ( params.size() >= 4 )
590 privkey = komodo_kvprivkey(&pubkey,(char *)params[3].get_str().c_str());
593 printf("have privkey derived from (%s)\n",(char *)params[3].get_str().c_str());
594 //printf("flags.%d (%s)\n",flags,params[2].get_str().c_str());
596 printf("params.%d flags.%d haveprivkey.%d (%s %s)\n",(int32_t)params.size(),flags,haveprivkey,(char *)params[1].get_str().c_str(),(char *)params[3].get_str().c_str());
597 LOCK2(cs_main, pwalletMain->cs_wallet);
598 if ( (keylen= (int32_t)strlen(params[0].get_str().c_str())) > 0 )
600 key = (uint8_t *)params[0].get_str().c_str();
601 if ( params.size() >= 2 && params[1].get_str().c_str() != 0 )
603 value = (uint8_t *)params[1].get_str().c_str();
604 valuesize = (int32_t)strlen(params[1].get_str().c_str());
606 memcpy(keyvalue,key,keylen);
607 if ( (refvaluesize= komodo_kvsearch(&refpubkey,chainActive.Tip()->nHeight,&tmpflags,&height,&keyvalue[keylen],key,keylen)) >= 0 )
609 if ( (tmpflags & KOMODO_KVPROTECTED) != 0 )
611 if ( refpubkey != pubkey )
613 ret.push_back(Pair("error",(char *)"cant modify write once key without passphrase"));
616 printf("calc sig for keylen.%d + valuesize.%d\n",keylen,valuesize);
617 sig = komodo_kvsig(keyvalue,keylen+valuesize,privkey);
620 ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)));
621 height = chainActive.Tip()->nHeight;
622 if ( memcmp(&zeroes,&refpubkey,sizeof(refpubkey)) != 0 )
623 ret.push_back(Pair("owner",refpubkey.GetHex()));
624 ret.push_back(Pair("height", (int64_t)height));
625 duration = komodo_kvduration(flags); //((flags >> 2) + 1) * KOMODO_KVDURATION;
626 ret.push_back(Pair("expiration", (int64_t)(height+duration)));
627 ret.push_back(Pair("flags",(int64_t)flags));
628 ret.push_back(Pair("key",params[0].get_str()));
629 ret.push_back(Pair("keylen",(int64_t)keylen));
630 if ( params.size() >= 2 && params[1].get_str().c_str() != 0 )
632 ret.push_back(Pair("value",params[1].get_str()));
633 ret.push_back(Pair("valuesize",valuesize));
635 iguana_rwnum(1,&keyvalue[0],sizeof(keylen),&keylen);
636 iguana_rwnum(1,&keyvalue[2],sizeof(valuesize),&valuesize);
637 iguana_rwnum(1,&keyvalue[4],sizeof(height),&height);
638 iguana_rwnum(1,&keyvalue[8],sizeof(flags),&flags);
639 memcpy(&keyvalue[12],key,keylen);
641 memcpy(&keyvalue[12 + keylen],value,valuesize);
642 coresize = (int32_t)(sizeof(flags)+sizeof(height)+sizeof(uint16_t)*2+keylen+valuesize);
643 if ( haveprivkey != 0 )
646 keyvalue[12 + keylen + valuesize + i] = ((uint8_t *)&pubkey)[i];
648 if ( refvaluesize >=0 )
651 keyvalue[12 + keylen + valuesize + 32 + i] = ((uint8_t *)&sig)[i];
655 if ( (opretlen= komodo_opreturnscript(opretbuf,'K',keyvalue,coresize)) == 40 )
657 //for (i=0; i<opretlen; i++)
658 // printf("%02x",opretbuf[i]);
659 //printf(" opretbuf keylen.%d valuesize.%d height.%d (%02x %02x %02x)\n",*(uint16_t *)&keyvalue[0],*(uint16_t *)&keyvalue[2],*(uint32_t *)&keyvalue[4],keyvalue[8],keyvalue[9],keyvalue[10]);
660 EnsureWalletIsUnlocked();
661 fee = komodo_kvfee(flags,opretlen,keylen);
662 ret.push_back(Pair("fee",(double)fee/COIN));
663 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
664 if (!destaddress.IsValid())
665 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
666 SendMoney(destaddress.Get(),10000,false,wtx,opretbuf,opretlen,fee);
667 ret.push_back(Pair("txid",wtx.GetHash().GetHex()));
668 } else ret.push_back(Pair("error",(char *)"null key"));
672 Value listaddressgroupings(const Array& params, bool fHelp)
674 if (!EnsureWalletIsAvailable(fHelp))
679 "listaddressgroupings\n"
680 "\nLists groups of addresses which have had their common ownership\n"
681 "made public by common use as inputs or as the resulting change\n"
682 "in past transactions\n"
687 " \"zcashaddress\", (string) The zcash address\n"
688 " amount, (numeric) The amount in btc\n"
689 " \"account\" (string, optional) The account (DEPRECATED)\n"
696 + HelpExampleCli("listaddressgroupings", "")
697 + HelpExampleRpc("listaddressgroupings", "")
700 LOCK2(cs_main, pwalletMain->cs_wallet);
703 map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
704 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
707 BOOST_FOREACH(CTxDestination address, grouping)
710 addressInfo.push_back(CBitcoinAddress(address).ToString());
711 addressInfo.push_back(ValueFromAmount(balances[address]));
713 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
714 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
716 jsonGrouping.push_back(addressInfo);
718 jsonGroupings.push_back(jsonGrouping);
720 return jsonGroupings;
723 Value signmessage(const Array& params, bool fHelp)
725 if (!EnsureWalletIsAvailable(fHelp))
728 if (fHelp || params.size() != 2)
730 "signmessage \"zcashaddress\" \"message\"\n"
731 "\nSign a message with the private key of an address"
732 + HelpRequiringPassphrase() + "\n"
734 "1. \"zcashaddress\" (string, required) The zcash address to use for the private key.\n"
735 "2. \"message\" (string, required) The message to create a signature of.\n"
737 "\"signature\" (string) The signature of the message encoded in base 64\n"
739 "\nUnlock the wallet for 30 seconds\n"
740 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
741 "\nCreate the signature\n"
742 + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
743 "\nVerify the signature\n"
744 + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
746 + HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"my message\"")
749 LOCK2(cs_main, pwalletMain->cs_wallet);
751 EnsureWalletIsUnlocked();
753 string strAddress = params[0].get_str();
754 string strMessage = params[1].get_str();
756 CBitcoinAddress addr(strAddress);
758 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
761 if (!addr.GetKeyID(keyID))
762 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
765 if (!pwalletMain->GetKey(keyID, key))
766 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
768 CHashWriter ss(SER_GETHASH, 0);
769 ss << strMessageMagic;
772 vector<unsigned char> vchSig;
773 if (!key.SignCompact(ss.GetHash(), vchSig))
774 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
776 return EncodeBase64(&vchSig[0], vchSig.size());
779 Value getreceivedbyaddress(const Array& params, bool fHelp)
781 if (!EnsureWalletIsAvailable(fHelp))
784 if (fHelp || params.size() < 1 || params.size() > 2)
786 "getreceivedbyaddress \"zcashaddress\" ( minconf )\n"
787 "\nReturns the total amount received by the given zcashaddress in transactions with at least minconf confirmations.\n"
789 "1. \"zcashaddress\" (string, required) The zcash address for transactions.\n"
790 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
792 "amount (numeric) The total amount in btc received at this address.\n"
794 "\nThe amount from transactions with at least 1 confirmation\n"
795 + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"") +
796 "\nThe amount including unconfirmed transactions, zero confirmations\n"
797 + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" 0") +
798 "\nThe amount with at least 6 confirmation, very safe\n"
799 + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" 6") +
800 "\nAs a json rpc call\n"
801 + HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", 6")
804 LOCK2(cs_main, pwalletMain->cs_wallet);
807 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
808 if (!address.IsValid())
809 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address");
810 CScript scriptPubKey = GetScriptForDestination(address.Get());
811 if (!IsMine(*pwalletMain,scriptPubKey))
814 // Minimum confirmations
816 if (params.size() > 1)
817 nMinDepth = params[1].get_int();
821 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
823 const CWalletTx& wtx = (*it).second;
824 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
827 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
828 if (txout.scriptPubKey == scriptPubKey)
829 if (wtx.GetDepthInMainChain() >= nMinDepth)
830 nAmount += txout.nValue; // komodo_interest?
833 return ValueFromAmount(nAmount);
837 Value getreceivedbyaccount(const Array& params, bool fHelp)
839 if (!EnsureWalletIsAvailable(fHelp))
842 if (fHelp || params.size() < 1 || params.size() > 2)
844 "getreceivedbyaccount \"account\" ( minconf )\n"
845 "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
847 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
848 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
850 "amount (numeric) The total amount in btc received for this account.\n"
852 "\nAmount received by the default account with at least 1 confirmation\n"
853 + HelpExampleCli("getreceivedbyaccount", "\"\"") +
854 "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
855 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
856 "\nThe amount with at least 6 confirmation, very safe\n"
857 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
858 "\nAs a json rpc call\n"
859 + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
862 LOCK2(cs_main, pwalletMain->cs_wallet);
864 // Minimum confirmations
866 if (params.size() > 1)
867 nMinDepth = params[1].get_int();
869 // Get the set of pub keys assigned to account
870 string strAccount = AccountFromValue(params[0]);
871 set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
875 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
877 const CWalletTx& wtx = (*it).second;
878 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
881 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
883 CTxDestination address;
884 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
885 if (wtx.GetDepthInMainChain() >= nMinDepth)
886 nAmount += txout.nValue; // komodo_interest?
890 return (double)nAmount / (double)COIN;
894 CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
896 CAmount nBalance = 0;
898 // Tally wallet transactions
899 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
901 const CWalletTx& wtx = (*it).second;
902 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
905 CAmount nReceived, nSent, nFee;
906 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
908 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
909 nBalance += nReceived;
910 nBalance -= nSent + nFee;
913 // Tally internal accounting entries
914 nBalance += walletdb.GetAccountCreditDebit(strAccount);
919 CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
921 CWalletDB walletdb(pwalletMain->strWalletFile);
922 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
926 Value getbalance(const Array& params, bool fHelp)
928 if (!EnsureWalletIsAvailable(fHelp))
931 if (fHelp || params.size() > 3)
933 "getbalance ( \"account\" minconf includeWatchonly )\n"
934 "\nReturns the server's total available balance.\n"
936 "1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" or to the string \"*\", either of which will give the total available balance. Passing any other string will result in an error.\n"
937 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
938 "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
940 "amount (numeric) The total amount in btc received for this account.\n"
942 "\nThe total amount in the wallet\n"
943 + HelpExampleCli("getbalance", "") +
944 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
945 + HelpExampleCli("getbalance", "\"*\" 6") +
946 "\nAs a json rpc call\n"
947 + HelpExampleRpc("getbalance", "\"*\", 6")
950 LOCK2(cs_main, pwalletMain->cs_wallet);
952 if (params.size() == 0)
953 return ValueFromAmount(pwalletMain->GetBalance());
956 if (params.size() > 1)
957 nMinDepth = params[1].get_int();
958 isminefilter filter = ISMINE_SPENDABLE;
959 if(params.size() > 2)
960 if(params[2].get_bool())
961 filter = filter | ISMINE_WATCH_ONLY;
963 if (params[0].get_str() == "*") {
964 // Calculate total balance a different way from GetBalance()
965 // (GetBalance() sums up all unspent TxOuts)
966 // getbalance and "getbalance * 1 true" should return the same number
967 CAmount nBalance = 0;
968 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
970 const CWalletTx& wtx = (*it).second;
971 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
975 string strSentAccount;
976 list<COutputEntry> listReceived;
977 list<COutputEntry> listSent;
978 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
979 if (wtx.GetDepthInMainChain() >= nMinDepth)
981 BOOST_FOREACH(const COutputEntry& r, listReceived)
982 nBalance += r.amount;
984 BOOST_FOREACH(const COutputEntry& s, listSent)
985 nBalance -= s.amount;
988 return ValueFromAmount(nBalance);
991 string strAccount = AccountFromValue(params[0]);
993 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
995 return ValueFromAmount(nBalance);
998 Value getunconfirmedbalance(const Array ¶ms, bool fHelp)
1000 if (!EnsureWalletIsAvailable(fHelp))
1003 if (fHelp || params.size() > 0)
1004 throw runtime_error(
1005 "getunconfirmedbalance\n"
1006 "Returns the server's total unconfirmed balance\n");
1008 LOCK2(cs_main, pwalletMain->cs_wallet);
1010 return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
1014 Value movecmd(const Array& params, bool fHelp)
1016 if (!EnsureWalletIsAvailable(fHelp))
1019 if (fHelp || params.size() < 3 || params.size() > 5)
1020 throw runtime_error(
1021 "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
1022 "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
1024 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1025 "2. \"toaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1026 "3. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
1027 "4. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
1029 "true|false (boolean) true if successful.\n"
1031 "\nMove 0.01 btc from the default account to the account named tabby\n"
1032 + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
1033 "\nMove 0.01 btc timotei to akiko with a comment and funds have 6 confirmations\n"
1034 + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
1035 "\nAs a json rpc call\n"
1036 + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
1039 LOCK2(cs_main, pwalletMain->cs_wallet);
1041 string strFrom = AccountFromValue(params[0]);
1042 string strTo = AccountFromValue(params[1]);
1043 CAmount nAmount = AmountFromValue(params[2]);
1044 if (params.size() > 3)
1045 // unused parameter, used to be nMinDepth, keep type-checking it though
1046 (void)params[3].get_int();
1048 if (params.size() > 4)
1049 strComment = params[4].get_str();
1051 CWalletDB walletdb(pwalletMain->strWalletFile);
1052 if (!walletdb.TxnBegin())
1053 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
1055 int64_t nNow = GetAdjustedTime();
1058 CAccountingEntry debit;
1059 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
1060 debit.strAccount = strFrom;
1061 debit.nCreditDebit = -nAmount;
1063 debit.strOtherAccount = strTo;
1064 debit.strComment = strComment;
1065 walletdb.WriteAccountingEntry(debit);
1068 CAccountingEntry credit;
1069 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
1070 credit.strAccount = strTo;
1071 credit.nCreditDebit = nAmount;
1072 credit.nTime = nNow;
1073 credit.strOtherAccount = strFrom;
1074 credit.strComment = strComment;
1075 walletdb.WriteAccountingEntry(credit);
1077 if (!walletdb.TxnCommit())
1078 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
1084 Value sendfrom(const Array& params, bool fHelp)
1086 if (!EnsureWalletIsAvailable(fHelp))
1089 if (fHelp || params.size() < 3 || params.size() > 6)
1090 throw runtime_error(
1091 "sendfrom \"fromaccount\" \"tozcashaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
1092 "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a zcash address.\n"
1093 "The amount is a real and is rounded to the nearest 0.00000001."
1094 + HelpRequiringPassphrase() + "\n"
1096 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1097 "2. \"tozcashaddress\" (string, required) The zcash address to send funds to.\n"
1098 "3. amount (numeric, required) The amount in btc. (transaction fee is added on top).\n"
1099 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
1100 "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
1101 " This is not part of the transaction, just kept in your wallet.\n"
1102 "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n"
1103 " to which you're sending the transaction. This is not part of the transaction, \n"
1104 " it is just kept in your wallet.\n"
1106 "\"transactionid\" (string) The transaction id.\n"
1108 "\nSend 0.01 btc from the default account to the address, must have at least 1 confirmation\n"
1109 + HelpExampleCli("sendfrom", "\"\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
1110 "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
1111 + HelpExampleCli("sendfrom", "\"tabby\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01 6 \"donation\" \"seans outpost\"") +
1112 "\nAs a json rpc call\n"
1113 + HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
1116 LOCK2(cs_main, pwalletMain->cs_wallet);
1118 string strAccount = AccountFromValue(params[0]);
1119 CBitcoinAddress address(params[1].get_str());
1120 if (!address.IsValid())
1121 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address");
1122 CAmount nAmount = AmountFromValue(params[2]);
1124 if (params.size() > 3)
1125 nMinDepth = params[3].get_int();
1128 wtx.strFromAccount = strAccount;
1129 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
1130 wtx.mapValue["comment"] = params[4].get_str();
1131 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
1132 wtx.mapValue["to"] = params[5].get_str();
1134 EnsureWalletIsUnlocked();
1137 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
1138 if (nAmount > nBalance)
1139 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
1141 SendMoney(address.Get(), nAmount, false, wtx,0,0,0);
1143 return wtx.GetHash().GetHex();
1147 Value sendmany(const Array& params, bool fHelp)
1149 if (!EnsureWalletIsAvailable(fHelp))
1152 if (fHelp || params.size() < 2 || params.size() > 5)
1153 throw runtime_error(
1154 "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
1155 "\nSend multiple times. Amounts are double-precision floating point numbers."
1156 + HelpRequiringPassphrase() + "\n"
1158 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1159 "2. \"amounts\" (string, required) A json object with addresses and amounts\n"
1161 " \"address\":amount (numeric) The zcash address is the key, the numeric amount in btc is the value\n"
1164 "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
1165 "4. \"comment\" (string, optional) A comment\n"
1166 "5. subtractfeefromamount (string, optional) A json array with addresses.\n"
1167 " The fee will be equally deducted from the amount of each selected address.\n"
1168 " Those recipients will receive less zcashs than you enter in their corresponding amount field.\n"
1169 " If no addresses are specified here, the sender pays the fee.\n"
1171 " \"address\" (string) Subtract fee from this address\n"
1175 "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
1176 " the number of addresses.\n"
1178 "\nSend two amounts to two different addresses:\n"
1179 + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
1180 "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
1181 + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
1182 "\nSend two amounts to two different addresses, subtract fee from amount:\n"
1183 + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\",\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
1184 "\nAs a json rpc call\n"
1185 + HelpExampleRpc("sendmany", "\"\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
1188 LOCK2(cs_main, pwalletMain->cs_wallet);
1190 string strAccount = AccountFromValue(params[0]);
1191 Object sendTo = params[1].get_obj();
1193 if (params.size() > 2)
1194 nMinDepth = params[2].get_int();
1197 wtx.strFromAccount = strAccount;
1198 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
1199 wtx.mapValue["comment"] = params[3].get_str();
1201 Array subtractFeeFromAmount;
1202 if (params.size() > 4)
1203 subtractFeeFromAmount = params[4].get_array();
1205 set<CBitcoinAddress> setAddress;
1206 vector<CRecipient> vecSend;
1208 CAmount totalAmount = 0;
1209 BOOST_FOREACH(const Pair& s, sendTo)
1211 CBitcoinAddress address(s.name_);
1212 if (!address.IsValid())
1213 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Komodo address: ")+s.name_);
1215 if (setAddress.count(address))
1216 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
1217 setAddress.insert(address);
1219 CScript scriptPubKey = GetScriptForDestination(address.Get());
1220 CAmount nAmount = AmountFromValue(s.value_);
1221 totalAmount += nAmount;
1223 bool fSubtractFeeFromAmount = false;
1224 BOOST_FOREACH(const Value& addr, subtractFeeFromAmount)
1225 if (addr.get_str() == s.name_)
1226 fSubtractFeeFromAmount = true;
1228 CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
1229 vecSend.push_back(recipient);
1232 EnsureWalletIsUnlocked();
1235 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
1236 if (totalAmount > nBalance)
1237 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
1240 CReserveKey keyChange(pwalletMain);
1241 CAmount nFeeRequired = 0;
1242 int nChangePosRet = -1;
1243 string strFailReason;
1244 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
1246 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
1247 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1248 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
1250 return wtx.GetHash().GetHex();
1253 // Defined in rpcmisc.cpp
1254 extern CScript _createmultisig_redeemScript(const Array& params);
1256 Value addmultisigaddress(const Array& params, bool fHelp)
1258 if (!EnsureWalletIsAvailable(fHelp))
1261 if (fHelp || params.size() < 2 || params.size() > 3)
1263 string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
1264 "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
1265 "Each key is a Komodo address or hex-encoded public key.\n"
1266 "If 'account' is specified (DEPRECATED), assign address to that account.\n"
1269 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
1270 "2. \"keysobject\" (string, required) A json array of zcash addresses or hex-encoded public keys\n"
1272 " \"address\" (string) zcash address or hex-encoded public key\n"
1275 "3. \"account\" (string, optional) DEPRECATED. If provided, MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1278 "\"zcashaddress\" (string) A zcash address associated with the keys.\n"
1281 "\nAdd a multisig address from 2 addresses\n"
1282 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
1283 "\nAs json rpc call\n"
1284 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
1286 throw runtime_error(msg);
1289 LOCK2(cs_main, pwalletMain->cs_wallet);
1292 if (params.size() > 2)
1293 strAccount = AccountFromValue(params[2]);
1295 // Construct using pay-to-script-hash:
1296 CScript inner = _createmultisig_redeemScript(params);
1297 CScriptID innerID(inner);
1298 pwalletMain->AddCScript(inner);
1300 pwalletMain->SetAddressBook(innerID, strAccount, "send");
1301 return CBitcoinAddress(innerID).ToString();
1309 vector<uint256> txids;
1314 nConf = std::numeric_limits<int>::max();
1315 fIsWatchonly = false;
1319 Value ListReceived(const Array& params, bool fByAccounts)
1321 // Minimum confirmations
1323 if (params.size() > 0)
1324 nMinDepth = params[0].get_int();
1326 // Whether to include empty accounts
1327 bool fIncludeEmpty = false;
1328 if (params.size() > 1)
1329 fIncludeEmpty = params[1].get_bool();
1331 isminefilter filter = ISMINE_SPENDABLE;
1332 if(params.size() > 2)
1333 if(params[2].get_bool())
1334 filter = filter | ISMINE_WATCH_ONLY;
1337 map<CBitcoinAddress, tallyitem> mapTally;
1338 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1340 const CWalletTx& wtx = (*it).second;
1342 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
1345 int nDepth = wtx.GetDepthInMainChain();
1346 if (nDepth < nMinDepth)
1349 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1351 CTxDestination address;
1352 if (!ExtractDestination(txout.scriptPubKey, address))
1355 isminefilter mine = IsMine(*pwalletMain, address);
1356 if(!(mine & filter))
1359 tallyitem& item = mapTally[address];
1360 item.nAmount += txout.nValue; // komodo_interest?
1361 item.nConf = min(item.nConf, nDepth);
1362 item.txids.push_back(wtx.GetHash());
1363 if (mine & ISMINE_WATCH_ONLY)
1364 item.fIsWatchonly = true;
1370 map<string, tallyitem> mapAccountTally;
1371 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
1373 const CBitcoinAddress& address = item.first;
1374 const string& strAccount = item.second.name;
1375 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1376 if (it == mapTally.end() && !fIncludeEmpty)
1379 CAmount nAmount = 0;
1380 int nConf = std::numeric_limits<int>::max();
1381 bool fIsWatchonly = false;
1382 if (it != mapTally.end())
1384 nAmount = (*it).second.nAmount;
1385 nConf = (*it).second.nConf;
1386 fIsWatchonly = (*it).second.fIsWatchonly;
1391 tallyitem& item = mapAccountTally[strAccount];
1392 item.nAmount += nAmount;
1393 item.nConf = min(item.nConf, nConf);
1394 item.fIsWatchonly = fIsWatchonly;
1400 obj.push_back(Pair("involvesWatchonly", true));
1401 obj.push_back(Pair("address", address.ToString()));
1402 obj.push_back(Pair("account", strAccount));
1403 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1404 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1406 if (it != mapTally.end())
1408 BOOST_FOREACH(const uint256& item, (*it).second.txids)
1410 transactions.push_back(item.GetHex());
1413 obj.push_back(Pair("txids", transactions));
1420 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1422 CAmount nAmount = (*it).second.nAmount;
1423 int nConf = (*it).second.nConf;
1425 if((*it).second.fIsWatchonly)
1426 obj.push_back(Pair("involvesWatchonly", true));
1427 obj.push_back(Pair("account", (*it).first));
1428 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1429 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1437 Value listreceivedbyaddress(const Array& params, bool fHelp)
1439 if (!EnsureWalletIsAvailable(fHelp))
1442 if (fHelp || params.size() > 3)
1443 throw runtime_error(
1444 "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
1445 "\nList balances by receiving address.\n"
1447 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1448 "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n"
1449 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1454 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
1455 " \"address\" : \"receivingaddress\", (string) The receiving address\n"
1456 " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
1457 " \"amount\" : x.xxx, (numeric) The total amount in btc received by the address\n"
1458 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1464 + HelpExampleCli("listreceivedbyaddress", "")
1465 + HelpExampleCli("listreceivedbyaddress", "6 true")
1466 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
1469 LOCK2(cs_main, pwalletMain->cs_wallet);
1471 return ListReceived(params, false);
1474 Value listreceivedbyaccount(const Array& params, bool fHelp)
1476 if (!EnsureWalletIsAvailable(fHelp))
1479 if (fHelp || params.size() > 3)
1480 throw runtime_error(
1481 "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
1482 "\nDEPRECATED. List balances by account.\n"
1484 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1485 "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
1486 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1491 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
1492 " \"account\" : \"accountname\", (string) The account name of the receiving account\n"
1493 " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
1494 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1500 + HelpExampleCli("listreceivedbyaccount", "")
1501 + HelpExampleCli("listreceivedbyaccount", "6 true")
1502 + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
1505 LOCK2(cs_main, pwalletMain->cs_wallet);
1507 return ListReceived(params, true);
1510 static void MaybePushAddress(Object & entry, const CTxDestination &dest)
1512 CBitcoinAddress addr;
1514 entry.push_back(Pair("address", addr.ToString()));
1517 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
1520 string strSentAccount;
1521 list<COutputEntry> listReceived;
1522 list<COutputEntry> listSent;
1524 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
1526 bool fAllAccounts = (strAccount == string("*"));
1527 bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
1530 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1532 BOOST_FOREACH(const COutputEntry& s, listSent)
1535 if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
1536 entry.push_back(Pair("involvesWatchonly", true));
1537 entry.push_back(Pair("account", strSentAccount));
1538 MaybePushAddress(entry, s.destination);
1539 entry.push_back(Pair("category", "send"));
1540 entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
1541 entry.push_back(Pair("vout", s.vout));
1542 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1544 WalletTxToJSON(wtx, entry);
1545 ret.push_back(entry);
1550 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1552 BOOST_FOREACH(const COutputEntry& r, listReceived)
1555 if (pwalletMain->mapAddressBook.count(r.destination))
1556 account = pwalletMain->mapAddressBook[r.destination].name;
1557 if (fAllAccounts || (account == strAccount))
1560 if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
1561 entry.push_back(Pair("involvesWatchonly", true));
1562 entry.push_back(Pair("account", account));
1563 MaybePushAddress(entry, r.destination);
1564 if (wtx.IsCoinBase())
1566 if (wtx.GetDepthInMainChain() < 1)
1567 entry.push_back(Pair("category", "orphan"));
1568 else if (wtx.GetBlocksToMaturity() > 0)
1569 entry.push_back(Pair("category", "immature"));
1571 entry.push_back(Pair("category", "generate"));
1575 entry.push_back(Pair("category", "receive"));
1577 entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
1578 entry.push_back(Pair("vout", r.vout));
1580 WalletTxToJSON(wtx, entry);
1581 ret.push_back(entry);
1587 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1589 bool fAllAccounts = (strAccount == string("*"));
1591 if (fAllAccounts || acentry.strAccount == strAccount)
1594 entry.push_back(Pair("account", acentry.strAccount));
1595 entry.push_back(Pair("category", "move"));
1596 entry.push_back(Pair("time", acentry.nTime));
1597 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1598 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1599 entry.push_back(Pair("comment", acentry.strComment));
1600 ret.push_back(entry);
1604 Value listtransactions(const Array& params, bool fHelp)
1606 if (!EnsureWalletIsAvailable(fHelp))
1609 if (fHelp || params.size() > 4)
1610 throw runtime_error(
1611 "listtransactions ( \"account\" count from includeWatchonly)\n"
1612 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
1614 "1. \"account\" (string, optional) DEPRECATED. The account name. Should be \"*\".\n"
1615 "2. count (numeric, optional, default=10) The number of transactions to return\n"
1616 "3. from (numeric, optional, default=0) The number of transactions to skip\n"
1617 "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
1621 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n"
1622 " It will be \"\" for the default account.\n"
1623 " \"address\":\"zcashaddress\", (string) The zcash address of the transaction. Not present for \n"
1624 " move transactions (category = move).\n"
1625 " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
1626 " transaction between accounts, and not associated with an address,\n"
1627 " transaction id or block. 'send' and 'receive' transactions are \n"
1628 " associated with an address, transaction id and block details\n"
1629 " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the\n"
1630 " 'move' category for moves outbound. It is positive for the 'receive' category,\n"
1631 " and for the 'move' category for inbound funds.\n"
1632 " \"vout\" : n, (numeric) the vout value\n"
1633 " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the \n"
1634 " 'send' category of transactions.\n"
1635 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
1636 " 'receive' category of transactions.\n"
1637 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
1638 " category of transactions.\n"
1639 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
1640 " category of transactions.\n"
1641 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1642 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1643 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
1644 " for 'send' and 'receive' category of transactions.\n"
1645 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1646 " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
1647 " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
1648 " negative amounts).\n"
1653 "\nList the most recent 10 transactions in the systems\n"
1654 + HelpExampleCli("listtransactions", "") +
1655 "\nList transactions 100 to 120\n"
1656 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
1657 "\nAs a json rpc call\n"
1658 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
1661 LOCK2(cs_main, pwalletMain->cs_wallet);
1663 string strAccount = "*";
1664 if (params.size() > 0)
1665 strAccount = params[0].get_str();
1667 if (params.size() > 1)
1668 nCount = params[1].get_int();
1670 if (params.size() > 2)
1671 nFrom = params[2].get_int();
1672 isminefilter filter = ISMINE_SPENDABLE;
1673 if(params.size() > 3)
1674 if(params[3].get_bool())
1675 filter = filter | ISMINE_WATCH_ONLY;
1678 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1680 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1684 std::list<CAccountingEntry> acentries;
1685 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1687 // iterate backwards until we have nCount items to return:
1688 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1690 CWalletTx *const pwtx = (*it).second.first;
1692 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1693 CAccountingEntry *const pacentry = (*it).second.second;
1695 AcentryToJSON(*pacentry, strAccount, ret);
1697 if ((int)ret.size() >= (nCount+nFrom)) break;
1699 // ret is newest to oldest
1701 if (nFrom > (int)ret.size())
1703 if ((nFrom + nCount) > (int)ret.size())
1704 nCount = ret.size() - nFrom;
1705 Array::iterator first = ret.begin();
1706 std::advance(first, nFrom);
1707 Array::iterator last = ret.begin();
1708 std::advance(last, nFrom+nCount);
1710 if (last != ret.end()) ret.erase(last, ret.end());
1711 if (first != ret.begin()) ret.erase(ret.begin(), first);
1713 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1718 Value listaccounts(const Array& params, bool fHelp)
1720 if (!EnsureWalletIsAvailable(fHelp))
1723 if (fHelp || params.size() > 2)
1724 throw runtime_error(
1725 "listaccounts ( minconf includeWatchonly)\n"
1726 "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
1728 "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
1729 "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
1731 "{ (json object where keys are account names, and values are numeric balances\n"
1732 " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
1736 "\nList account balances where there at least 1 confirmation\n"
1737 + HelpExampleCli("listaccounts", "") +
1738 "\nList account balances including zero confirmation transactions\n"
1739 + HelpExampleCli("listaccounts", "0") +
1740 "\nList account balances for 6 or more confirmations\n"
1741 + HelpExampleCli("listaccounts", "6") +
1742 "\nAs json rpc call\n"
1743 + HelpExampleRpc("listaccounts", "6")
1746 LOCK2(cs_main, pwalletMain->cs_wallet);
1749 if (params.size() > 0)
1750 nMinDepth = params[0].get_int();
1751 isminefilter includeWatchonly = ISMINE_SPENDABLE;
1752 if(params.size() > 1)
1753 if(params[1].get_bool())
1754 includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
1756 map<string, CAmount> mapAccountBalances;
1757 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
1758 if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
1759 mapAccountBalances[entry.second.name] = 0;
1762 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1764 const CWalletTx& wtx = (*it).second;
1766 string strSentAccount;
1767 list<COutputEntry> listReceived;
1768 list<COutputEntry> listSent;
1769 int nDepth = wtx.GetDepthInMainChain();
1770 if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
1772 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1773 mapAccountBalances[strSentAccount] -= nFee;
1774 BOOST_FOREACH(const COutputEntry& s, listSent)
1775 mapAccountBalances[strSentAccount] -= s.amount;
1776 if (nDepth >= nMinDepth)
1778 BOOST_FOREACH(const COutputEntry& r, listReceived)
1779 if (pwalletMain->mapAddressBook.count(r.destination))
1780 mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
1782 mapAccountBalances[""] += r.amount;
1786 list<CAccountingEntry> acentries;
1787 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1788 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1789 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1792 BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
1793 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1798 Value listsinceblock(const Array& params, bool fHelp)
1800 if (!EnsureWalletIsAvailable(fHelp))
1804 throw runtime_error(
1805 "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
1806 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
1808 "1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
1809 "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
1810 "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
1813 " \"transactions\": [\n"
1814 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
1815 " \"address\":\"zcashaddress\", (string) The zcash address of the transaction. Not present for move transactions (category = move).\n"
1816 " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
1817 " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the 'move' category for moves \n"
1818 " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
1819 " \"vout\" : n, (numeric) the vout value\n"
1820 " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the 'send' category of transactions.\n"
1821 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
1822 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1823 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1824 " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
1825 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1826 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
1827 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
1828 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1829 " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
1831 " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
1834 + HelpExampleCli("listsinceblock", "")
1835 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1836 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1839 LOCK2(cs_main, pwalletMain->cs_wallet);
1841 CBlockIndex *pindex = NULL;
1842 int target_confirms = 1;
1843 isminefilter filter = ISMINE_SPENDABLE;
1845 if (params.size() > 0)
1849 blockId.SetHex(params[0].get_str());
1850 BlockMap::iterator it = mapBlockIndex.find(blockId);
1851 if (it != mapBlockIndex.end())
1852 pindex = it->second;
1855 if (params.size() > 1)
1857 target_confirms = params[1].get_int();
1859 if (target_confirms < 1)
1860 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1863 if(params.size() > 2)
1864 if(params[2].get_bool())
1865 filter = filter | ISMINE_WATCH_ONLY;
1867 int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
1871 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1873 CWalletTx tx = (*it).second;
1875 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1876 ListTransactions(tx, "*", 0, true, transactions, filter);
1879 CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
1880 uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
1883 ret.push_back(Pair("transactions", transactions));
1884 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1889 Value gettransaction(const Array& params, bool fHelp)
1891 if (!EnsureWalletIsAvailable(fHelp))
1894 if (fHelp || params.size() < 1 || params.size() > 2)
1895 throw runtime_error(
1896 "gettransaction \"txid\" ( includeWatchonly )\n"
1897 "\nGet detailed information about in-wallet transaction <txid>\n"
1899 "1. \"txid\" (string, required) The transaction id\n"
1900 "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
1903 " \"amount\" : x.xxx, (numeric) The transaction amount in btc\n"
1904 " \"confirmations\" : n, (numeric) The number of confirmations\n"
1905 " \"blockhash\" : \"hash\", (string) The block hash\n"
1906 " \"blockindex\" : xx, (numeric) The block index\n"
1907 " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
1908 " \"txid\" : \"transactionid\", (string) The transaction id.\n"
1909 " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
1910 " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
1911 " \"details\" : [\n"
1913 " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
1914 " \"address\" : \"zcashaddress\", (string) The zcash address involved in the transaction\n"
1915 " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
1916 " \"amount\" : x.xxx (numeric) The amount in btc\n"
1917 " \"vout\" : n, (numeric) the vout value\n"
1921 " \"vjoinsplit\" : [\n"
1923 " \"anchor\" : \"treestateref\", (string) Merkle root of note commitment tree\n"
1924 " \"nullifiers\" : [ string, ... ] (string) Nullifiers of input notes\n"
1925 " \"commitments\" : [ string, ... ] (string) Note commitments for note outputs\n"
1926 " \"macs\" : [ string, ... ] (string) Message authentication tags\n"
1927 " \"vpub_old\" : x.xxx (numeric) The amount removed from the transparent value pool\n"
1928 " \"vpub_new\" : x.xxx, (numeric) The amount added to the transparent value pool\n"
1932 " \"hex\" : \"data\" (string) Raw data for transaction\n"
1936 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1937 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
1938 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1941 LOCK2(cs_main, pwalletMain->cs_wallet);
1944 hash.SetHex(params[0].get_str());
1946 isminefilter filter = ISMINE_SPENDABLE;
1947 if(params.size() > 1)
1948 if(params[1].get_bool())
1949 filter = filter | ISMINE_WATCH_ONLY;
1952 if (!pwalletMain->mapWallet.count(hash))
1953 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
1954 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1956 CAmount nCredit = wtx.GetCredit(filter);
1957 CAmount nDebit = wtx.GetDebit(filter);
1958 CAmount nNet = nCredit - nDebit;
1959 CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1961 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1962 if (wtx.IsFromMe(filter))
1963 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1965 WalletTxToJSON(wtx, entry);
1968 ListTransactions(wtx, "*", 0, false, details, filter);
1969 entry.push_back(Pair("details", details));
1971 string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
1972 entry.push_back(Pair("hex", strHex));
1978 Value backupwallet(const Array& params, bool fHelp)
1980 if (!EnsureWalletIsAvailable(fHelp))
1983 if (fHelp || params.size() != 1)
1984 throw runtime_error(
1985 "backupwallet \"destination\"\n"
1986 "\nSafely copies wallet.dat to destination, which can be a directory or a path with filename.\n"
1988 "1. \"destination\" (string) The destination directory or file\n"
1990 + HelpExampleCli("backupwallet", "\"backup.dat\"")
1991 + HelpExampleRpc("backupwallet", "\"backup.dat\"")
1994 LOCK2(cs_main, pwalletMain->cs_wallet);
1996 string strDest = params[0].get_str();
1997 if (!BackupWallet(*pwalletMain, strDest))
1998 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
2004 Value keypoolrefill(const Array& params, bool fHelp)
2006 if (!EnsureWalletIsAvailable(fHelp))
2009 if (fHelp || params.size() > 1)
2010 throw runtime_error(
2011 "keypoolrefill ( newsize )\n"
2012 "\nFills the keypool."
2013 + HelpRequiringPassphrase() + "\n"
2015 "1. newsize (numeric, optional, default=100) The new keypool size\n"
2017 + HelpExampleCli("keypoolrefill", "")
2018 + HelpExampleRpc("keypoolrefill", "")
2021 LOCK2(cs_main, pwalletMain->cs_wallet);
2023 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
2024 unsigned int kpSize = 0;
2025 if (params.size() > 0) {
2026 if (params[0].get_int() < 0)
2027 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
2028 kpSize = (unsigned int)params[0].get_int();
2031 EnsureWalletIsUnlocked();
2032 pwalletMain->TopUpKeyPool(kpSize);
2034 if (pwalletMain->GetKeyPoolSize() < kpSize)
2035 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
2041 static void LockWallet(CWallet* pWallet)
2043 LOCK(cs_nWalletUnlockTime);
2044 nWalletUnlockTime = 0;
2048 Value walletpassphrase(const Array& params, bool fHelp)
2050 if (!EnsureWalletIsAvailable(fHelp))
2053 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
2054 throw runtime_error(
2055 "walletpassphrase \"passphrase\" timeout\n"
2056 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
2057 "This is needed prior to performing transactions related to private keys such as sending zcash\n"
2059 "1. \"passphrase\" (string, required) The wallet passphrase\n"
2060 "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
2062 "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
2063 "time that overrides the old one.\n"
2065 "\nunlock the wallet for 60 seconds\n"
2066 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
2067 "\nLock the wallet again (before 60 seconds)\n"
2068 + HelpExampleCli("walletlock", "") +
2069 "\nAs json rpc call\n"
2070 + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
2073 LOCK2(cs_main, pwalletMain->cs_wallet);
2077 if (!pwalletMain->IsCrypted())
2078 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
2080 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
2081 SecureString strWalletPass;
2082 strWalletPass.reserve(100);
2083 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2084 // Alternately, find a way to make params[0] mlock()'d to begin with.
2085 strWalletPass = params[0].get_str().c_str();
2087 if (strWalletPass.length() > 0)
2089 if (!pwalletMain->Unlock(strWalletPass))
2090 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
2093 throw runtime_error(
2094 "walletpassphrase <passphrase> <timeout>\n"
2095 "Stores the wallet decryption key in memory for <timeout> seconds.");
2097 // No need to check return values, because the wallet was unlocked above
2098 pwalletMain->UpdateNullifierNoteMap();
2099 pwalletMain->TopUpKeyPool();
2101 int64_t nSleepTime = params[1].get_int64();
2102 LOCK(cs_nWalletUnlockTime);
2103 nWalletUnlockTime = GetTime() + nSleepTime;
2104 RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
2110 Value walletpassphrasechange(const Array& params, bool fHelp)
2112 if (!EnsureWalletIsAvailable(fHelp))
2115 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
2116 throw runtime_error(
2117 "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
2118 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
2120 "1. \"oldpassphrase\" (string) The current passphrase\n"
2121 "2. \"newpassphrase\" (string) The new passphrase\n"
2123 + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
2124 + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
2127 LOCK2(cs_main, pwalletMain->cs_wallet);
2131 if (!pwalletMain->IsCrypted())
2132 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
2134 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
2135 // Alternately, find a way to make params[0] mlock()'d to begin with.
2136 SecureString strOldWalletPass;
2137 strOldWalletPass.reserve(100);
2138 strOldWalletPass = params[0].get_str().c_str();
2140 SecureString strNewWalletPass;
2141 strNewWalletPass.reserve(100);
2142 strNewWalletPass = params[1].get_str().c_str();
2144 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
2145 throw runtime_error(
2146 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
2147 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
2149 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
2150 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
2156 Value walletlock(const Array& params, bool fHelp)
2158 if (!EnsureWalletIsAvailable(fHelp))
2161 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
2162 throw runtime_error(
2164 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
2165 "After calling this method, you will need to call walletpassphrase again\n"
2166 "before being able to call any methods which require the wallet to be unlocked.\n"
2168 "\nSet the passphrase for 2 minutes to perform a transaction\n"
2169 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
2170 "\nPerform a send (requires passphrase set)\n"
2171 + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 1.0") +
2172 "\nClear the passphrase since we are done before 2 minutes is up\n"
2173 + HelpExampleCli("walletlock", "") +
2174 "\nAs json rpc call\n"
2175 + HelpExampleRpc("walletlock", "")
2178 LOCK2(cs_main, pwalletMain->cs_wallet);
2182 if (!pwalletMain->IsCrypted())
2183 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
2186 LOCK(cs_nWalletUnlockTime);
2187 pwalletMain->Lock();
2188 nWalletUnlockTime = 0;
2195 Value encryptwallet(const Array& params, bool fHelp)
2197 if (!EnsureWalletIsAvailable(fHelp))
2200 auto fEnableWalletEncryption = GetBoolArg("-developerencryptwallet", false);
2202 std::string strWalletEncryptionDisabledMsg = "";
2203 if (!fEnableWalletEncryption) {
2204 strWalletEncryptionDisabledMsg = "\nWARNING: Wallet encryption is DISABLED. This call always fails.\n";
2207 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
2208 throw runtime_error(
2209 "encryptwallet \"passphrase\"\n"
2210 + strWalletEncryptionDisabledMsg +
2211 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
2212 "After this, any calls that interact with private keys such as sending or signing \n"
2213 "will require the passphrase to be set prior the making these calls.\n"
2214 "Use the walletpassphrase call for this, and then walletlock call.\n"
2215 "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
2216 "Note that this will shutdown the server.\n"
2218 "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
2220 "\nEncrypt you wallet\n"
2221 + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
2222 "\nNow set the passphrase to use the wallet, such as for signing or sending zcash\n"
2223 + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
2224 "\nNow we can so something like sign\n"
2225 + HelpExampleCli("signmessage", "\"zcashaddress\" \"test message\"") +
2226 "\nNow lock the wallet again by removing the passphrase\n"
2227 + HelpExampleCli("walletlock", "") +
2228 "\nAs a json rpc call\n"
2229 + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
2232 LOCK2(cs_main, pwalletMain->cs_wallet);
2236 if (!fEnableWalletEncryption) {
2237 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet encryption is disabled.");
2239 if (pwalletMain->IsCrypted())
2240 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
2242 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2243 // Alternately, find a way to make params[0] mlock()'d to begin with.
2244 SecureString strWalletPass;
2245 strWalletPass.reserve(100);
2246 strWalletPass = params[0].get_str().c_str();
2248 if (strWalletPass.length() < 1)
2249 throw runtime_error(
2250 "encryptwallet <passphrase>\n"
2251 "Encrypts the wallet with <passphrase>.");
2253 if (!pwalletMain->EncryptWallet(strWalletPass))
2254 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
2256 // BDB seems to have a bad habit of writing old data into
2257 // slack space in .dat files; that is bad if the old data is
2258 // unencrypted private keys. So:
2260 return "wallet encrypted; Komodo server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
2263 Value lockunspent(const Array& params, bool fHelp)
2265 if (!EnsureWalletIsAvailable(fHelp))
2268 if (fHelp || params.size() < 1 || params.size() > 2)
2269 throw runtime_error(
2270 "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
2271 "\nUpdates list of temporarily unspendable outputs.\n"
2272 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
2273 "A locked transaction output will not be chosen by automatic coin selection, when spending zcash.\n"
2274 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2275 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
2276 "Also see the listunspent call\n"
2278 "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
2279 "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
2280 " [ (json array of json objects)\n"
2282 " \"txid\":\"id\", (string) The transaction id\n"
2283 " \"vout\": n (numeric) The output number\n"
2289 "true|false (boolean) Whether the command was successful or not\n"
2292 "\nList the unspent transactions\n"
2293 + HelpExampleCli("listunspent", "") +
2294 "\nLock an unspent transaction\n"
2295 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2296 "\nList the locked transactions\n"
2297 + HelpExampleCli("listlockunspent", "") +
2298 "\nUnlock the transaction again\n"
2299 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2300 "\nAs a json rpc call\n"
2301 + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
2304 LOCK2(cs_main, pwalletMain->cs_wallet);
2306 if (params.size() == 1)
2307 RPCTypeCheck(params, boost::assign::list_of(bool_type));
2309 RPCTypeCheck(params, boost::assign::list_of(bool_type)(array_type));
2311 bool fUnlock = params[0].get_bool();
2313 if (params.size() == 1) {
2315 pwalletMain->UnlockAllCoins();
2319 Array outputs = params[1].get_array();
2320 BOOST_FOREACH(Value& output, outputs)
2322 if (output.type() != obj_type)
2323 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
2324 const Object& o = output.get_obj();
2326 RPCTypeCheck(o, boost::assign::map_list_of("txid", str_type)("vout", int_type));
2328 string txid = find_value(o, "txid").get_str();
2330 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
2332 int nOutput = find_value(o, "vout").get_int();
2334 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
2336 COutPoint outpt(uint256S(txid), nOutput);
2339 pwalletMain->UnlockCoin(outpt);
2341 pwalletMain->LockCoin(outpt);
2347 Value listlockunspent(const Array& params, bool fHelp)
2349 if (!EnsureWalletIsAvailable(fHelp))
2352 if (fHelp || params.size() > 0)
2353 throw runtime_error(
2355 "\nReturns list of temporarily unspendable outputs.\n"
2356 "See the lockunspent call to lock and unlock transactions for spending.\n"
2360 " \"txid\" : \"transactionid\", (string) The transaction id locked\n"
2361 " \"vout\" : n (numeric) The vout value\n"
2366 "\nList the unspent transactions\n"
2367 + HelpExampleCli("listunspent", "") +
2368 "\nLock an unspent transaction\n"
2369 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2370 "\nList the locked transactions\n"
2371 + HelpExampleCli("listlockunspent", "") +
2372 "\nUnlock the transaction again\n"
2373 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2374 "\nAs a json rpc call\n"
2375 + HelpExampleRpc("listlockunspent", "")
2378 LOCK2(cs_main, pwalletMain->cs_wallet);
2380 vector<COutPoint> vOutpts;
2381 pwalletMain->ListLockedCoins(vOutpts);
2385 BOOST_FOREACH(COutPoint &outpt, vOutpts) {
2388 o.push_back(Pair("txid", outpt.hash.GetHex()));
2389 o.push_back(Pair("vout", (int)outpt.n));
2396 Value settxfee(const Array& params, bool fHelp)
2398 if (!EnsureWalletIsAvailable(fHelp))
2401 if (fHelp || params.size() < 1 || params.size() > 1)
2402 throw runtime_error(
2404 "\nSet the transaction fee per kB.\n"
2406 "1. amount (numeric, required) The transaction fee in BTC/kB rounded to the nearest 0.00000001\n"
2408 "true|false (boolean) Returns true if successful\n"
2410 + HelpExampleCli("settxfee", "0.00001")
2411 + HelpExampleRpc("settxfee", "0.00001")
2414 LOCK2(cs_main, pwalletMain->cs_wallet);
2417 CAmount nAmount = 0;
2418 if (params[0].get_real() != 0.0)
2419 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
2421 payTxFee = CFeeRate(nAmount, 1000);
2425 Value getwalletinfo(const Array& params, bool fHelp)
2427 if (!EnsureWalletIsAvailable(fHelp))
2430 if (fHelp || params.size() != 0)
2431 throw runtime_error(
2433 "Returns an object containing various wallet state info.\n"
2436 " \"walletversion\": xxxxx, (numeric) the wallet version\n"
2437 " \"balance\": xxxxxxx, (numeric) the total confirmed zcash balance of the wallet\n"
2438 " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed zcash balance of the wallet\n"
2439 " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet\n"
2440 " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
2441 " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
2442 " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
2443 " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
2446 + HelpExampleCli("getwalletinfo", "")
2447 + HelpExampleRpc("getwalletinfo", "")
2450 LOCK2(cs_main, pwalletMain->cs_wallet);
2453 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
2454 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
2455 obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
2456 obj.push_back(Pair("immature_balance", ValueFromAmount(pwalletMain->GetImmatureBalance())));
2457 obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size()));
2458 obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
2459 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
2460 if (pwalletMain->IsCrypted())
2461 obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
2465 Value resendwallettransactions(const Array& params, bool fHelp)
2467 if (!EnsureWalletIsAvailable(fHelp))
2470 if (fHelp || params.size() != 0)
2471 throw runtime_error(
2472 "resendwallettransactions\n"
2473 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
2474 "Intended only for testing; the wallet code periodically re-broadcasts\n"
2476 "Returns array of transaction ids that were re-broadcast.\n"
2479 LOCK2(cs_main, pwalletMain->cs_wallet);
2481 std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
2483 BOOST_FOREACH(const uint256& txid, txids)
2485 result.push_back(txid.ToString());
2490 uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
2492 Value listunspent(const Array& params, bool fHelp)
2494 if (!EnsureWalletIsAvailable(fHelp))
2497 if (fHelp || params.size() > 3)
2498 throw runtime_error(
2499 "listunspent ( minconf maxconf [\"address\",...] )\n"
2500 "\nReturns array of unspent transaction outputs\n"
2501 "with between minconf and maxconf (inclusive) confirmations.\n"
2502 "Optionally filter to only include txouts paid to specified addresses.\n"
2503 "Results are an array of Objects, each of which has:\n"
2504 "{txid, vout, scriptPubKey, amount, confirmations}\n"
2506 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
2507 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
2508 "3. \"addresses\" (string) A json array of zcash addresses to filter\n"
2510 " \"address\" (string) zcash address\n"
2514 "[ (array of json object)\n"
2516 " \"txid\" : \"txid\", (string) the transaction id \n"
2517 " \"vout\" : n, (numeric) the vout value\n"
2518 " \"address\" : \"address\", (string) the zcash address\n"
2519 " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
2520 " \"scriptPubKey\" : \"key\", (string) the script key\n"
2521 " \"amount\" : x.xxx, (numeric) the transaction amount in btc\n"
2522 " \"confirmations\" : n (numeric) The number of confirmations\n"
2528 + HelpExampleCli("listunspent", "")
2529 + HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2530 + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2533 RPCTypeCheck(params, boost::assign::list_of(int_type)(int_type)(array_type));
2536 if (params.size() > 0)
2537 nMinDepth = params[0].get_int();
2539 int nMaxDepth = 9999999;
2540 if (params.size() > 1)
2541 nMaxDepth = params[1].get_int();
2543 set<CBitcoinAddress> setAddress;
2544 if (params.size() > 2) {
2545 Array inputs = params[2].get_array();
2546 BOOST_FOREACH(Value& input, inputs) {
2547 CBitcoinAddress address(input.get_str());
2548 if (!address.IsValid())
2549 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Komodo address: ")+input.get_str());
2550 if (setAddress.count(address))
2551 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
2552 setAddress.insert(address);
2557 vector<COutput> vecOutputs;
2558 assert(pwalletMain != NULL);
2559 LOCK2(cs_main, pwalletMain->cs_wallet);
2560 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2561 BOOST_FOREACH(const COutput& out, vecOutputs) {
2562 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
2565 if (setAddress.size()) {
2566 CTxDestination address;
2567 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
2570 if (!setAddress.count(address))
2574 CAmount nValue = out.tx->vout[out.i].nValue;
2575 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
2577 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
2578 entry.push_back(Pair("vout", out.i));
2579 CTxDestination address;
2580 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
2581 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
2582 if (pwalletMain->mapAddressBook.count(address))
2583 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
2585 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
2586 if (pk.IsPayToScriptHash()) {
2587 CTxDestination address;
2588 if (ExtractDestination(pk, address)) {
2589 const CScriptID& hash = boost::get<CScriptID>(address);
2590 CScript redeemScript;
2591 if (pwalletMain->GetCScript(hash, redeemScript))
2592 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
2595 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
2596 if ( out.tx->nLockTime != 0 )
2598 BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
2599 CBlockIndex *tipindex,*pindex = it->second;
2601 if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 )
2603 interest = komodo_interest(pindex->nHeight,nValue,out.tx->nLockTime,tipindex->nTime);
2604 entry.push_back(Pair("interest",ValueFromAmount(interest)));
2607 entry.push_back(Pair("confirmations",out.nDepth));
2608 entry.push_back(Pair("spendable", out.fSpendable));
2609 results.push_back(entry);
2615 uint64_t komodo_interestsum()
2617 uint64_t interest,sum = 0;
2618 vector<COutput> vecOutputs;
2619 assert(pwalletMain != NULL);
2620 LOCK2(cs_main, pwalletMain->cs_wallet);
2621 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2622 BOOST_FOREACH(const COutput& out,vecOutputs)
2624 CAmount nValue = out.tx->vout[out.i].nValue;
2625 if ( out.tx->nLockTime != 0 && out.fSpendable != 0 )
2627 BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
2628 CBlockIndex *tipindex,*pindex = it->second;
2629 if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 )
2631 interest = komodo_interest(pindex->nHeight,nValue,out.tx->nLockTime,tipindex->nTime);
2639 Value zc_sample_joinsplit(const json_spirit::Array& params, bool fHelp)
2642 throw runtime_error(
2643 "zcsamplejoinsplit\n"
2645 "Perform a joinsplit and return the JSDescription.\n"
2652 uint256 anchor = ZCIncrementalMerkleTree().root();
2653 JSDescription samplejoinsplit(*pzcashParams,
2656 {JSInput(), JSInput()},
2657 {JSOutput(), JSOutput()},
2661 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2662 ss << samplejoinsplit;
2664 return HexStr(ss.begin(), ss.end());
2667 Value zc_benchmark(const json_spirit::Array& params, bool fHelp)
2669 if (!EnsureWalletIsAvailable(fHelp)) {
2673 if (fHelp || params.size() < 2) {
2674 throw runtime_error(
2675 "zcbenchmark benchmarktype samplecount\n"
2677 "Runs a benchmark of the selected type samplecount times,\n"
2678 "returning the running times of each sample.\n"
2682 " \"runningtime\": runningtime\n"
2685 " \"runningtime\": runningtime\n"
2694 std::string benchmarktype = params[0].get_str();
2695 int samplecount = params[1].get_int();
2697 if (samplecount <= 0) {
2698 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount");
2701 std::vector<double> sample_times;
2703 if (benchmarktype == "createjoinsplit") {
2704 /* Load the proving now key so that it doesn't happen as part of the
2705 * first joinsplit. */
2706 pzcashParams->loadProvingKey();
2709 JSDescription samplejoinsplit;
2711 if (benchmarktype == "verifyjoinsplit") {
2712 CDataStream ss(ParseHexV(params[2].get_str(), "js"), SER_NETWORK, PROTOCOL_VERSION);
2713 ss >> samplejoinsplit;
2716 for (int i = 0; i < samplecount; i++) {
2717 if (benchmarktype == "sleep") {
2718 sample_times.push_back(benchmark_sleep());
2719 } else if (benchmarktype == "parameterloading") {
2720 sample_times.push_back(benchmark_parameter_loading());
2721 } else if (benchmarktype == "createjoinsplit") {
2722 sample_times.push_back(benchmark_create_joinsplit());
2723 } else if (benchmarktype == "verifyjoinsplit") {
2724 sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
2725 } else if (benchmarktype == "solveequihash") {
2726 if (params.size() < 3) {
2727 sample_times.push_back(benchmark_solve_equihash());
2729 int nThreads = params[2].get_int();
2730 std::vector<double> vals = benchmark_solve_equihash_threaded(nThreads);
2731 sample_times.insert(sample_times.end(), vals.begin(), vals.end());
2733 } else if (benchmarktype == "verifyequihash") {
2734 sample_times.push_back(benchmark_verify_equihash());
2735 } else if (benchmarktype == "validatelargetx") {
2736 sample_times.push_back(benchmark_large_tx());
2737 } else if (benchmarktype == "trydecryptnotes") {
2738 int nAddrs = params[2].get_int();
2739 sample_times.push_back(benchmark_try_decrypt_notes(nAddrs));
2740 } else if (benchmarktype == "incnotewitnesses") {
2741 int nTxs = params[2].get_int();
2742 sample_times.push_back(benchmark_increment_note_witnesses(nTxs));
2744 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
2749 for (auto time : sample_times) {
2751 result.push_back(Pair("runningtime", time));
2752 results.push_back(result);
2758 Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
2760 if (!EnsureWalletIsAvailable(fHelp)) {
2764 if (fHelp || params.size() != 2) {
2765 throw runtime_error(
2766 "zcrawreceive zcsecretkey encryptednote\n"
2768 "DEPRECATED. Decrypts encryptednote and checks if the coin commitments\n"
2769 "are in the blockchain as indicated by the \"exists\" result.\n"
2772 " \"amount\": value,\n"
2773 " \"note\": noteplaintext,\n"
2774 " \"exists\": exists\n"
2779 RPCTypeCheck(params, boost::assign::list_of(str_type)(str_type));
2783 CZCSpendingKey spendingkey(params[0].get_str());
2784 SpendingKey k = spendingkey.Get();
2787 unsigned char nonce;
2788 ZCNoteEncryption::Ciphertext ct;
2792 CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
2798 } catch(const std::exception &) {
2799 throw runtime_error(
2800 "encrypted_note could not be decoded"
2805 ZCNoteDecryption decryptor(k.viewing_key());
2807 NotePlaintext npt = NotePlaintext::decrypt(
2814 PaymentAddress payment_addr = k.address();
2815 Note decrypted_note = npt.note(payment_addr);
2817 assert(pwalletMain != NULL);
2818 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
2820 uint256 commitment = decrypted_note.cm();
2821 pwalletMain->WitnessNoteCommitment(
2827 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2831 result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value)));
2832 result.push_back(Pair("note", HexStr(ss.begin(), ss.end())));
2833 result.push_back(Pair("exists", (bool) witnesses[0]));
2839 Value zc_raw_joinsplit(const json_spirit::Array& params, bool fHelp)
2841 if (!EnsureWalletIsAvailable(fHelp)) {
2845 if (fHelp || params.size() != 5) {
2846 throw runtime_error(
2847 "zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
2848 " inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
2849 " outputs: a JSON object mapping {zcaddr: value, ...}\n"
2851 "DEPRECATED. Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
2852 "Outputs are confidential between sender/receiver. The vpub_old and\n"
2853 "vpub_new values are globally public and move transparent value into\n"
2854 "or out of the confidential value store, respectively.\n"
2856 "Note: The caller is responsible for delivering the output enc1 and\n"
2857 "enc2 to the appropriate recipients, as well as signing rawtxout and\n"
2858 "ensuring it is mined. (A future RPC call will deliver the confidential\n"
2859 "payments in-band on the blockchain.)\n"
2862 " \"encryptednote1\": enc1,\n"
2863 " \"encryptednote2\": enc2,\n"
2864 " \"rawtxn\": rawtxout\n"
2872 if (!DecodeHexTx(tx, params[0].get_str()))
2873 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2875 Object inputs = params[1].get_obj();
2876 Object outputs = params[2].get_obj();
2878 CAmount vpub_old(0);
2879 CAmount vpub_new(0);
2881 if (params[3].get_real() != 0.0)
2882 vpub_old = AmountFromValue(params[3]);
2884 if (params[4].get_real() != 0.0)
2885 vpub_new = AmountFromValue(params[4]);
2887 std::vector<JSInput> vjsin;
2888 std::vector<JSOutput> vjsout;
2889 std::vector<Note> notes;
2890 std::vector<SpendingKey> keys;
2891 std::vector<uint256> commitments;
2893 BOOST_FOREACH(const Pair& s, inputs)
2895 CZCSpendingKey spendingkey(s.value_.get_str());
2896 SpendingKey k = spendingkey.Get();
2903 CDataStream ssData(ParseHexV(s.name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
2907 PaymentAddress addr = k.address();
2908 Note note = npt.note(addr);
2909 notes.push_back(note);
2910 commitments.push_back(note.cm());
2914 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
2915 pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
2917 assert(witnesses.size() == notes.size());
2918 assert(notes.size() == keys.size());
2921 for (size_t i = 0; i < witnesses.size(); i++) {
2922 if (!witnesses[i]) {
2923 throw runtime_error(
2924 "joinsplit input could not be found in tree"
2928 vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
2932 while (vjsin.size() < ZC_NUM_JS_INPUTS) {
2933 vjsin.push_back(JSInput());
2936 BOOST_FOREACH(const Pair& s, outputs)
2938 CZCPaymentAddress pubaddr(s.name_);
2939 PaymentAddress addrTo = pubaddr.Get();
2940 CAmount nAmount = AmountFromValue(s.value_);
2942 vjsout.push_back(JSOutput(addrTo, nAmount));
2945 while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
2946 vjsout.push_back(JSOutput());
2950 if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
2951 throw runtime_error("unsupported joinsplit input/output counts");
2954 uint256 joinSplitPubKey;
2955 unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
2956 crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
2958 CMutableTransaction mtx(tx);
2960 mtx.joinSplitPubKey = joinSplitPubKey;
2962 JSDescription jsdesc(*pzcashParams,
2965 {vjsin[0], vjsin[1]},
2966 {vjsout[0], vjsout[1]},
2971 auto verifier = libzcash::ProofVerifier::Strict();
2972 assert(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey));
2975 mtx.vjoinsplit.push_back(jsdesc);
2977 // Empty output script.
2979 CTransaction signTx(mtx);
2980 uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
2982 // Add the signature
2983 assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
2984 dataToBeSigned.begin(), 32,
2989 assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
2990 dataToBeSigned.begin(), 32,
2991 mtx.joinSplitPubKey.begin()
2994 CTransaction rawTx(mtx);
2996 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2999 std::string encryptedNote1;
3000 std::string encryptedNote2;
3002 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
3003 ss2 << ((unsigned char) 0x00);
3004 ss2 << jsdesc.ephemeralKey;
3005 ss2 << jsdesc.ciphertexts[0];
3006 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
3008 encryptedNote1 = HexStr(ss2.begin(), ss2.end());
3011 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
3012 ss2 << ((unsigned char) 0x01);
3013 ss2 << jsdesc.ephemeralKey;
3014 ss2 << jsdesc.ciphertexts[1];
3015 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
3017 encryptedNote2 = HexStr(ss2.begin(), ss2.end());
3021 result.push_back(Pair("encryptednote1", encryptedNote1));
3022 result.push_back(Pair("encryptednote2", encryptedNote2));
3023 result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
3027 Value zc_raw_keygen(const json_spirit::Array& params, bool fHelp)
3029 if (!EnsureWalletIsAvailable(fHelp)) {
3033 if (fHelp || params.size() != 0) {
3034 throw runtime_error(
3037 "DEPRECATED. Generate a zcaddr which can send and receive confidential values.\n"
3040 " \"zcaddress\": zcaddr,\n"
3041 " \"zcsecretkey\": zcsecretkey,\n"
3046 auto k = SpendingKey::random();
3047 auto addr = k.address();
3048 auto viewing_key = k.viewing_key();
3050 CDataStream viewing(SER_NETWORK, PROTOCOL_VERSION);
3052 viewing << viewing_key;
3054 CZCPaymentAddress pubaddr(addr);
3055 CZCSpendingKey spendingkey(k);
3056 std::string viewing_hex = HexStr(viewing.begin(), viewing.end());
3059 result.push_back(Pair("zcaddress", pubaddr.ToString()));
3060 result.push_back(Pair("zcsecretkey", spendingkey.ToString()));
3061 result.push_back(Pair("zcviewingkey", viewing_hex));
3066 Value z_getnewaddress(const Array& params, bool fHelp)
3068 if (!EnsureWalletIsAvailable(fHelp))
3071 if (fHelp || params.size() > 0)
3072 throw runtime_error(
3074 "\nReturns a new zaddr for receiving payments.\n"
3077 "\"zcashaddress\" (string) The new zaddr\n"
3079 + HelpExampleCli("z_getnewaddress", "")
3080 + HelpExampleRpc("z_getnewaddress", "")
3083 LOCK2(cs_main, pwalletMain->cs_wallet);
3085 EnsureWalletIsUnlocked();
3087 CZCPaymentAddress pubaddr = pwalletMain->GenerateNewZKey();
3088 std::string result = pubaddr.ToString();
3093 Value z_listaddresses(const Array& params, bool fHelp)
3095 if (!EnsureWalletIsAvailable(fHelp))
3098 if (fHelp || params.size() > 1)
3099 throw runtime_error(
3101 "\nReturns the list of zaddr belonging to the wallet.\n"
3104 "[ (json array of string)\n"
3105 " \"zaddr\" (string) a zaddr belonging to the wallet\n"
3109 + HelpExampleCli("z_listaddresses", "")
3110 + HelpExampleRpc("z_listaddresses", "")
3113 LOCK2(cs_main, pwalletMain->cs_wallet);
3116 std::set<libzcash::PaymentAddress> addresses;
3117 pwalletMain->GetPaymentAddresses(addresses);
3118 for (auto addr : addresses ) {
3119 ret.push_back(CZCPaymentAddress(addr).ToString());
3124 CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1) {
3125 set<CBitcoinAddress> setAddress;
3126 vector<COutput> vecOutputs;
3127 CAmount balance = 0;
3129 if (transparentAddress.length() > 0) {
3130 CBitcoinAddress taddr = CBitcoinAddress(transparentAddress);
3131 if (!taddr.IsValid()) {
3132 throw std::runtime_error("invalid transparent address");
3134 setAddress.insert(taddr);
3137 LOCK2(cs_main, pwalletMain->cs_wallet);
3139 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
3141 BOOST_FOREACH(const COutput& out, vecOutputs) {
3142 if (out.nDepth < minDepth) {
3146 if (setAddress.size()) {
3147 CTxDestination address;
3148 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3152 if (!setAddress.count(address)) {
3157 CAmount nValue = out.tx->vout[out.i].nValue; // komodo_interest
3163 CAmount getBalanceZaddr(std::string address, int minDepth = 1) {
3164 CAmount balance = 0;
3165 std::vector<CNotePlaintextEntry> entries;
3166 LOCK2(cs_main, pwalletMain->cs_wallet);
3167 pwalletMain->GetFilteredNotes(entries, address, minDepth);
3168 for (auto & entry : entries) {
3169 balance += CAmount(entry.plaintext.value);
3175 Value z_listreceivedbyaddress(const Array& params, bool fHelp)
3177 if (!EnsureWalletIsAvailable(fHelp))
3180 if (fHelp || params.size()==0 || params.size() >2)
3181 throw runtime_error(
3182 "z_listreceivedbyaddress \"address\" ( minconf )\n"
3183 "\nReturn a list of amounts received by a zaddr belonging to the node’s wallet.\n"
3185 "1. \"address\" (string) The private address.\n"
3186 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3189 " \"txid\": xxxxx, (string) the transaction id\n"
3190 " \"amount\": xxxxx, (numeric) the amount of value in the note\n"
3191 " \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
3195 LOCK2(cs_main, pwalletMain->cs_wallet);
3198 if (params.size() > 1) {
3199 nMinDepth = params[1].get_int();
3201 if (nMinDepth < 0) {
3202 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3205 // Check that the from address is valid.
3206 auto fromaddress = params[0].get_str();
3208 libzcash::PaymentAddress zaddr;
3209 CZCPaymentAddress address(fromaddress);
3211 zaddr = address.Get();
3212 } catch (std::runtime_error) {
3213 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
3216 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3217 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3222 std::vector<CNotePlaintextEntry> entries;
3223 pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false);
3224 for (CNotePlaintextEntry & entry : entries) {
3226 obj.push_back(Pair("txid",entry.jsop.hash.ToString()));
3227 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value))));
3228 std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end());
3229 obj.push_back(Pair("memo", HexStr(data)));
3230 result.push_back(obj);
3236 Value z_getbalance(const Array& params, bool fHelp)
3238 if (!EnsureWalletIsAvailable(fHelp))
3241 if (fHelp || params.size()==0 || params.size() >2)
3242 throw runtime_error(
3243 "z_getbalance \"address\" ( minconf )\n"
3244 "\nReturns the balance of a taddr or zaddr belonging to the node’s wallet.\n"
3246 "1. \"address\" (string) The selected address. It may be a transparent or private address.\n"
3247 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3249 "amount (numeric) The total amount in ZEC received for this address.\n"
3251 "\nThe total amount received by address \"myaddress\"\n"
3252 + HelpExampleCli("z_getbalance", "\"myaddress\"") +
3253 "\nThe total amount received by address \"myaddress\" at least 5 blocks confirmed\n"
3254 + HelpExampleCli("z_getbalance", "\"myaddress\" 5") +
3255 "\nAs a json rpc call\n"
3256 + HelpExampleRpc("z_getbalance", "\"myaddress\", 5")
3259 LOCK2(cs_main, pwalletMain->cs_wallet);
3262 if (params.size() > 1) {
3263 nMinDepth = params[1].get_int();
3265 if (nMinDepth < 0) {
3266 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3269 // Check that the from address is valid.
3270 auto fromaddress = params[0].get_str();
3271 bool fromTaddr = false;
3272 CBitcoinAddress taddr(fromaddress);
3273 fromTaddr = taddr.IsValid();
3274 libzcash::PaymentAddress zaddr;
3276 CZCPaymentAddress address(fromaddress);
3278 zaddr = address.Get();
3279 } catch (std::runtime_error) {
3280 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3282 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3283 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3287 CAmount nBalance = 0;
3289 nBalance = getBalanceTaddr(fromaddress, nMinDepth);
3291 nBalance = getBalanceZaddr(fromaddress, nMinDepth);
3294 return ValueFromAmount(nBalance);
3298 Value z_gettotalbalance(const Array& params, bool fHelp)
3300 if (!EnsureWalletIsAvailable(fHelp))
3303 if (fHelp || params.size() > 1)
3304 throw runtime_error(
3305 "z_gettotalbalance ( minconf )\n"
3306 "\nReturn the total value of funds stored in the node’s wallet.\n"
3308 "1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
3311 " \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
3312 " \"private\": xxxxx, (numeric) the total balance of private funds\n"
3313 " \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n"
3316 "\nThe total amount in the wallet\n"
3317 + HelpExampleCli("z_gettotalbalance", "") +
3318 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3319 + HelpExampleCli("z_gettotalbalance", "5") +
3320 "\nAs a json rpc call\n"
3321 + HelpExampleRpc("z_gettotalbalance", "5")
3324 LOCK2(cs_main, pwalletMain->cs_wallet);
3327 if (params.size() == 1) {
3328 nMinDepth = params[0].get_int();
3330 if (nMinDepth < 0) {
3331 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3334 // getbalance and "getbalance * 1 true" should return the same number
3335 // but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
3336 // pwalletMain->GetBalance() does not accept min depth parameter
3337 // so we use our own method to get balance of utxos.
3338 CAmount nBalance = getBalanceTaddr("", nMinDepth);
3339 CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth);
3340 uint64_t interest = komodo_interestsum();
3341 CAmount nTotalBalance = nBalance + nPrivateBalance + interest;
3343 result.push_back(Pair("transparent", FormatMoney(nBalance, false)));
3344 result.push_back(Pair("interest", FormatMoney(interest, false)));
3345 result.push_back(Pair("private", FormatMoney(nPrivateBalance, false)));
3346 result.push_back(Pair("total", FormatMoney(nTotalBalance, false)));
3350 Value z_getoperationresult(const Array& params, bool fHelp)
3352 if (!EnsureWalletIsAvailable(fHelp))
3355 if (fHelp || params.size() > 1)
3356 throw runtime_error(
3357 "z_getoperationresult ([\"operationid\", ... ]) \n"
3358 "\nRetrieve the result and status of an operation which has finished, and then remove the operation from memory."
3359 + HelpRequiringPassphrase() + "\n"
3361 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3363 "\" [object, ...]\" (array) A list of JSON objects\n"
3366 // This call will remove finished operations
3367 return z_getoperationstatus_IMPL(params, true);
3370 Value z_getoperationstatus(const Array& params, bool fHelp)
3372 if (!EnsureWalletIsAvailable(fHelp))
3375 if (fHelp || params.size() > 1)
3376 throw runtime_error(
3377 "z_getoperationstatus ([\"operationid\", ... ]) \n"
3378 "\nGet operation status and any associated result or error data. The operation will remain in memory."
3379 + HelpRequiringPassphrase() + "\n"
3381 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3383 "\" [object, ...]\" (array) A list of JSON objects\n"
3386 // This call is idempotent so we don't want to remove finished operations
3387 return z_getoperationstatus_IMPL(params, false);
3390 Value z_getoperationstatus_IMPL(const Array& params, bool fRemoveFinishedOperations=false)
3392 LOCK2(cs_main, pwalletMain->cs_wallet);
3394 std::set<AsyncRPCOperationId> filter;
3395 if (params.size()==1) {
3396 Array ids = params[0].get_array();
3397 for (Value & v : ids) {
3398 filter.insert(v.get_str());
3401 bool useFilter = (filter.size()>0);
3404 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3405 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3407 for (auto id : ids) {
3408 if (useFilter && !filter.count(id))
3411 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3414 // It's possible that the operation was removed from the internal queue and map during this loop
3415 // throw JSONRPCError(RPC_INVALID_PARAMETER, "No operation exists for that id.");
3418 Value status = operation->getStatus();
3420 if (fRemoveFinishedOperations) {
3421 // Caller is only interested in retrieving finished results
3422 if (operation->isSuccess() || operation->isFailed() || operation->isCancelled()) {
3423 ret.push_back(status);
3424 q->popOperationForId(id);
3427 ret.push_back(status);
3435 // Here we define the maximum number of zaddr outputs that can be included in a transaction.
3436 // If input notes are small, we might actually require more than one joinsplit per zaddr output.
3437 // For now though, we assume we use one joinsplit per zaddr output (and the second output note is change).
3438 // We reduce the result by 1 to ensure there is room for non-joinsplit CTransaction data.
3439 #define Z_SENDMANY_MAX_ZADDR_OUTPUTS ((MAX_TX_SIZE / JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)) - 1)
3441 // transaction.h comment: spending taddr output requires CTxIn >= 148 bytes and typical taddr txout is 34 bytes
3442 #define CTXIN_SPEND_DUST_SIZE 148
3443 #define CTXOUT_REGULAR_SIZE 34
3445 Value z_sendmany(const Array& params, bool fHelp)
3447 if (!EnsureWalletIsAvailable(fHelp))
3450 if (fHelp || params.size() < 2 || params.size() > 4)
3451 throw runtime_error(
3452 "z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee )\n"
3453 "\nSend multiple times. Amounts are double-precision floating point numbers."
3454 "\nChange from a taddr flows to a new taddr address, while change from zaddr returns to itself."
3455 "\nWhen sending coinbase UTXOs to a zaddr, change is not allowed. The entire value of the UTXO(s) must be consumed."
3456 + strprintf("\nCurrently, the maximum number of zaddr outputs is %d due to transaction size limits.\n", Z_SENDMANY_MAX_ZADDR_OUTPUTS)
3457 + HelpRequiringPassphrase() + "\n"
3459 "1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from.\n"
3460 "2. \"amounts\" (array, required) An array of json objects representing the amounts to send.\n"
3462 " \"address\":address (string, required) The address is a taddr or zaddr\n"
3463 " \"amount\":amount (numeric, required) The numeric amount in ZEC is the value\n"
3464 " \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
3466 "3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
3467 "4. fee (numeric, optional, default="
3468 + strprintf("%s", FormatMoney(ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
3470 "\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
3473 LOCK2(cs_main, pwalletMain->cs_wallet);
3475 // Check that the from address is valid.
3476 auto fromaddress = params[0].get_str();
3477 bool fromTaddr = false;
3478 CBitcoinAddress taddr(fromaddress);
3479 fromTaddr = taddr.IsValid();
3480 libzcash::PaymentAddress zaddr;
3482 CZCPaymentAddress address(fromaddress);
3484 zaddr = address.Get();
3485 } catch (std::runtime_error) {
3487 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3491 // Check that we have the spending key
3493 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3494 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3498 Array outputs = params[1].get_array();
3500 if (outputs.size()==0)
3501 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
3503 // Keep track of addresses to spot duplicates
3504 set<std::string> setAddress;
3507 std::vector<SendManyRecipient> taddrRecipients;
3508 std::vector<SendManyRecipient> zaddrRecipients;
3509 CAmount nTotalOut = 0;
3511 BOOST_FOREACH(Value& output, outputs)
3513 if (output.type() != obj_type)
3514 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
3515 const Object& o = output.get_obj();
3517 // sanity check, report error if unknown key-value pairs
3518 for (const Pair& p : o) {
3519 std::string s = p.name_;
3520 if (s != "address" && s != "amount" && s!="memo")
3521 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown key: ")+s);
3524 string address = find_value(o, "address").get_str();
3525 bool isZaddr = false;
3526 CBitcoinAddress taddr(address);
3527 if (!taddr.IsValid()) {
3529 CZCPaymentAddress zaddr(address);
3532 } catch (std::runtime_error) {
3533 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
3537 if (setAddress.count(address))
3538 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address);
3539 setAddress.insert(address);
3541 Value memoValue = find_value(o, "memo");
3543 if (!memoValue.is_null()) {
3544 memo = memoValue.get_str();
3546 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
3547 } else if (!IsHex(memo)) {
3548 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
3550 if (memo.length() > ZC_MEMO_SIZE*2) {
3551 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
3555 Value av = find_value(o, "amount");
3556 CAmount nAmount = AmountFromValue( av );
3558 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
3561 zaddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3563 taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3566 nTotalOut += nAmount;
3569 // Check the number of zaddr outputs does not exceed the limit.
3570 if (zaddrRecipients.size() > Z_SENDMANY_MAX_ZADDR_OUTPUTS) {
3571 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, too many zaddr outputs");
3574 // As a sanity check, estimate and verify that the size of the transaction will be valid.
3575 // Depending on the input notes, the actual tx size may turn out to be larger and perhaps invalid.
3577 CMutableTransaction mtx;
3579 for (int i = 0; i < zaddrRecipients.size(); i++) {
3580 mtx.vjoinsplit.push_back(JSDescription());
3582 CTransaction tx(mtx);
3583 txsize += tx.GetSerializeSize(SER_NETWORK, tx.nVersion);
3585 txsize += CTXIN_SPEND_DUST_SIZE;
3586 txsize += CTXOUT_REGULAR_SIZE; // There will probably be taddr change
3588 txsize += CTXOUT_REGULAR_SIZE * taddrRecipients.size();
3589 if (txsize > MAX_TX_SIZE) {
3590 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Too many outputs, size of raw transaction would be larger than limit of %d bytes", MAX_TX_SIZE ));
3593 // Minimum confirmations
3595 if (params.size() > 2) {
3596 nMinDepth = params[2].get_int();
3598 if (nMinDepth < 0) {
3599 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3602 // Fee in Zatoshis, not currency format)
3603 CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE;
3604 if (params.size() > 3) {
3605 nFee = AmountFromValue( params[3] );
3606 // Check that the user specified fee is sane.
3607 if (nFee > nTotalOut) {
3608 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the sum of outputs %s", FormatMoney(nFee), FormatMoney(nTotalOut)));
3612 // Create operation and add to global queue
3613 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3614 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee) );
3615 q->addOperation(operation);
3616 AsyncRPCOperationId operationId = operation->getId();
3621 Value z_listoperationids(const Array& params, bool fHelp)
3623 if (!EnsureWalletIsAvailable(fHelp))
3626 if (fHelp || params.size() > 1)
3627 throw runtime_error(
3628 "z_listoperationids\n"
3629 "\nReturns the list of operation ids currently known to the wallet.\n"
3631 "1. \"status\" (string, optional) Filter result by the operation's state state e.g. \"success\".\n"
3633 "[ (json array of string)\n"
3634 " \"operationid\" (string) an operation id belonging to the wallet\n"
3638 + HelpExampleCli("z_listoperationids", "")
3639 + HelpExampleRpc("z_listoperationids", "")
3642 LOCK2(cs_main, pwalletMain->cs_wallet);
3645 bool useFilter = false;
3646 if (params.size()==1) {
3647 filter = params[0].get_str();
3652 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3653 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3654 for (auto id : ids) {
3655 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3659 std::string state = operation->getStateAsString();
3660 if (useFilter && filter.compare(state)!=0)