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.
8 #include "consensus/upgrades.h"
14 #include "rpcserver.h"
17 #include "utilmoneystr.h"
20 #include "primitives/transaction.h"
21 #include "zcbenchmarks.h"
22 #include "script/interpreter.h"
25 #include "asyncrpcoperation.h"
26 #include "asyncrpcqueue.h"
27 #include "wallet/asyncrpcoperation_mergetoaddress.h"
28 #include "wallet/asyncrpcoperation_sendmany.h"
29 #include "wallet/asyncrpcoperation_shieldcoinbase.h"
35 #include <boost/assign/list_of.hpp>
43 using namespace libzcash;
45 extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
46 extern UniValue TxJoinSplitToJSON(const CTransaction& tx);
47 extern uint8_t ASSETCHAINS_PRIVATE;
48 uint32_t komodo_segid32(char *coinaddr);
50 int64_t nWalletUnlockTime;
51 static CCriticalSection cs_nWalletUnlockTime;
54 UniValue z_getoperationstatus_IMPL(const UniValue&, bool);
56 std::string HelpRequiringPassphrase()
58 return pwalletMain && pwalletMain->IsCrypted()
59 ? "\nRequires wallet passphrase to be set with walletpassphrase call."
63 bool EnsureWalletIsAvailable(bool avoidException)
68 throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
75 void EnsureWalletIsUnlocked()
77 if (pwalletMain->IsLocked())
78 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
81 uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight);
83 void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
85 //int32_t i,n,txheight; uint32_t locktime; uint64_t interest = 0;
86 int confirms = wtx.GetDepthInMainChain();
87 entry.push_back(Pair("confirmations", confirms));
89 entry.push_back(Pair("generated", true));
92 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
93 entry.push_back(Pair("blockindex", wtx.nIndex));
94 entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
95 entry.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight));
97 uint256 hash = wtx.GetHash();
98 entry.push_back(Pair("txid", hash.GetHex()));
99 UniValue conflicts(UniValue::VARR);
100 BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
101 conflicts.push_back(conflict.GetHex());
102 entry.push_back(Pair("walletconflicts", conflicts));
103 entry.push_back(Pair("time", wtx.GetTxTime()));
104 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
105 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
106 entry.push_back(Pair(item.first, item.second));
108 entry.push_back(Pair("vjoinsplit", TxJoinSplitToJSON(wtx)));
111 string AccountFromValue(const UniValue& value)
113 string strAccount = value.get_str();
114 //if (strAccount != "")
115 // throw JSONRPCError(RPC_WALLET_ACCOUNTS_UNSUPPORTED, "Accounts are unsupported");
119 char *komodo_chainname()
121 return(ASSETCHAINS_SYMBOL[0] == 0 ? (char *)"KMD" : ASSETCHAINS_SYMBOL);
124 UniValue getnewaddress(const UniValue& params, bool fHelp)
126 if (!EnsureWalletIsAvailable(fHelp))
129 if (fHelp || params.size() > 1)
131 "getnewaddress ( \"account\" )\n"
132 "\nReturns a new " + strprintf("%s",komodo_chainname()) + " address for receiving payments.\n"
134 "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"
136 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) The new " + strprintf("%s",komodo_chainname()) + " address\n"
138 + HelpExampleCli("getnewaddress", "")
139 + HelpExampleRpc("getnewaddress", "")
142 LOCK2(cs_main, pwalletMain->cs_wallet);
144 // Parse the account first so we don't generate a key if there's an error
146 if (params.size() > 0)
147 strAccount = AccountFromValue(params[0]);
149 if (!pwalletMain->IsLocked())
150 pwalletMain->TopUpKeyPool();
152 // Generate a new key that is added to wallet
154 if (!pwalletMain->GetKeyFromPool(newKey))
155 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
156 CKeyID keyID = newKey.GetID();
158 pwalletMain->SetAddressBook(keyID, strAccount, "receive");
160 return CBitcoinAddress(keyID).ToString();
164 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
166 CWalletDB walletdb(pwalletMain->strWalletFile);
169 walletdb.ReadAccount(strAccount, account);
171 bool bKeyUsed = false;
173 // Check if the current key has been used
174 if (account.vchPubKey.IsValid())
176 CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
177 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
178 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
181 const CWalletTx& wtx = (*it).second;
182 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
183 if (txout.scriptPubKey == scriptPubKey)
188 // Generate a new key
189 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
191 if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
192 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
194 pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
195 walletdb.WriteAccount(strAccount, account);
198 return CBitcoinAddress(account.vchPubKey.GetID());
201 UniValue getaccountaddress(const UniValue& params, bool fHelp)
203 if (!EnsureWalletIsAvailable(fHelp))
206 if (fHelp || params.size() != 1)
208 "getaccountaddress \"account\"\n"
209 "\nDEPRECATED. Returns the current " + strprintf("%s",komodo_chainname()) + " address for receiving payments to this account.\n"
211 "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"
213 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) The account " + strprintf("%s",komodo_chainname()) + " address\n"
215 + HelpExampleCli("getaccountaddress", "")
216 + HelpExampleCli("getaccountaddress", "\"\"")
217 + HelpExampleCli("getaccountaddress", "\"myaccount\"")
218 + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
221 LOCK2(cs_main, pwalletMain->cs_wallet);
223 // Parse the account first so we don't generate a key if there's an error
224 string strAccount = AccountFromValue(params[0]);
226 UniValue ret(UniValue::VSTR);
228 ret = GetAccountAddress(strAccount).ToString();
233 UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
235 if (!EnsureWalletIsAvailable(fHelp))
238 if (fHelp || params.size() > 1)
240 "getrawchangeaddress\n"
241 "\nReturns a new " + strprintf("%s",komodo_chainname()) + " address, for receiving change.\n"
242 "This is for use with raw transactions, NOT normal use.\n"
244 "\"address\" (string) The address\n"
246 + HelpExampleCli("getrawchangeaddress", "")
247 + HelpExampleRpc("getrawchangeaddress", "")
250 LOCK2(cs_main, pwalletMain->cs_wallet);
252 if (!pwalletMain->IsLocked())
253 pwalletMain->TopUpKeyPool();
255 CReserveKey reservekey(pwalletMain);
257 if (!reservekey.GetReservedKey(vchPubKey))
258 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
260 reservekey.KeepKey();
262 CKeyID keyID = vchPubKey.GetID();
264 return CBitcoinAddress(keyID).ToString();
268 UniValue setaccount(const UniValue& params, bool fHelp)
270 if (!EnsureWalletIsAvailable(fHelp))
273 if (fHelp || params.size() < 1 || params.size() > 2)
275 "setaccount \"" + strprintf("%s",komodo_chainname()) + "_address\" \"account\"\n"
276 "\nDEPRECATED. Sets the account associated with the given address.\n"
278 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to be associated with an account.\n"
279 "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"
281 + HelpExampleCli("setaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"tabby\"")
282 + HelpExampleRpc("setaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"tabby\"")
285 LOCK2(cs_main, pwalletMain->cs_wallet);
287 CBitcoinAddress address(params[0].get_str());
288 if (!address.IsValid())
289 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
292 if (params.size() > 1)
293 strAccount = AccountFromValue(params[1]);
295 // Only add the account if the address is yours.
296 if (IsMine(*pwalletMain, address.Get()))
298 // Detect when changing the account of an address that is the 'unused current key' of another account:
299 if (pwalletMain->mapAddressBook.count(address.Get()))
301 string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name;
302 if (address == GetAccountAddress(strOldAccount))
303 GetAccountAddress(strOldAccount, true);
305 pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
308 throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
314 UniValue getaccount(const UniValue& params, bool fHelp)
316 if (!EnsureWalletIsAvailable(fHelp))
319 if (fHelp || params.size() != 1)
321 "getaccount \"" + strprintf("%s",komodo_chainname()) + "_address\"\n"
322 "\nDEPRECATED. Returns the account associated with the given address.\n"
324 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address for account lookup.\n"
326 "\"accountname\" (string) the account address\n"
328 + HelpExampleCli("getaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"")
329 + HelpExampleRpc("getaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"")
332 LOCK2(cs_main, pwalletMain->cs_wallet);
334 CBitcoinAddress address(params[0].get_str());
335 if (!address.IsValid())
336 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
339 map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
340 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty())
341 strAccount = (*mi).second.name;
346 UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
348 if (!EnsureWalletIsAvailable(fHelp))
351 if (fHelp || params.size() != 1)
353 "getaddressesbyaccount \"account\"\n"
354 "\nDEPRECATED. Returns the list of addresses for the given account.\n"
356 "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"
358 "[ (json array of string)\n"
359 " \"" + strprintf("%s",komodo_chainname()) + "_address\" (string) a " + strprintf("%s",komodo_chainname()) + " address associated with the given account\n"
363 + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
364 + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
367 LOCK2(cs_main, pwalletMain->cs_wallet);
369 string strAccount = AccountFromValue(params[0]);
371 // Find all addresses that have the given account
372 UniValue ret(UniValue::VARR);
373 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
375 const CBitcoinAddress& address = item.first;
376 const string& strName = item.second.name;
377 if (strName == strAccount)
378 ret.push_back(address.ToString());
383 static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew,uint8_t *opretbuf,int32_t opretlen,long int opretValue)
385 CAmount curBalance = pwalletMain->GetBalance();
389 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
391 if (nValue > curBalance)
392 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
394 // Parse Zcash address
395 CScript scriptPubKey = GetScriptForDestination(address);
397 // Create and send the transaction
398 CReserveKey reservekey(pwalletMain);
399 CAmount nFeeRequired;
400 std::string strError;
401 vector<CRecipient> vecSend;
402 int nChangePosRet = -1;
403 CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
404 vecSend.push_back(recipient);
405 if ( opretlen > 0 && opretbuf != 0 )
407 CScript opretpubkey; int32_t i; uint8_t *ptr;
408 opretpubkey.resize(opretlen);
409 ptr = (uint8_t *)opretpubkey.data();
410 for (i=0; i<opretlen; i++)
412 ptr[i] = opretbuf[i];
413 //printf("%02x",ptr[i]);
415 //printf(" opretbuf[%d]\n",opretlen);
416 CRecipient opret = { opretpubkey, opretValue, false };
417 vecSend.push_back(opret);
419 if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
420 if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
421 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));
422 throw JSONRPCError(RPC_WALLET_ERROR, strError);
424 if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
425 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.");
428 UniValue sendtoaddress(const UniValue& params, bool fHelp)
430 if (!EnsureWalletIsAvailable(fHelp))
433 if (fHelp || params.size() < 2 || params.size() > 5)
435 "sendtoaddress \"" + strprintf("%s",komodo_chainname()) + "_address\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
436 "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
437 + HelpRequiringPassphrase() +
439 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to send to.\n"
440 "2. \"amount\" (numeric, required) The amount in " + strprintf("%s",komodo_chainname()) + " to send. eg 0.1\n"
441 "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
442 " This is not part of the transaction, just kept in your wallet.\n"
443 "4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
444 " to which you're sending the transaction. This is not part of the \n"
445 " transaction, just kept in your wallet.\n"
446 "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
447 " The recipient will receive less " + strprintf("%s",komodo_chainname()) + " than you enter in the amount field.\n"
449 "\"transactionid\" (string) The transaction id.\n"
451 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.1")
452 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.1 \"donation\" \"seans outpost\"")
453 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.1 \"\" \"\" true")
454 + HelpExampleRpc("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", 0.1, \"donation\", \"seans outpost\"")
457 if ( ASSETCHAINS_PRIVATE != 0 && AmountFromValue(params[1]) > 0 )
458 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
460 LOCK2(cs_main, pwalletMain->cs_wallet);
462 CBitcoinAddress address(params[0].get_str());
463 if (!address.IsValid())
464 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
467 CAmount nAmount = AmountFromValue(params[1]);
469 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
473 if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty())
474 wtx.mapValue["comment"] = params[2].get_str();
475 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
476 wtx.mapValue["to"] = params[3].get_str();
478 bool fSubtractFeeFromAmount = false;
479 if (params.size() > 4)
480 fSubtractFeeFromAmount = params[4].get_bool();
482 EnsureWalletIsUnlocked();
484 SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, wtx,0,0,0);
486 return wtx.GetHash().GetHex();
488 #include "komodo_defs.h"
490 #define KOMODO_KVPROTECTED 1
491 #define KOMODO_KVBINARY 2
492 #define KOMODO_KVDURATION 1440
493 #define IGUANA_MAXSCRIPTSIZE 10001
494 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);
495 int32_t komodo_opreturnscript(uint8_t *script,uint8_t type,uint8_t *opret,int32_t opretlen);
496 #define CRYPTO777_KMDADDR "RXL3YXG2ceaB6C5hfJcN4fvmLH2C34knhA"
497 extern int32_t KOMODO_PAX;
498 extern uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE;
499 int32_t komodo_is_issuer();
500 int32_t iguana_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp);
501 int32_t komodo_isrealtime(int32_t *kmdheightp);
502 int32_t pax_fiatstatus(uint64_t *available,uint64_t *deposited,uint64_t *issued,uint64_t *withdrawn,uint64_t *approved,uint64_t *redeemed,char *base);
503 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);
504 int32_t komodo_kvcmp(uint8_t *refvalue,uint16_t refvaluesize,uint8_t *value,uint16_t valuesize);
505 uint64_t komodo_kvfee(uint32_t flags,int32_t opretlen,int32_t keylen);
506 uint256 komodo_kvsig(uint8_t *buf,int32_t len,uint256 privkey);
507 int32_t komodo_kvduration(uint32_t flags);
508 uint256 komodo_kvprivkey(uint256 *pubkeyp,char *passphrase);
509 int32_t komodo_kvsigverify(uint8_t *buf,int32_t len,uint256 _pubkey,uint256 sig);
511 UniValue kvupdate(const UniValue& params, bool fHelp)
513 static uint256 zeroes;
514 CWalletTx wtx; UniValue ret(UniValue::VOBJ);
515 uint8_t keyvalue[IGUANA_MAXSCRIPTSIZE],opretbuf[IGUANA_MAXSCRIPTSIZE]; int32_t i,coresize,haveprivkey,duration,opretlen,height; uint16_t keylen=0,valuesize=0,refvaluesize=0; uint8_t *key,*value=0; uint32_t flags,tmpflags,n; struct komodo_kv *ptr; uint64_t fee; uint256 privkey,pubkey,refpubkey,sig;
516 if (fHelp || params.size() < 3 )
518 "kvupdate key \"value\" days passphrase\n"
519 "\nStore a key value. This feature is only available for asset chains.\n"
521 "1. key (string, required) key\n"
522 "2. \"value\" (string, required) value\n"
523 "3. days (numeric, required) amount of days(1440 blocks/day) before the key expires. Minimum 1 day\n"
524 "4. passphrase (string, optional) passphrase required to update this key\n"
527 " \"coin\": \"xxxxx\", (string) chain the key is stored on\n"
528 " \"height\": xxxxx, (numeric) height the key was stored at\n"
529 " \"expiration\": xxxxx, (numeric) height the key will expire\n"
530 " \"flags\": x, (string) amount of days the key will be stored \n"
531 " \"key\": \"xxxxx\", (numeric) stored key\n"
532 " \"keylen\": xxxxx, (numeric) length of the key\n"
533 " \"value\": \"xxxxx\" (numeric) stored value\n"
534 " \"valuesize\": xxxxx, (string) length of the stored value\n"
535 " \"fee\": xxxxx (string) transaction fee paid to store the key\n"
536 " \"txid\": \"xxxxx\" (string) transaction id\n"
539 + HelpExampleCli("kvupdate", "examplekey \"examplevalue\" 2 examplepassphrase")
540 + HelpExampleRpc("kvupdate", "examplekey \"examplevalue\" 2 examplepassphrase")
542 if (!EnsureWalletIsAvailable(fHelp))
544 if ( ASSETCHAINS_SYMBOL[0] == 0 )
547 memset(&sig,0,sizeof(sig));
548 memset(&privkey,0,sizeof(privkey));
549 memset(&refpubkey,0,sizeof(refpubkey));
550 memset(&pubkey,0,sizeof(pubkey));
551 if ( (n= (int32_t)params.size()) >= 3 )
553 flags = atoi(params[2].get_str().c_str());
554 //printf("flags.%d (%s) n.%d\n",flags,params[2].get_str().c_str(),n);
557 privkey = komodo_kvprivkey(&pubkey,(char *)(n >= 4 ? params[3].get_str().c_str() : "password"));
560 /*for (i=0; i<32; i++)
561 printf("%02x",((uint8_t *)&privkey)[i]);
564 printf("%02x",((uint8_t *)&pubkey)[i]);
565 printf(" pubkey, privkey derived from (%s)\n",(char *)params[3].get_str().c_str());
567 LOCK2(cs_main, pwalletMain->cs_wallet);
568 if ( (keylen= (int32_t)strlen(params[0].get_str().c_str())) > 0 )
570 key = (uint8_t *)params[0].get_str().c_str();
571 if ( n >= 2 && params[1].get_str().c_str() != 0 )
573 value = (uint8_t *)params[1].get_str().c_str();
574 valuesize = (int32_t)strlen(params[1].get_str().c_str());
576 memcpy(keyvalue,key,keylen);
577 if ( (refvaluesize= komodo_kvsearch(&refpubkey,chainActive.LastTip()->nHeight,&tmpflags,&height,&keyvalue[keylen],key,keylen)) >= 0 )
579 if ( (tmpflags & KOMODO_KVPROTECTED) != 0 )
581 if ( memcmp(&refpubkey,&pubkey,sizeof(refpubkey)) != 0 )
583 ret.push_back(Pair("error",(char *)"cant modify write once key without passphrase"));
587 if ( keylen+refvaluesize <= sizeof(keyvalue) )
589 sig = komodo_kvsig(keyvalue,keylen+refvaluesize,privkey);
590 if ( komodo_kvsigverify(keyvalue,keylen+refvaluesize,refpubkey,sig) < 0 )
592 ret.push_back(Pair("error",(char *)"error verifying sig, passphrase is probably wrong"));
593 printf("VERIFY ERROR\n");
595 } // else printf("verified immediately\n");
598 //for (i=0; i<32; i++)
599 // printf("%02x",((uint8_t *)&sig)[i]);
600 //printf(" sig for keylen.%d + valuesize.%d\n",keylen,refvaluesize);
601 ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)));
602 height = chainActive.LastTip()->nHeight;
603 if ( memcmp(&zeroes,&refpubkey,sizeof(refpubkey)) != 0 )
604 ret.push_back(Pair("owner",refpubkey.GetHex()));
605 ret.push_back(Pair("height", (int64_t)height));
606 duration = komodo_kvduration(flags); //((flags >> 2) + 1) * KOMODO_KVDURATION;
607 ret.push_back(Pair("expiration", (int64_t)(height+duration)));
608 ret.push_back(Pair("flags",(int64_t)flags));
609 ret.push_back(Pair("key",params[0].get_str()));
610 ret.push_back(Pair("keylen",(int64_t)keylen));
611 if ( n >= 2 && params[1].get_str().c_str() != 0 )
613 ret.push_back(Pair("value",params[1].get_str()));
614 ret.push_back(Pair("valuesize",valuesize));
616 iguana_rwnum(1,&keyvalue[0],sizeof(keylen),&keylen);
617 iguana_rwnum(1,&keyvalue[2],sizeof(valuesize),&valuesize);
618 iguana_rwnum(1,&keyvalue[4],sizeof(height),&height);
619 iguana_rwnum(1,&keyvalue[8],sizeof(flags),&flags);
620 memcpy(&keyvalue[12],key,keylen);
622 memcpy(&keyvalue[12 + keylen],value,valuesize);
623 coresize = (int32_t)(sizeof(flags)+sizeof(height)+sizeof(uint16_t)*2+keylen+valuesize);
624 if ( haveprivkey != 0 )
627 keyvalue[12 + keylen + valuesize + i] = ((uint8_t *)&pubkey)[i];
629 if ( refvaluesize >=0 )
632 keyvalue[12 + keylen + valuesize + 32 + i] = ((uint8_t *)&sig)[i];
636 if ( (opretlen= komodo_opreturnscript(opretbuf,'K',keyvalue,coresize)) == 40 )
638 //for (i=0; i<opretlen; i++)
639 // printf("%02x",opretbuf[i]);
640 //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]);
641 EnsureWalletIsUnlocked();
642 fee = komodo_kvfee(flags,opretlen,keylen);
643 ret.push_back(Pair("fee",(double)fee/COIN));
644 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
645 if (!destaddress.IsValid())
646 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
647 SendMoney(destaddress.Get(),10000,false,wtx,opretbuf,opretlen,fee);
648 ret.push_back(Pair("txid",wtx.GetHash().GetHex()));
649 } else ret.push_back(Pair("error",(char *)"null key"));
653 UniValue paxdeposit(const UniValue& params, bool fHelp)
655 uint64_t available,deposited,issued,withdrawn,approved,redeemed,seed,komodoshis = 0; int32_t height; char destaddr[64]; uint8_t i,pubkey37[33];
656 bool fSubtractFeeFromAmount = false;
657 if ( KOMODO_PAX == 0 )
659 throw runtime_error("paxdeposit disabled without -pax");
661 if ( komodo_is_issuer() != 0 )
662 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "paxdeposit only from KMD");
663 if (!EnsureWalletIsAvailable(fHelp))
664 throw runtime_error("paxdeposit needs wallet"); //return Value::null;
665 if (fHelp || params.size() != 3)
666 throw runtime_error("paxdeposit address fiatoshis base");
667 LOCK2(cs_main, pwalletMain->cs_wallet);
668 CBitcoinAddress address(params[0].get_str());
669 if (!address.IsValid())
670 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
671 int64_t fiatoshis = atof(params[1].get_str().c_str()) * COIN;
672 std::string base = params[2].get_str();
674 height = chainActive.LastTip()->nHeight;
675 if ( pax_fiatstatus(&available,&deposited,&issued,&withdrawn,&approved,&redeemed,(char *)base.c_str()) != 0 || available < fiatoshis )
677 fprintf(stderr,"available %llu vs fiatoshis %llu\n",(long long)available,(long long)fiatoshis);
678 throw runtime_error("paxdeposit not enough available inventory");
680 komodoshis = PAX_fiatdest(&seed,0,destaddr,pubkey37,(char *)params[0].get_str().c_str(),height,(char *)base.c_str(),fiatoshis);
681 dest.append(destaddr);
682 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
683 if (!destaddress.IsValid())
684 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
686 fprintf(stderr,"%02x",pubkey37[i]);
687 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);
688 EnsureWalletIsUnlocked();
690 uint8_t opretbuf[64]; int32_t opretlen; uint64_t fee = komodoshis / 1000;
693 iguana_rwnum(1,&pubkey37[33],sizeof(height),&height);
694 opretlen = komodo_opreturnscript(opretbuf,'D',pubkey37,37);
695 SendMoney(address.Get(),fee,fSubtractFeeFromAmount,wtx,opretbuf,opretlen,komodoshis);
696 return wtx.GetHash().GetHex();
699 UniValue paxwithdraw(const UniValue& params, bool fHelp)
701 CWalletTx wtx; std::string dest; int32_t kmdheight; uint64_t seed,komodoshis = 0; char destaddr[64]; uint8_t i,pubkey37[37]; bool fSubtractFeeFromAmount = false;
702 if ( ASSETCHAINS_SYMBOL[0] == 0 )
704 if (!EnsureWalletIsAvailable(fHelp))
706 throw runtime_error("paxwithdraw deprecated");
707 if (fHelp || params.size() != 2)
708 throw runtime_error("paxwithdraw address fiatamount");
709 if ( komodo_isrealtime(&kmdheight) == 0 )
711 LOCK2(cs_main, pwalletMain->cs_wallet);
712 CBitcoinAddress address(params[0].get_str());
713 if (!address.IsValid())
714 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
715 int64_t fiatoshis = atof(params[1].get_str().c_str()) * COIN;
716 komodoshis = PAX_fiatdest(&seed,1,destaddr,pubkey37,(char *)params[0].get_str().c_str(),kmdheight,ASSETCHAINS_SYMBOL,fiatoshis);
717 dest.append(destaddr);
718 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
719 if (!destaddress.IsValid())
720 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
722 printf("%02x",pubkey37[i]);
723 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);
724 EnsureWalletIsUnlocked();
725 uint8_t opretbuf[64]; int32_t opretlen; uint64_t fee = fiatoshis / 1000;
728 iguana_rwnum(1,&pubkey37[33],sizeof(kmdheight),&kmdheight);
729 opretlen = komodo_opreturnscript(opretbuf,'W',pubkey37,37);
730 SendMoney(destaddress.Get(),fee,fSubtractFeeFromAmount,wtx,opretbuf,opretlen,fiatoshis);
731 return wtx.GetHash().GetHex();
734 UniValue listaddressgroupings(const UniValue& params, bool fHelp)
736 if (!EnsureWalletIsAvailable(fHelp))
741 "listaddressgroupings\n"
742 "\nLists groups of addresses which have had their common ownership\n"
743 "made public by common use as inputs or as the resulting change\n"
744 "in past transactions\n"
749 " \"" + strprintf("%s",komodo_chainname()) + " address\", (string) The " + strprintf("%s",komodo_chainname()) + " address\n"
750 " amount, (numeric) The amount in " + strprintf("%s",komodo_chainname()) + "\n"
751 " \"account\" (string, optional) The account (DEPRECATED)\n"
758 + HelpExampleCli("listaddressgroupings", "")
759 + HelpExampleRpc("listaddressgroupings", "")
762 LOCK2(cs_main, pwalletMain->cs_wallet);
764 UniValue jsonGroupings(UniValue::VARR);
765 map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
766 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
768 UniValue jsonGrouping(UniValue::VARR);
769 BOOST_FOREACH(CTxDestination address, grouping)
771 UniValue addressInfo(UniValue::VARR);
772 addressInfo.push_back(CBitcoinAddress(address).ToString());
773 addressInfo.push_back(ValueFromAmount(balances[address]));
775 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
776 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
778 jsonGrouping.push_back(addressInfo);
780 jsonGroupings.push_back(jsonGrouping);
782 return jsonGroupings;
785 UniValue signmessage(const UniValue& params, bool fHelp)
787 if (!EnsureWalletIsAvailable(fHelp))
790 if (fHelp || params.size() != 2)
792 "signmessage \"" + strprintf("%s",komodo_chainname()) + " address\" \"message\"\n"
793 "\nSign a message with the private key of an address"
794 + HelpRequiringPassphrase() + "\n"
796 "1. \"" + strprintf("%s",komodo_chainname()) + " address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to use for the private key.\n"
797 "2. \"message\" (string, required) The message to create a signature of.\n"
799 "\"signature\" (string) The signature of the message encoded in base 64\n"
801 "\nUnlock the wallet for 30 seconds\n"
802 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
803 "\nCreate the signature\n"
804 + HelpExampleCli("signmessage", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"my message\"") +
805 "\nVerify the signature\n"
806 + HelpExampleCli("verifymessage", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"signature\" \"my message\"") +
808 + HelpExampleRpc("signmessage", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"my message\"")
811 LOCK2(cs_main, pwalletMain->cs_wallet);
813 EnsureWalletIsUnlocked();
815 string strAddress = params[0].get_str();
816 string strMessage = params[1].get_str();
818 CBitcoinAddress addr(strAddress);
820 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
823 if (!addr.GetKeyID(keyID))
824 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
827 if (!pwalletMain->GetKey(keyID, key))
828 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
830 CHashWriter ss(SER_GETHASH, 0);
831 ss << strMessageMagic;
834 vector<unsigned char> vchSig;
835 if (!key.SignCompact(ss.GetHash(), vchSig))
836 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
838 return EncodeBase64(&vchSig[0], vchSig.size());
841 UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
843 if (!EnsureWalletIsAvailable(fHelp))
846 if (fHelp || params.size() < 1 || params.size() > 2)
848 "getreceivedbyaddress \"" + strprintf("%s",komodo_chainname()) + "_address\" ( minconf )\n"
849 "\nReturns the total amount received by the given " + strprintf("%s",komodo_chainname()) + " address in transactions with at least minconf confirmations.\n"
851 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address for transactions.\n"
852 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
854 "amount (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received at this address.\n"
856 "\nThe amount from transactions with at least 1 confirmation\n"
857 + HelpExampleCli("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"") +
858 "\nThe amount including unconfirmed transactions, zero confirmations\n"
859 + HelpExampleCli("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0") +
860 "\nThe amount with at least 6 confirmations, very safe\n"
861 + HelpExampleCli("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 6") +
862 "\nAs a json rpc call\n"
863 + HelpExampleRpc("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", 6")
866 LOCK2(cs_main, pwalletMain->cs_wallet);
869 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
870 if (!address.IsValid())
871 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
872 CScript scriptPubKey = GetScriptForDestination(address.Get());
873 if (!IsMine(*pwalletMain,scriptPubKey))
876 // Minimum confirmations
878 if (params.size() > 1)
879 nMinDepth = params[1].get_int();
883 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
885 const CWalletTx& wtx = (*it).second;
886 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
889 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
890 if (txout.scriptPubKey == scriptPubKey)
891 if (wtx.GetDepthInMainChain() >= nMinDepth)
892 nAmount += txout.nValue; // komodo_interest?
895 return ValueFromAmount(nAmount);
899 UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
901 if (!EnsureWalletIsAvailable(fHelp))
904 if (fHelp || params.size() < 1 || params.size() > 2)
906 "getreceivedbyaccount \"account\" ( minconf )\n"
907 "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
909 "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"
910 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
912 "amount (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received for this account.\n"
914 "\nAmount received by the default account with at least 1 confirmation\n"
915 + HelpExampleCli("getreceivedbyaccount", "\"\"") +
916 "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
917 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
918 "\nThe amount with at least 6 confirmation, very safe\n"
919 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
920 "\nAs a json rpc call\n"
921 + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
924 LOCK2(cs_main, pwalletMain->cs_wallet);
926 // Minimum confirmations
928 if (params.size() > 1)
929 nMinDepth = params[1].get_int();
931 // Get the set of pub keys assigned to account
932 string strAccount = AccountFromValue(params[0]);
933 set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
937 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
939 const CWalletTx& wtx = (*it).second;
940 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
943 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
945 CTxDestination address;
946 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
947 if (wtx.GetDepthInMainChain() >= nMinDepth)
948 nAmount += txout.nValue; // komodo_interest?
952 return (double)nAmount / (double)COIN;
956 CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
958 CAmount nBalance = 0;
960 // Tally wallet transactions
961 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
963 const CWalletTx& wtx = (*it).second;
964 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
967 CAmount nReceived, nSent, nFee;
968 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
970 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
971 nBalance += nReceived;
972 nBalance -= nSent + nFee;
975 // Tally internal accounting entries
976 nBalance += walletdb.GetAccountCreditDebit(strAccount);
981 CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
983 CWalletDB walletdb(pwalletMain->strWalletFile);
984 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
988 UniValue getbalance(const UniValue& params, bool fHelp)
990 if (!EnsureWalletIsAvailable(fHelp))
993 if (fHelp || params.size() > 3)
995 "getbalance ( \"account\" minconf includeWatchonly )\n"
996 "\nReturns the server's total available balance.\n"
998 "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"
999 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
1000 "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
1002 "amount (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received for this account.\n"
1004 "\nThe total amount in the wallet\n"
1005 + HelpExampleCli("getbalance", "") +
1006 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
1007 + HelpExampleCli("getbalance", "\"*\" 6") +
1008 "\nAs a json rpc call\n"
1009 + HelpExampleRpc("getbalance", "\"*\", 6")
1012 LOCK2(cs_main, pwalletMain->cs_wallet);
1014 if (params.size() == 0)
1015 return ValueFromAmount(pwalletMain->GetBalance());
1018 if (params.size() > 1)
1019 nMinDepth = params[1].get_int();
1020 isminefilter filter = ISMINE_SPENDABLE;
1021 if(params.size() > 2)
1022 if(params[2].get_bool())
1023 filter = filter | ISMINE_WATCH_ONLY;
1025 if (params[0].get_str() == "*") {
1026 // Calculate total balance a different way from GetBalance()
1027 // (GetBalance() sums up all unspent TxOuts)
1028 // getbalance and "getbalance * 1 true" should return the same number
1029 CAmount nBalance = 0;
1030 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1032 const CWalletTx& wtx = (*it).second;
1033 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
1037 string strSentAccount;
1038 list<COutputEntry> listReceived;
1039 list<COutputEntry> listSent;
1040 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
1041 if (wtx.GetDepthInMainChain() >= nMinDepth)
1043 BOOST_FOREACH(const COutputEntry& r, listReceived)
1044 nBalance += r.amount;
1046 BOOST_FOREACH(const COutputEntry& s, listSent)
1047 nBalance -= s.amount;
1050 return ValueFromAmount(nBalance);
1053 string strAccount = AccountFromValue(params[0]);
1055 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
1057 return ValueFromAmount(nBalance);
1060 UniValue getunconfirmedbalance(const UniValue ¶ms, bool fHelp)
1062 if (!EnsureWalletIsAvailable(fHelp))
1063 return NullUniValue;
1065 if (fHelp || params.size() > 0)
1066 throw runtime_error(
1067 "getunconfirmedbalance\n"
1068 "Returns the server's total unconfirmed balance\n");
1070 LOCK2(cs_main, pwalletMain->cs_wallet);
1072 return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
1076 UniValue movecmd(const UniValue& params, bool fHelp)
1078 if (!EnsureWalletIsAvailable(fHelp))
1079 return NullUniValue;
1081 if (fHelp || params.size() < 3 || params.size() > 5)
1082 throw runtime_error(
1083 "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
1084 "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
1086 "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"
1087 "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"
1088 "3. amount (numeric) Quantity of " + strprintf("%s",komodo_chainname()) + " to move between accounts.\n"
1089 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
1090 "5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
1092 "true|false (boolean) true if successful.\n"
1094 "\nMove 0.01 " + strprintf("%s",komodo_chainname()) + " from the default account to the account named tabby\n"
1095 + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
1096 "\nMove 0.01 " + strprintf("%s",komodo_chainname()) + " timotei to akiko with a comment and funds have 6 confirmations\n"
1097 + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
1098 "\nAs a json rpc call\n"
1099 + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
1101 if ( ASSETCHAINS_PRIVATE != 0 )
1102 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
1104 LOCK2(cs_main, pwalletMain->cs_wallet);
1106 string strFrom = AccountFromValue(params[0]);
1107 string strTo = AccountFromValue(params[1]);
1108 CAmount nAmount = AmountFromValue(params[2]);
1110 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1111 if (params.size() > 3)
1112 // unused parameter, used to be nMinDepth, keep type-checking it though
1113 (void)params[3].get_int();
1115 if (params.size() > 4)
1116 strComment = params[4].get_str();
1118 CWalletDB walletdb(pwalletMain->strWalletFile);
1119 if (!walletdb.TxnBegin())
1120 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
1122 int64_t nNow = GetAdjustedTime();
1125 CAccountingEntry debit;
1126 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
1127 debit.strAccount = strFrom;
1128 debit.nCreditDebit = -nAmount;
1130 debit.strOtherAccount = strTo;
1131 debit.strComment = strComment;
1132 walletdb.WriteAccountingEntry(debit);
1135 CAccountingEntry credit;
1136 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
1137 credit.strAccount = strTo;
1138 credit.nCreditDebit = nAmount;
1139 credit.nTime = nNow;
1140 credit.strOtherAccount = strFrom;
1141 credit.strComment = strComment;
1142 walletdb.WriteAccountingEntry(credit);
1144 if (!walletdb.TxnCommit())
1145 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
1151 UniValue sendfrom(const UniValue& params, bool fHelp)
1153 if (!EnsureWalletIsAvailable(fHelp))
1154 return NullUniValue;
1156 if (fHelp || params.size() < 3 || params.size() > 6)
1157 throw runtime_error(
1158 "sendfrom \"fromaccount\" \"to" + strprintf("%s",komodo_chainname()) + "address\" amount ( minconf \"comment\" \"comment-to\" )\n"
1159 "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a " + strprintf("%s",komodo_chainname()) + " address.\n"
1160 "The amount is a real and is rounded to the nearest 0.00000001."
1161 + HelpRequiringPassphrase() + "\n"
1163 "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"
1164 "2. \"to" + strprintf("%s",komodo_chainname()) + "address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to send funds to.\n"
1165 "3. amount (numeric, required) The amount in " + strprintf("%s",komodo_chainname()) + " (transaction fee is added on top).\n"
1166 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
1167 "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
1168 " This is not part of the transaction, just kept in your wallet.\n"
1169 "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n"
1170 " to which you're sending the transaction. This is not part of the transaction, \n"
1171 " it is just kept in your wallet.\n"
1173 "\"transactionid\" (string) The transaction id.\n"
1175 "\nSend 0.01 " + strprintf("%s",komodo_chainname()) + " from the default account to the address, must have at least 1 confirmation\n"
1176 + HelpExampleCli("sendfrom", "\"\" \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.01") +
1177 "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
1178 + HelpExampleCli("sendfrom", "\"tabby\" \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.01 6 \"donation\" \"seans outpost\"") +
1179 "\nAs a json rpc call\n"
1180 + HelpExampleRpc("sendfrom", "\"tabby\", \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", 0.01, 6, \"donation\", \"seans outpost\"")
1182 if ( ASSETCHAINS_PRIVATE != 0 )
1183 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
1185 LOCK2(cs_main, pwalletMain->cs_wallet);
1187 string strAccount = AccountFromValue(params[0]);
1188 CBitcoinAddress address(params[1].get_str());
1189 if (!address.IsValid())
1190 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
1191 CAmount nAmount = AmountFromValue(params[2]);
1193 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1195 if (params.size() > 3)
1196 nMinDepth = params[3].get_int();
1199 wtx.strFromAccount = strAccount;
1200 if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty())
1201 wtx.mapValue["comment"] = params[4].get_str();
1202 if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty())
1203 wtx.mapValue["to"] = params[5].get_str();
1205 EnsureWalletIsUnlocked();
1208 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
1209 if (nAmount > nBalance)
1210 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
1212 SendMoney(address.Get(), nAmount, false, wtx,0,0,0);
1214 return wtx.GetHash().GetHex();
1218 UniValue sendmany(const UniValue& params, bool fHelp)
1220 if (!EnsureWalletIsAvailable(fHelp))
1221 return NullUniValue;
1223 if (fHelp || params.size() < 2 || params.size() > 5)
1224 throw runtime_error(
1225 "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
1226 "\nSend multiple times. Amounts are double-precision floating point numbers."
1227 + HelpRequiringPassphrase() + "\n"
1229 "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"
1230 "2. \"amounts\" (string, required) A json object with addresses and amounts\n"
1232 " \"address\":amount (numeric) The " + strprintf("%s",komodo_chainname()) + " address is the key, the numeric amount in " + strprintf("%s",komodo_chainname()) + " is the value\n"
1235 "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
1236 "4. \"comment\" (string, optional) A comment\n"
1237 "5. subtractfeefromamount (string, optional) A json array with addresses.\n"
1238 " The fee will be equally deducted from the amount of each selected address.\n"
1239 " Those recipients will receive less " + strprintf("%s",komodo_chainname()) + " than you enter in their corresponding amount field.\n"
1240 " If no addresses are specified here, the sender pays the fee.\n"
1242 " \"address\" (string) Subtract fee from this address\n"
1246 "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
1247 " the number of addresses.\n"
1249 "\nSend two amounts to two different addresses:\n"
1250 + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\"") +
1251 "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
1252 + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\" 6 \"testing\"") +
1253 "\nSend two amounts to two different addresses, subtract fee from amount:\n"
1254 + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\" 1 \"\" \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"") +
1255 "\nAs a json rpc call\n"
1256 + HelpExampleRpc("sendmany", "\"\", \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\", 6, \"testing\"")
1258 if ( ASSETCHAINS_PRIVATE != 0 )
1259 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
1261 LOCK2(cs_main, pwalletMain->cs_wallet);
1263 string strAccount = AccountFromValue(params[0]);
1264 UniValue sendTo = params[1].get_obj();
1266 if (params.size() > 2)
1267 nMinDepth = params[2].get_int();
1270 wtx.strFromAccount = strAccount;
1271 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
1272 wtx.mapValue["comment"] = params[3].get_str();
1274 UniValue subtractFeeFromAmount(UniValue::VARR);
1275 if (params.size() > 4)
1276 subtractFeeFromAmount = params[4].get_array();
1278 set<CBitcoinAddress> setAddress;
1279 vector<CRecipient> vecSend;
1281 CAmount totalAmount = 0;
1282 vector<string> keys = sendTo.getKeys();
1283 BOOST_FOREACH(const string& name_, keys)
1285 CBitcoinAddress address(name_);
1286 if (!address.IsValid())
1287 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid " + strprintf("%s",komodo_chainname()) + " address: ")+name_);
1289 //if (setAddress.count(address))
1290 // throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
1291 setAddress.insert(address);
1293 CScript scriptPubKey = GetScriptForDestination(address.Get());
1294 CAmount nAmount = AmountFromValue(sendTo[name_]);
1296 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1297 totalAmount += nAmount;
1299 bool fSubtractFeeFromAmount = false;
1300 for (size_t idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
1301 const UniValue& addr = subtractFeeFromAmount[idx];
1302 if (addr.get_str() == name_)
1303 fSubtractFeeFromAmount = true;
1306 CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
1307 vecSend.push_back(recipient);
1310 EnsureWalletIsUnlocked();
1313 CAmount nBalance = pwalletMain->GetBalance();
1314 //CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
1315 if (totalAmount > nBalance)
1316 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
1319 CReserveKey keyChange(pwalletMain);
1320 CAmount nFeeRequired = 0;
1321 int nChangePosRet = -1;
1322 string strFailReason;
1323 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
1325 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
1326 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1327 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
1329 return wtx.GetHash().GetHex();
1332 // Defined in rpcmisc.cpp
1333 extern CScript _createmultisig_redeemScript(const UniValue& params);
1335 UniValue addmultisigaddress(const UniValue& params, bool fHelp)
1337 if (!EnsureWalletIsAvailable(fHelp))
1338 return NullUniValue;
1340 if (fHelp || params.size() < 2 || params.size() > 3)
1342 string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
1343 "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
1344 "Each key is a " + strprintf("%s",komodo_chainname()) + " address or hex-encoded public key.\n"
1345 "If 'account' is specified (DEPRECATED), assign address to that account.\n"
1348 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
1349 "2. \"keysobject\" (string, required) A json array of " + strprintf("%s",komodo_chainname()) + " addresses or hex-encoded public keys\n"
1351 " \"address\" (string) " + strprintf("%s",komodo_chainname()) + " address or hex-encoded public key\n"
1354 "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"
1357 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) A " + strprintf("%s",komodo_chainname()) + " address associated with the keys.\n"
1360 "\nAdd a multisig address from 2 addresses\n"
1361 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"") +
1362 "\nAs json rpc call\n"
1363 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"")
1365 throw runtime_error(msg);
1368 LOCK2(cs_main, pwalletMain->cs_wallet);
1371 if (params.size() > 2)
1372 strAccount = AccountFromValue(params[2]);
1374 // Construct using pay-to-script-hash:
1375 CScript inner = _createmultisig_redeemScript(params);
1376 CScriptID innerID(inner);
1377 pwalletMain->AddCScript(inner);
1379 pwalletMain->SetAddressBook(innerID, strAccount, "send");
1380 return CBitcoinAddress(innerID).ToString();
1388 vector<uint256> txids;
1393 nConf = std::numeric_limits<int>::max();
1394 fIsWatchonly = false;
1398 UniValue ListReceived(const UniValue& params, bool fByAccounts)
1400 // Minimum confirmations
1402 if (params.size() > 0)
1403 nMinDepth = params[0].get_int();
1405 // Whether to include empty accounts
1406 bool fIncludeEmpty = false;
1407 if (params.size() > 1)
1408 fIncludeEmpty = params[1].get_bool();
1410 isminefilter filter = ISMINE_SPENDABLE;
1411 if(params.size() > 2)
1412 if(params[2].get_bool())
1413 filter = filter | ISMINE_WATCH_ONLY;
1416 map<CBitcoinAddress, tallyitem> mapTally;
1417 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1419 const CWalletTx& wtx = (*it).second;
1421 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
1424 int nDepth = wtx.GetDepthInMainChain();
1425 if (nDepth < nMinDepth)
1428 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1430 CTxDestination address;
1431 if (!ExtractDestination(txout.scriptPubKey, address))
1434 isminefilter mine = IsMine(*pwalletMain, address);
1435 if(!(mine & filter))
1438 tallyitem& item = mapTally[address];
1439 item.nAmount += txout.nValue; // komodo_interest?
1440 item.nConf = min(item.nConf, nDepth);
1441 item.txids.push_back(wtx.GetHash());
1442 if (mine & ISMINE_WATCH_ONLY)
1443 item.fIsWatchonly = true;
1448 UniValue ret(UniValue::VARR);
1449 map<string, tallyitem> mapAccountTally;
1450 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
1452 const CBitcoinAddress& address = item.first;
1453 const string& strAccount = item.second.name;
1454 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1455 if (it == mapTally.end() && !fIncludeEmpty)
1458 CAmount nAmount = 0;
1459 int nConf = std::numeric_limits<int>::max();
1460 bool fIsWatchonly = false;
1461 if (it != mapTally.end())
1463 nAmount = (*it).second.nAmount;
1464 nConf = (*it).second.nConf;
1465 fIsWatchonly = (*it).second.fIsWatchonly;
1470 tallyitem& item = mapAccountTally[strAccount];
1471 item.nAmount += nAmount;
1472 item.nConf = min(item.nConf, nConf);
1473 item.fIsWatchonly = fIsWatchonly;
1477 UniValue obj(UniValue::VOBJ);
1479 obj.push_back(Pair("involvesWatchonly", true));
1480 obj.push_back(Pair("address", address.ToString()));
1481 obj.push_back(Pair("account", strAccount));
1482 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1483 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1484 UniValue transactions(UniValue::VARR);
1485 if (it != mapTally.end())
1487 BOOST_FOREACH(const uint256& item, (*it).second.txids)
1489 transactions.push_back(item.GetHex());
1492 obj.push_back(Pair("txids", transactions));
1499 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1501 CAmount nAmount = (*it).second.nAmount;
1502 int nConf = (*it).second.nConf;
1503 UniValue obj(UniValue::VOBJ);
1504 if((*it).second.fIsWatchonly)
1505 obj.push_back(Pair("involvesWatchonly", true));
1506 obj.push_back(Pair("account", (*it).first));
1507 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1508 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1516 UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
1518 if (!EnsureWalletIsAvailable(fHelp))
1519 return NullUniValue;
1521 if (fHelp || params.size() > 3)
1522 throw runtime_error(
1523 "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
1524 "\nList balances by receiving address.\n"
1526 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1527 "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n"
1528 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1533 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
1534 " \"address\" : \"receivingaddress\", (string) The receiving address\n"
1535 " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
1536 " \"amount\" : x.xxx, (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received by the address\n"
1537 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1543 + HelpExampleCli("listreceivedbyaddress", "")
1544 + HelpExampleCli("listreceivedbyaddress", "6 true")
1545 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
1548 LOCK2(cs_main, pwalletMain->cs_wallet);
1550 return ListReceived(params, false);
1553 UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
1555 if (!EnsureWalletIsAvailable(fHelp))
1556 return NullUniValue;
1558 if (fHelp || params.size() > 3)
1559 throw runtime_error(
1560 "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
1561 "\nDEPRECATED. List balances by account.\n"
1563 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1564 "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
1565 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1570 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
1571 " \"account\" : \"accountname\", (string) The account name of the receiving account\n"
1572 " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
1573 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1579 + HelpExampleCli("listreceivedbyaccount", "")
1580 + HelpExampleCli("listreceivedbyaccount", "6 true")
1581 + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
1584 LOCK2(cs_main, pwalletMain->cs_wallet);
1586 return ListReceived(params, true);
1589 static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
1591 CBitcoinAddress addr;
1593 entry.push_back(Pair("address", addr.ToString()));
1596 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
1599 string strSentAccount;
1600 list<COutputEntry> listReceived;
1601 list<COutputEntry> listSent;
1603 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
1605 bool fAllAccounts = (strAccount == string("*"));
1606 bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
1609 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1611 BOOST_FOREACH(const COutputEntry& s, listSent)
1613 UniValue entry(UniValue::VOBJ);
1614 if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
1615 entry.push_back(Pair("involvesWatchonly", true));
1616 entry.push_back(Pair("account", strSentAccount));
1617 MaybePushAddress(entry, s.destination);
1618 entry.push_back(Pair("category", "send"));
1619 entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
1620 entry.push_back(Pair("vout", s.vout));
1621 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1623 WalletTxToJSON(wtx, entry);
1625 entry.push_back(Pair("size", (uint64_t)static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1627 entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1629 ret.push_back(entry);
1634 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1636 BOOST_FOREACH(const COutputEntry& r, listReceived)
1639 if (pwalletMain->mapAddressBook.count(r.destination))
1640 account = pwalletMain->mapAddressBook[r.destination].name;
1641 if (fAllAccounts || (account == strAccount))
1643 UniValue entry(UniValue::VOBJ);
1644 if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
1645 entry.push_back(Pair("involvesWatchonly", true));
1646 entry.push_back(Pair("account", account));
1647 MaybePushAddress(entry, r.destination);
1648 if (wtx.IsCoinBase())
1650 if (wtx.GetDepthInMainChain() < 1)
1651 entry.push_back(Pair("category", "orphan"));
1652 else if (wtx.GetBlocksToMaturity() > 0)
1653 entry.push_back(Pair("category", "immature"));
1655 entry.push_back(Pair("category", "generate"));
1659 entry.push_back(Pair("category", "receive"));
1661 entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
1662 entry.push_back(Pair("vout", r.vout));
1664 WalletTxToJSON(wtx, entry);
1666 entry.push_back(Pair("size", (uint64_t)static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1668 entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1670 ret.push_back(entry);
1676 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret)
1678 bool fAllAccounts = (strAccount == string("*"));
1680 if (fAllAccounts || acentry.strAccount == strAccount)
1682 UniValue entry(UniValue::VOBJ);
1683 entry.push_back(Pair("account", acentry.strAccount));
1684 entry.push_back(Pair("category", "move"));
1685 entry.push_back(Pair("time", acentry.nTime));
1686 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1687 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1688 entry.push_back(Pair("comment", acentry.strComment));
1689 ret.push_back(entry);
1693 UniValue listtransactions(const UniValue& params, bool fHelp)
1695 if (!EnsureWalletIsAvailable(fHelp))
1696 return NullUniValue;
1698 if (fHelp || params.size() > 4)
1699 throw runtime_error(
1700 "listtransactions ( \"account\" count from includeWatchonly)\n"
1701 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
1703 "1. \"account\" (string, optional) DEPRECATED. The account name. Should be \"*\".\n"
1704 "2. count (numeric, optional, default=10) The number of transactions to return\n"
1705 "3. from (numeric, optional, default=0) The number of transactions to skip\n"
1706 "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
1710 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n"
1711 " It will be \"\" for the default account.\n"
1712 " \"address\":\"" + strprintf("%s",komodo_chainname()) + "_address\", (string) The " + strprintf("%s",komodo_chainname()) + " address of the transaction. Not present for \n"
1713 " move transactions (category = move).\n"
1714 " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
1715 " transaction between accounts, and not associated with an address,\n"
1716 " transaction id or block. 'send' and 'receive' transactions are \n"
1717 " associated with an address, transaction id and block details\n"
1718 " \"amount\": x.xxx, (numeric) The amount in " + strprintf("%s",komodo_chainname()) + ". This is negative for the 'send' category, and for the\n"
1719 " 'move' category for moves outbound. It is positive for the 'receive' category,\n"
1720 " and for the 'move' category for inbound funds.\n"
1721 " \"vout\" : n, (numeric) the vout value\n"
1722 " \"fee\": x.xxx, (numeric) The amount of the fee in " + strprintf("%s",komodo_chainname()) + ". This is negative and only available for the \n"
1723 " 'send' category of transactions.\n"
1724 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
1725 " 'receive' category of transactions.\n"
1726 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
1727 " category of transactions.\n"
1728 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
1729 " category of transactions.\n"
1730 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1731 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1732 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
1733 " for 'send' and 'receive' category of transactions.\n"
1734 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1735 " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
1736 " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
1737 " negative amounts).\n"
1738 " \"size\": n, (numeric) Transaction size in bytes\n"
1743 "\nList the most recent 10 transactions in the systems\n"
1744 + HelpExampleCli("listtransactions", "") +
1745 "\nList transactions 100 to 120\n"
1746 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
1747 "\nAs a json rpc call\n"
1748 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
1751 LOCK2(cs_main, pwalletMain->cs_wallet);
1753 string strAccount = "*";
1754 if (params.size() > 0)
1755 strAccount = params[0].get_str();
1757 if (params.size() > 1)
1758 nCount = params[1].get_int();
1760 if (params.size() > 2)
1761 nFrom = params[2].get_int();
1762 isminefilter filter = ISMINE_SPENDABLE;
1763 if(params.size() > 3)
1764 if(params[3].get_bool())
1765 filter = filter | ISMINE_WATCH_ONLY;
1768 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1770 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1772 UniValue ret(UniValue::VARR);
1774 std::list<CAccountingEntry> acentries;
1775 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1777 // iterate backwards until we have nCount items to return:
1778 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1780 CWalletTx *const pwtx = (*it).second.first;
1782 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1783 CAccountingEntry *const pacentry = (*it).second.second;
1785 AcentryToJSON(*pacentry, strAccount, ret);
1787 if ((int)ret.size() >= (nCount+nFrom)) break;
1789 // ret is newest to oldest
1791 if (nFrom > (int)ret.size())
1793 if ((nFrom + nCount) > (int)ret.size())
1794 nCount = ret.size() - nFrom;
1796 vector<UniValue> arrTmp = ret.getValues();
1798 vector<UniValue>::iterator first = arrTmp.begin();
1799 std::advance(first, nFrom);
1800 vector<UniValue>::iterator last = arrTmp.begin();
1801 std::advance(last, nFrom+nCount);
1803 if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
1804 if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
1806 std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
1810 ret.push_backV(arrTmp);
1815 UniValue listaccounts(const UniValue& params, bool fHelp)
1817 if (!EnsureWalletIsAvailable(fHelp))
1818 return NullUniValue;
1820 if (fHelp || params.size() > 2)
1821 throw runtime_error(
1822 "listaccounts ( minconf includeWatchonly)\n"
1823 "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
1825 "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
1826 "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
1828 "{ (json object where keys are account names, and values are numeric balances\n"
1829 " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
1833 "\nList account balances where there at least 1 confirmation\n"
1834 + HelpExampleCli("listaccounts", "") +
1835 "\nList account balances including zero confirmation transactions\n"
1836 + HelpExampleCli("listaccounts", "0") +
1837 "\nList account balances for 6 or more confirmations\n"
1838 + HelpExampleCli("listaccounts", "6") +
1839 "\nAs json rpc call\n"
1840 + HelpExampleRpc("listaccounts", "6")
1843 LOCK2(cs_main, pwalletMain->cs_wallet);
1846 if (params.size() > 0)
1847 nMinDepth = params[0].get_int();
1848 isminefilter includeWatchonly = ISMINE_SPENDABLE;
1849 if(params.size() > 1)
1850 if(params[1].get_bool())
1851 includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
1853 map<string, CAmount> mapAccountBalances;
1854 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
1855 if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
1856 mapAccountBalances[entry.second.name] = 0;
1859 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1861 const CWalletTx& wtx = (*it).second;
1863 string strSentAccount;
1864 list<COutputEntry> listReceived;
1865 list<COutputEntry> listSent;
1866 int nDepth = wtx.GetDepthInMainChain();
1867 if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
1869 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1870 mapAccountBalances[strSentAccount] -= nFee;
1871 BOOST_FOREACH(const COutputEntry& s, listSent)
1872 mapAccountBalances[strSentAccount] -= s.amount;
1873 if (nDepth >= nMinDepth)
1875 BOOST_FOREACH(const COutputEntry& r, listReceived)
1876 if (pwalletMain->mapAddressBook.count(r.destination))
1877 mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
1879 mapAccountBalances[""] += r.amount;
1883 list<CAccountingEntry> acentries;
1884 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1885 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1886 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1888 UniValue ret(UniValue::VOBJ);
1889 BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
1890 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1895 UniValue listsinceblock(const UniValue& params, bool fHelp)
1897 if (!EnsureWalletIsAvailable(fHelp))
1898 return NullUniValue;
1901 throw runtime_error(
1902 "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
1903 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
1905 "1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
1906 "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
1907 "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
1910 " \"transactions\": [\n"
1911 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
1912 " \"address\":\"" + strprintf("%s",komodo_chainname()) + "_address\", (string) The " + strprintf("%s",komodo_chainname()) + " address of the transaction. Not present for move transactions (category = move).\n"
1913 " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
1914 " \"amount\": x.xxx, (numeric) The amount in " + strprintf("%s",komodo_chainname()) + ". This is negative for the 'send' category, and for the 'move' category for moves \n"
1915 " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
1916 " \"vout\" : n, (numeric) the vout value\n"
1917 " \"fee\": x.xxx, (numeric) The amount of the fee in " + strprintf("%s",komodo_chainname()) + ". This is negative and only available for the 'send' category of transactions.\n"
1918 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
1919 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1920 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1921 " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
1922 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1923 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
1924 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
1925 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1926 " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
1928 " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
1931 + HelpExampleCli("listsinceblock", "")
1932 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1933 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1936 LOCK2(cs_main, pwalletMain->cs_wallet);
1938 CBlockIndex *pindex = NULL;
1939 int target_confirms = 1;
1940 isminefilter filter = ISMINE_SPENDABLE;
1942 if (params.size() > 0)
1946 blockId.SetHex(params[0].get_str());
1947 BlockMap::iterator it = mapBlockIndex.find(blockId);
1948 if (it != mapBlockIndex.end())
1949 pindex = it->second;
1952 if (params.size() > 1)
1954 target_confirms = params[1].get_int();
1956 if (target_confirms < 1)
1957 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1960 if(params.size() > 2)
1961 if(params[2].get_bool())
1962 filter = filter | ISMINE_WATCH_ONLY;
1964 int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
1966 UniValue transactions(UniValue::VARR);
1968 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1970 CWalletTx tx = (*it).second;
1972 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1973 ListTransactions(tx, "*", 0, true, transactions, filter);
1976 CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
1977 uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
1979 UniValue ret(UniValue::VOBJ);
1980 ret.push_back(Pair("transactions", transactions));
1981 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1986 UniValue gettransaction(const UniValue& params, bool fHelp)
1988 if (!EnsureWalletIsAvailable(fHelp))
1989 return NullUniValue;
1991 if (fHelp || params.size() < 1 || params.size() > 2)
1992 throw runtime_error(
1993 "gettransaction \"txid\" ( includeWatchonly )\n"
1994 "\nGet detailed information about in-wallet transaction <txid>\n"
1996 "1. \"txid\" (string, required) The transaction id\n"
1997 "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
2000 " \"amount\" : x.xxx, (numeric) The transaction amount in " + strprintf("%s",komodo_chainname()) + "\n"
2001 " \"confirmations\" : n, (numeric) The number of confirmations\n"
2002 " \"blockhash\" : \"hash\", (string) The block hash\n"
2003 " \"blockindex\" : xx, (numeric) The block index\n"
2004 " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
2005 " \"txid\" : \"transactionid\", (string) The transaction id.\n"
2006 " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
2007 " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
2008 " \"details\" : [\n"
2010 " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
2011 " \"address\" : \"" + strprintf("%s",komodo_chainname()) + "_address\", (string) The " + strprintf("%s",komodo_chainname()) + " address involved in the transaction\n"
2012 " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
2013 " \"amount\" : x.xxx (numeric) The amount in " + strprintf("%s",komodo_chainname()) + "\n"
2014 " \"vout\" : n, (numeric) the vout value\n"
2018 " \"vjoinsplit\" : [\n"
2020 " \"anchor\" : \"treestateref\", (string) Merkle root of note commitment tree\n"
2021 " \"nullifiers\" : [ string, ... ] (string) Nullifiers of input notes\n"
2022 " \"commitments\" : [ string, ... ] (string) Note commitments for note outputs\n"
2023 " \"macs\" : [ string, ... ] (string) Message authentication tags\n"
2024 " \"vpub_old\" : x.xxx (numeric) The amount removed from the transparent value pool\n"
2025 " \"vpub_new\" : x.xxx, (numeric) The amount added to the transparent value pool\n"
2029 " \"hex\" : \"data\" (string) Raw data for transaction\n"
2033 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
2034 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
2035 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
2038 LOCK2(cs_main, pwalletMain->cs_wallet);
2041 hash.SetHex(params[0].get_str());
2043 isminefilter filter = ISMINE_SPENDABLE;
2044 if(params.size() > 1)
2045 if(params[1].get_bool())
2046 filter = filter | ISMINE_WATCH_ONLY;
2048 UniValue entry(UniValue::VOBJ);
2049 if (!pwalletMain->mapWallet.count(hash))
2050 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
2051 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
2053 CAmount nCredit = wtx.GetCredit(filter);
2054 CAmount nDebit = wtx.GetDebit(filter);
2055 CAmount nNet = nCredit - nDebit;
2056 CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
2058 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
2059 if (wtx.IsFromMe(filter))
2060 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
2062 WalletTxToJSON(wtx, entry);
2064 UniValue details(UniValue::VARR);
2065 ListTransactions(wtx, "*", 0, false, details, filter);
2066 entry.push_back(Pair("details", details));
2068 string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
2069 entry.push_back(Pair("hex", strHex));
2075 UniValue backupwallet(const UniValue& params, bool fHelp)
2077 if (!EnsureWalletIsAvailable(fHelp))
2078 return NullUniValue;
2080 if (fHelp || params.size() != 1)
2081 throw runtime_error(
2082 "backupwallet \"destination\"\n"
2083 "\nSafely copies wallet.dat to destination filename\n"
2085 "1. \"destination\" (string, required) The destination filename, saved in the directory set by -exportdir option.\n"
2087 "\"path\" (string) The full path of the destination file\n"
2089 + HelpExampleCli("backupwallet", "\"backupdata\"")
2090 + HelpExampleRpc("backupwallet", "\"backupdata\"")
2093 LOCK2(cs_main, pwalletMain->cs_wallet);
2095 boost::filesystem::path exportdir;
2097 exportdir = GetExportDir();
2098 } catch (const std::runtime_error& e) {
2099 throw JSONRPCError(RPC_INTERNAL_ERROR, e.what());
2101 if (exportdir.empty()) {
2102 throw JSONRPCError(RPC_WALLET_ERROR, "Cannot backup wallet until the -exportdir option has been set");
2104 std::string unclean = params[0].get_str();
2105 std::string clean = SanitizeFilename(unclean);
2106 if (clean.compare(unclean) != 0) {
2107 throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Filename is invalid as only alphanumeric characters are allowed. Try '%s' instead.", clean));
2109 boost::filesystem::path exportfilepath = exportdir / clean;
2111 if (!BackupWallet(*pwalletMain, exportfilepath.string()))
2112 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
2114 return exportfilepath.string();
2118 UniValue keypoolrefill(const UniValue& params, bool fHelp)
2120 if (!EnsureWalletIsAvailable(fHelp))
2121 return NullUniValue;
2123 if (fHelp || params.size() > 1)
2124 throw runtime_error(
2125 "keypoolrefill ( newsize )\n"
2126 "\nFills the keypool."
2127 + HelpRequiringPassphrase() + "\n"
2129 "1. newsize (numeric, optional, default=100) The new keypool size\n"
2131 + HelpExampleCli("keypoolrefill", "")
2132 + HelpExampleRpc("keypoolrefill", "")
2135 LOCK2(cs_main, pwalletMain->cs_wallet);
2137 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
2138 unsigned int kpSize = 0;
2139 if (params.size() > 0) {
2140 if (params[0].get_int() < 0)
2141 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
2142 kpSize = (unsigned int)params[0].get_int();
2145 EnsureWalletIsUnlocked();
2146 pwalletMain->TopUpKeyPool(kpSize);
2148 if (pwalletMain->GetKeyPoolSize() < kpSize)
2149 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
2151 return NullUniValue;
2155 static void LockWallet(CWallet* pWallet)
2157 LOCK(cs_nWalletUnlockTime);
2158 nWalletUnlockTime = 0;
2162 UniValue walletpassphrase(const UniValue& params, bool fHelp)
2164 if (!EnsureWalletIsAvailable(fHelp))
2165 return NullUniValue;
2167 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
2168 throw runtime_error(
2169 "walletpassphrase \"passphrase\" timeout\n"
2170 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
2171 "This is needed prior to performing transactions related to private keys such as sending " + strprintf("%s",komodo_chainname()) + "\n"
2173 "1. \"passphrase\" (string, required) The wallet passphrase\n"
2174 "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
2176 "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
2177 "time that overrides the old one.\n"
2179 "\nunlock the wallet for 60 seconds\n"
2180 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
2181 "\nLock the wallet again (before 60 seconds)\n"
2182 + HelpExampleCli("walletlock", "") +
2183 "\nAs json rpc call\n"
2184 + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
2187 LOCK2(cs_main, pwalletMain->cs_wallet);
2191 if (!pwalletMain->IsCrypted())
2192 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
2194 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
2195 SecureString strWalletPass;
2196 strWalletPass.reserve(100);
2197 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2198 // Alternately, find a way to make params[0] mlock()'d to begin with.
2199 strWalletPass = params[0].get_str().c_str();
2201 if (strWalletPass.length() > 0)
2203 if (!pwalletMain->Unlock(strWalletPass))
2204 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
2207 throw runtime_error(
2208 "walletpassphrase <passphrase> <timeout>\n"
2209 "Stores the wallet decryption key in memory for <timeout> seconds.");
2211 // No need to check return values, because the wallet was unlocked above
2212 pwalletMain->UpdateNullifierNoteMap();
2213 pwalletMain->TopUpKeyPool();
2215 int64_t nSleepTime = params[1].get_int64();
2216 LOCK(cs_nWalletUnlockTime);
2217 nWalletUnlockTime = GetTime() + nSleepTime;
2218 RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
2220 return NullUniValue;
2224 UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
2226 if (!EnsureWalletIsAvailable(fHelp))
2227 return NullUniValue;
2229 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
2230 throw runtime_error(
2231 "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
2232 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
2234 "1. \"oldpassphrase\" (string) The current passphrase\n"
2235 "2. \"newpassphrase\" (string) The new passphrase\n"
2237 + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
2238 + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
2241 LOCK2(cs_main, pwalletMain->cs_wallet);
2245 if (!pwalletMain->IsCrypted())
2246 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
2248 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
2249 // Alternately, find a way to make params[0] mlock()'d to begin with.
2250 SecureString strOldWalletPass;
2251 strOldWalletPass.reserve(100);
2252 strOldWalletPass = params[0].get_str().c_str();
2254 SecureString strNewWalletPass;
2255 strNewWalletPass.reserve(100);
2256 strNewWalletPass = params[1].get_str().c_str();
2258 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
2259 throw runtime_error(
2260 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
2261 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
2263 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
2264 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
2266 return NullUniValue;
2270 UniValue walletlock(const UniValue& params, bool fHelp)
2272 if (!EnsureWalletIsAvailable(fHelp))
2273 return NullUniValue;
2275 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
2276 throw runtime_error(
2278 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
2279 "After calling this method, you will need to call walletpassphrase again\n"
2280 "before being able to call any methods which require the wallet to be unlocked.\n"
2282 "\nSet the passphrase for 2 minutes to perform a transaction\n"
2283 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
2284 "\nPerform a send (requires passphrase set)\n"
2285 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 1.0") +
2286 "\nClear the passphrase since we are done before 2 minutes is up\n"
2287 + HelpExampleCli("walletlock", "") +
2288 "\nAs json rpc call\n"
2289 + HelpExampleRpc("walletlock", "")
2292 LOCK2(cs_main, pwalletMain->cs_wallet);
2296 if (!pwalletMain->IsCrypted())
2297 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
2300 LOCK(cs_nWalletUnlockTime);
2301 pwalletMain->Lock();
2302 nWalletUnlockTime = 0;
2305 return NullUniValue;
2309 UniValue encryptwallet(const UniValue& params, bool fHelp)
2311 if (!EnsureWalletIsAvailable(fHelp))
2312 return NullUniValue;
2314 auto fEnableWalletEncryption = fExperimentalMode && GetBoolArg("-developerencryptwallet", false);
2316 std::string strWalletEncryptionDisabledMsg = "";
2317 if (!fEnableWalletEncryption) {
2318 strWalletEncryptionDisabledMsg = "\nWARNING: Wallet encryption is DISABLED. This call always fails.\n";
2321 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
2322 throw runtime_error(
2323 "encryptwallet \"passphrase\"\n"
2324 + strWalletEncryptionDisabledMsg +
2325 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
2326 "After this, any calls that interact with private keys such as sending or signing \n"
2327 "will require the passphrase to be set prior the making these calls.\n"
2328 "Use the walletpassphrase call for this, and then walletlock call.\n"
2329 "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
2330 "Note that this will shutdown the server.\n"
2332 "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
2334 "\nEncrypt you wallet\n"
2335 + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
2336 "\nNow set the passphrase to use the wallet, such as for signing or sending " + strprintf("%s",komodo_chainname()) + "\n"
2337 + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
2338 "\nNow we can so something like sign\n"
2339 + HelpExampleCli("signmessage", "\"" + strprintf("%s",komodo_chainname()) + "_address\" \"test message\"") +
2340 "\nNow lock the wallet again by removing the passphrase\n"
2341 + HelpExampleCli("walletlock", "") +
2342 "\nAs a json rpc call\n"
2343 + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
2346 LOCK2(cs_main, pwalletMain->cs_wallet);
2350 if (!fEnableWalletEncryption) {
2351 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet encryption is disabled.");
2353 if (pwalletMain->IsCrypted())
2354 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
2356 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2357 // Alternately, find a way to make params[0] mlock()'d to begin with.
2358 SecureString strWalletPass;
2359 strWalletPass.reserve(100);
2360 strWalletPass = params[0].get_str().c_str();
2362 if (strWalletPass.length() < 1)
2363 throw runtime_error(
2364 "encryptwallet <passphrase>\n"
2365 "Encrypts the wallet with <passphrase>.");
2367 if (!pwalletMain->EncryptWallet(strWalletPass))
2368 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
2370 // BDB seems to have a bad habit of writing old data into
2371 // slack space in .dat files; that is bad if the old data is
2372 // unencrypted private keys. So:
2374 return "wallet encrypted; Komodo server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
2377 UniValue lockunspent(const UniValue& params, bool fHelp)
2379 if (!EnsureWalletIsAvailable(fHelp))
2380 return NullUniValue;
2382 if (fHelp || params.size() < 1 || params.size() > 2)
2383 throw runtime_error(
2384 "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
2385 "\nUpdates list of temporarily unspendable outputs.\n"
2386 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
2387 "A locked transaction output will not be chosen by automatic coin selection, when spending " + strprintf("%s",komodo_chainname()) + ".\n"
2388 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2389 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
2390 "Also see the listunspent call\n"
2392 "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
2393 "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
2394 " [ (json array of json objects)\n"
2396 " \"txid\":\"id\", (string) The transaction id\n"
2397 " \"vout\": n (numeric) The output number\n"
2403 "true|false (boolean) Whether the command was successful or not\n"
2406 "\nList the unspent transactions\n"
2407 + HelpExampleCli("listunspent", "") +
2408 "\nLock an unspent transaction\n"
2409 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2410 "\nList the locked transactions\n"
2411 + HelpExampleCli("listlockunspent", "") +
2412 "\nUnlock the transaction again\n"
2413 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2414 "\nAs a json rpc call\n"
2415 + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
2418 LOCK2(cs_main, pwalletMain->cs_wallet);
2420 if (params.size() == 1)
2421 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL));
2423 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
2425 bool fUnlock = params[0].get_bool();
2427 if (params.size() == 1) {
2429 pwalletMain->UnlockAllCoins();
2433 UniValue outputs = params[1].get_array();
2434 for (size_t idx = 0; idx < outputs.size(); idx++) {
2435 const UniValue& output = outputs[idx];
2436 if (!output.isObject())
2437 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
2438 const UniValue& o = output.get_obj();
2440 RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM));
2442 string txid = find_value(o, "txid").get_str();
2444 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
2446 int nOutput = find_value(o, "vout").get_int();
2448 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
2450 COutPoint outpt(uint256S(txid), nOutput);
2453 pwalletMain->UnlockCoin(outpt);
2455 pwalletMain->LockCoin(outpt);
2461 UniValue listlockunspent(const UniValue& params, bool fHelp)
2463 if (!EnsureWalletIsAvailable(fHelp))
2464 return NullUniValue;
2466 if (fHelp || params.size() > 0)
2467 throw runtime_error(
2469 "\nReturns list of temporarily unspendable outputs.\n"
2470 "See the lockunspent call to lock and unlock transactions for spending.\n"
2474 " \"txid\" : \"transactionid\", (string) The transaction id locked\n"
2475 " \"vout\" : n (numeric) The vout value\n"
2480 "\nList the unspent transactions\n"
2481 + HelpExampleCli("listunspent", "") +
2482 "\nLock an unspent transaction\n"
2483 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2484 "\nList the locked transactions\n"
2485 + HelpExampleCli("listlockunspent", "") +
2486 "\nUnlock the transaction again\n"
2487 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2488 "\nAs a json rpc call\n"
2489 + HelpExampleRpc("listlockunspent", "")
2492 LOCK2(cs_main, pwalletMain->cs_wallet);
2494 vector<COutPoint> vOutpts;
2495 pwalletMain->ListLockedCoins(vOutpts);
2497 UniValue ret(UniValue::VARR);
2499 BOOST_FOREACH(COutPoint &outpt, vOutpts) {
2500 UniValue o(UniValue::VOBJ);
2502 o.push_back(Pair("txid", outpt.hash.GetHex()));
2503 o.push_back(Pair("vout", (int)outpt.n));
2510 UniValue settxfee(const UniValue& params, bool fHelp)
2512 if (!EnsureWalletIsAvailable(fHelp))
2513 return NullUniValue;
2515 if (fHelp || params.size() < 1 || params.size() > 1)
2516 throw runtime_error(
2518 "\nSet the transaction fee per kB.\n"
2520 "1. amount (numeric, required) The transaction fee in " + strprintf("%s",komodo_chainname()) + "/kB rounded to the nearest 0.00000001\n"
2522 "true|false (boolean) Returns true if successful\n"
2524 + HelpExampleCli("settxfee", "0.00001")
2525 + HelpExampleRpc("settxfee", "0.00001")
2528 LOCK2(cs_main, pwalletMain->cs_wallet);
2531 CAmount nAmount = AmountFromValue(params[0]);
2533 payTxFee = CFeeRate(nAmount, 1000);
2537 UniValue getwalletinfo(const UniValue& params, bool fHelp)
2539 if (!EnsureWalletIsAvailable(fHelp))
2540 return NullUniValue;
2542 if (fHelp || params.size() != 0)
2543 throw runtime_error(
2545 "Returns an object containing various wallet state info.\n"
2548 " \"walletversion\": xxxxx, (numeric) the wallet version\n"
2549 " \"balance\": xxxxxxx, (numeric) the total confirmed balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
2550 " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
2551 " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
2552 " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
2553 " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
2554 " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
2555 " \"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"
2556 " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in KMD/KB\n"
2559 + HelpExampleCli("getwalletinfo", "")
2560 + HelpExampleRpc("getwalletinfo", "")
2563 LOCK2(cs_main, pwalletMain->cs_wallet);
2565 UniValue obj(UniValue::VOBJ);
2566 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
2567 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
2568 obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
2569 obj.push_back(Pair("immature_balance", ValueFromAmount(pwalletMain->GetImmatureBalance())));
2570 obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size()));
2571 obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
2572 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
2573 if (pwalletMain->IsCrypted())
2574 obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
2575 obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
2579 UniValue resendwallettransactions(const UniValue& params, bool fHelp)
2581 if (!EnsureWalletIsAvailable(fHelp))
2582 return NullUniValue;
2584 if (fHelp || params.size() != 0)
2585 throw runtime_error(
2586 "resendwallettransactions\n"
2587 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
2588 "Intended only for testing; the wallet code periodically re-broadcasts\n"
2590 "Returns array of transaction ids that were re-broadcast.\n"
2593 LOCK2(cs_main, pwalletMain->cs_wallet);
2595 std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
2596 UniValue result(UniValue::VARR);
2597 BOOST_FOREACH(const uint256& txid, txids)
2599 result.push_back(txid.ToString());
2604 UniValue listunspent(const UniValue& params, bool fHelp)
2606 if (!EnsureWalletIsAvailable(fHelp))
2607 return NullUniValue;
2609 if (fHelp || params.size() > 3)
2610 throw runtime_error(
2611 "listunspent ( minconf maxconf [\"address\",...] )\n"
2612 "\nReturns array of unspent transaction outputs\n"
2613 "with between minconf and maxconf (inclusive) confirmations.\n"
2614 "Optionally filter to only include txouts paid to specified addresses.\n"
2615 "Results are an array of Objects, each of which has:\n"
2616 "{txid, vout, scriptPubKey, amount, confirmations}\n"
2618 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
2619 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
2620 "3. \"addresses\" (string) A json array of " + strprintf("%s",komodo_chainname()) + " addresses to filter\n"
2622 " \"address\" (string) " + strprintf("%s",komodo_chainname()) + " address\n"
2626 "[ (array of json object)\n"
2628 " \"txid\" : \"txid\", (string) the transaction id \n"
2629 " \"vout\" : n, (numeric) the vout value\n"
2630 " \"generated\" : true|false (boolean) true if txout is a coinbase transaction output\n"
2631 " \"address\" : \"address\", (string) the " + strprintf("%s",komodo_chainname()) + " address\n"
2632 " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
2633 " \"scriptPubKey\" : \"key\", (string) the script key\n"
2634 " \"amount\" : x.xxx, (numeric) the transaction amount in " + strprintf("%s",komodo_chainname()) + "\n"
2635 " \"confirmations\" : n (numeric) The number of confirmations\n"
2641 + HelpExampleCli("listunspent", "")
2642 + HelpExampleCli("listunspent", "6 9999999 \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"")
2643 + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"")
2646 RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
2649 if (params.size() > 0)
2650 nMinDepth = params[0].get_int();
2652 int nMaxDepth = 9999999;
2653 if (params.size() > 1)
2654 nMaxDepth = params[1].get_int();
2656 set<CBitcoinAddress> setAddress;
2657 if (params.size() > 2) {
2658 UniValue inputs = params[2].get_array();
2659 for (size_t idx = 0; idx < inputs.size(); idx++) {
2660 const UniValue& input = inputs[idx];
2661 CBitcoinAddress address(input.get_str());
2662 if (!address.IsValid())
2663 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid " + strprintf("%s",komodo_chainname()) + " address: ")+input.get_str());
2664 if (setAddress.count(address))
2665 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
2666 setAddress.insert(address);
2670 UniValue results(UniValue::VARR);
2671 vector<COutput> vecOutputs;
2672 assert(pwalletMain != NULL);
2673 LOCK2(cs_main, pwalletMain->cs_wallet);
2674 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2675 BOOST_FOREACH(const COutput& out, vecOutputs) {
2676 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
2679 if (setAddress.size()) {
2680 CTxDestination address;
2681 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
2684 if (!setAddress.count(address))
2688 CAmount nValue = out.tx->vout[out.i].nValue;
2689 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
2690 UniValue entry(UniValue::VOBJ);
2691 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
2692 entry.push_back(Pair("vout", out.i));
2693 entry.push_back(Pair("generated", out.tx->IsCoinBase()));
2694 CTxDestination address;
2695 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
2696 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
2697 if (pwalletMain->mapAddressBook.count(address))
2698 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
2700 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
2701 if (pk.IsPayToScriptHash()) {
2702 CTxDestination address;
2703 if (ExtractDestination(pk, address)) {
2704 const CScriptID& hash = boost::get<CScriptID>(address);
2705 CScript redeemScript;
2706 if (pwalletMain->GetCScript(hash, redeemScript))
2707 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
2710 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
2711 if ( out.tx->nLockTime != 0 )
2713 BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
2714 CBlockIndex *tipindex,*pindex = it->second;
2715 uint64_t interest; uint32_t locktime; int32_t txheight;
2716 if ( pindex != 0 && (tipindex= chainActive.LastTip()) != 0 )
2718 interest = komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight);
2719 //interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime);
2720 entry.push_back(Pair("interest",ValueFromAmount(interest)));
2722 //fprintf(stderr,"nValue %.8f pindex.%p tipindex.%p locktime.%u txheight.%d pindexht.%d\n",(double)nValue/COIN,pindex,chainActive.LastTip(),locktime,txheight,pindex->nHeight);
2724 entry.push_back(Pair("confirmations",out.nDepth));
2725 entry.push_back(Pair("spendable", out.fSpendable));
2726 results.push_back(entry);
2732 uint64_t komodo_interestsum()
2734 #ifdef ENABLE_WALLET
2735 if ( GetBoolArg("-disablewallet", false) == 0 )
2737 uint64_t interest,sum = 0; int32_t txheight; uint32_t locktime;
2738 vector<COutput> vecOutputs;
2739 assert(pwalletMain != NULL);
2740 LOCK2(cs_main, pwalletMain->cs_wallet);
2741 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2742 BOOST_FOREACH(const COutput& out,vecOutputs)
2744 CAmount nValue = out.tx->vout[out.i].nValue;
2745 if ( out.tx->nLockTime != 0 && out.fSpendable != 0 )
2747 BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
2748 CBlockIndex *tipindex,*pindex = it->second;
2749 if ( pindex != 0 && (tipindex= chainActive.LastTip()) != 0 )
2751 interest = komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight);
2752 //interest = komodo_interest(pindex->nHeight,nValue,out.tx->nLockTime,tipindex->nTime);
2757 KOMODO_INTERESTSUM = sum;
2758 KOMODO_WALLETBALANCE = pwalletMain->GetBalance();
2765 UniValue fundrawtransaction(const UniValue& params, bool fHelp)
2767 if (!EnsureWalletIsAvailable(fHelp))
2768 return NullUniValue;
2770 if (fHelp || params.size() != 1)
2771 throw runtime_error(
2772 "fundrawtransaction \"hexstring\"\n"
2773 "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
2774 "This will not modify existing inputs, and will add one change output to the outputs.\n"
2775 "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
2776 "The inputs added will not be signed, use signrawtransaction for that.\n"
2778 "1. \"hexstring\" (string, required) The hex string of the raw transaction\n"
2781 " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
2782 " \"fee\": n, (numeric) The fee added to the transaction\n"
2783 " \"changepos\": n (numeric) The position of the added change output, or -1\n"
2787 "\nCreate a transaction with no inputs\n"
2788 + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
2789 "\nAdd sufficient unsigned inputs to meet the output value\n"
2790 + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
2791 "\nSign the transaction\n"
2792 + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
2793 "\nSend the transaction\n"
2794 + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
2797 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
2799 // parse hex string from parameter
2800 CTransaction origTx;
2801 if (!DecodeHexTx(origTx, params[0].get_str()))
2802 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2804 CMutableTransaction tx(origTx);
2806 string strFailReason;
2807 int nChangePos = -1;
2808 if(!pwalletMain->FundTransaction(tx, nFee, nChangePos, strFailReason))
2809 throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
2811 UniValue result(UniValue::VOBJ);
2812 result.push_back(Pair("hex", EncodeHexTx(tx)));
2813 result.push_back(Pair("changepos", nChangePos));
2814 result.push_back(Pair("fee", ValueFromAmount(nFee)));
2819 UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp)
2822 throw runtime_error(
2823 "zcsamplejoinsplit\n"
2825 "Perform a joinsplit and return the JSDescription.\n"
2832 uint256 anchor = ZCIncrementalMerkleTree().root();
2833 JSDescription samplejoinsplit(*pzcashParams,
2836 {JSInput(), JSInput()},
2837 {JSOutput(), JSOutput()},
2841 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2842 ss << samplejoinsplit;
2844 return HexStr(ss.begin(), ss.end());
2847 UniValue zc_benchmark(const UniValue& params, bool fHelp)
2849 if (!EnsureWalletIsAvailable(fHelp)) {
2850 return NullUniValue;
2853 if (fHelp || params.size() < 2) {
2854 throw runtime_error(
2855 "zcbenchmark benchmarktype samplecount\n"
2857 "Runs a benchmark of the selected type samplecount times,\n"
2858 "returning the running times of each sample.\n"
2862 " \"runningtime\": runningtime\n"
2865 " \"runningtime\": runningtime\n"
2874 std::string benchmarktype = params[0].get_str();
2875 int samplecount = params[1].get_int();
2877 if (samplecount <= 0) {
2878 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount");
2881 std::vector<double> sample_times;
2883 JSDescription samplejoinsplit;
2885 if (benchmarktype == "verifyjoinsplit") {
2886 CDataStream ss(ParseHexV(params[2].get_str(), "js"), SER_NETWORK, PROTOCOL_VERSION);
2887 ss >> samplejoinsplit;
2890 for (int i = 0; i < samplecount; i++) {
2891 if (benchmarktype == "sleep") {
2892 sample_times.push_back(benchmark_sleep());
2893 } else if (benchmarktype == "parameterloading") {
2894 sample_times.push_back(benchmark_parameter_loading());
2895 } else if (benchmarktype == "createjoinsplit") {
2896 if (params.size() < 3) {
2897 sample_times.push_back(benchmark_create_joinsplit());
2899 int nThreads = params[2].get_int();
2900 std::vector<double> vals = benchmark_create_joinsplit_threaded(nThreads);
2901 // Divide by nThreads^2 to get average seconds per JoinSplit because
2902 // we are running one JoinSplit per thread.
2903 sample_times.push_back(std::accumulate(vals.begin(), vals.end(), 0.0) / (nThreads*nThreads));
2905 } else if (benchmarktype == "verifyjoinsplit") {
2906 sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
2907 #ifdef ENABLE_MINING
2908 } else if (benchmarktype == "solveequihash") {
2909 if (params.size() < 3) {
2910 sample_times.push_back(benchmark_solve_equihash());
2912 int nThreads = params[2].get_int();
2913 std::vector<double> vals = benchmark_solve_equihash_threaded(nThreads);
2914 sample_times.insert(sample_times.end(), vals.begin(), vals.end());
2917 } else if (benchmarktype == "verifyequihash") {
2918 sample_times.push_back(benchmark_verify_equihash());
2919 } else if (benchmarktype == "validatelargetx") {
2920 // Number of inputs in the spending transaction that we will simulate
2922 if (params.size() >= 3) {
2923 nInputs = params[2].get_int();
2925 sample_times.push_back(benchmark_large_tx(nInputs));
2926 } else if (benchmarktype == "trydecryptnotes") {
2927 int nAddrs = params[2].get_int();
2928 sample_times.push_back(benchmark_try_decrypt_notes(nAddrs));
2929 } else if (benchmarktype == "incnotewitnesses") {
2930 int nTxs = params[2].get_int();
2931 sample_times.push_back(benchmark_increment_note_witnesses(nTxs));
2932 } else if (benchmarktype == "connectblockslow") {
2933 if (Params().NetworkIDString() != "regtest") {
2934 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2936 sample_times.push_back(benchmark_connectblock_slow());
2937 } else if (benchmarktype == "sendtoaddress") {
2938 if (Params().NetworkIDString() != "regtest") {
2939 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2941 auto amount = AmountFromValue(params[2]);
2942 sample_times.push_back(benchmark_sendtoaddress(amount));
2943 } else if (benchmarktype == "loadwallet") {
2944 if (Params().NetworkIDString() != "regtest") {
2945 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2947 sample_times.push_back(benchmark_loadwallet());
2948 } else if (benchmarktype == "listunspent") {
2949 sample_times.push_back(benchmark_listunspent());
2951 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
2955 UniValue results(UniValue::VARR);
2956 for (auto time : sample_times) {
2957 UniValue result(UniValue::VOBJ);
2958 result.push_back(Pair("runningtime", time));
2959 results.push_back(result);
2965 UniValue zc_raw_receive(const UniValue& params, bool fHelp)
2967 if (!EnsureWalletIsAvailable(fHelp)) {
2968 return NullUniValue;
2971 if (fHelp || params.size() != 2) {
2972 throw runtime_error(
2973 "zcrawreceive zcsecretkey encryptednote\n"
2975 "DEPRECATED. Decrypts encryptednote and checks if the coin commitments\n"
2976 "are in the blockchain as indicated by the \"exists\" result.\n"
2979 " \"amount\": value,\n"
2980 " \"note\": noteplaintext,\n"
2981 " \"exists\": exists\n"
2986 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR));
2990 CZCSpendingKey spendingkey(params[0].get_str());
2991 SpendingKey k = spendingkey.Get();
2994 unsigned char nonce;
2995 ZCNoteEncryption::Ciphertext ct;
2999 CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
3005 } catch(const std::exception &) {
3006 throw runtime_error(
3007 "encrypted_note could not be decoded"
3012 ZCNoteDecryption decryptor(k.receiving_key());
3014 NotePlaintext npt = NotePlaintext::decrypt(
3021 PaymentAddress payment_addr = k.address();
3022 Note decrypted_note = npt.note(payment_addr);
3024 assert(pwalletMain != NULL);
3025 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
3027 uint256 commitment = decrypted_note.cm();
3028 pwalletMain->WitnessNoteCommitment(
3034 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
3037 UniValue result(UniValue::VOBJ);
3038 result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value)));
3039 result.push_back(Pair("note", HexStr(ss.begin(), ss.end())));
3040 result.push_back(Pair("exists", (bool) witnesses[0]));
3046 UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
3048 if (!EnsureWalletIsAvailable(fHelp)) {
3049 return NullUniValue;
3052 if (fHelp || params.size() != 5) {
3053 throw runtime_error(
3054 "zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
3055 " inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
3056 " outputs: a JSON object mapping {zcaddr: value, ...}\n"
3058 "DEPRECATED. Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
3059 "Outputs are confidential between sender/receiver. The vpub_old and\n"
3060 "vpub_new values are globally public and move transparent value into\n"
3061 "or out of the confidential value store, respectively.\n"
3063 "Note: The caller is responsible for delivering the output enc1 and\n"
3064 "enc2 to the appropriate recipients, as well as signing rawtxout and\n"
3065 "ensuring it is mined. (A future RPC call will deliver the confidential\n"
3066 "payments in-band on the blockchain.)\n"
3069 " \"encryptednote1\": enc1,\n"
3070 " \"encryptednote2\": enc2,\n"
3071 " \"rawtxn\": rawtxout\n"
3079 if (!DecodeHexTx(tx, params[0].get_str()))
3080 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
3082 UniValue inputs = params[1].get_obj();
3083 UniValue outputs = params[2].get_obj();
3085 CAmount vpub_old(0);
3086 CAmount vpub_new(0);
3088 if (params[3].get_real() != 0.0)
3089 vpub_old = AmountFromValue(params[3]);
3091 if (params[4].get_real() != 0.0)
3092 vpub_new = AmountFromValue(params[4]);
3094 std::vector<JSInput> vjsin;
3095 std::vector<JSOutput> vjsout;
3096 std::vector<Note> notes;
3097 std::vector<SpendingKey> keys;
3098 std::vector<uint256> commitments;
3100 for (const string& name_ : inputs.getKeys()) {
3101 CZCSpendingKey spendingkey(inputs[name_].get_str());
3102 SpendingKey k = spendingkey.Get();
3109 CDataStream ssData(ParseHexV(name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
3113 PaymentAddress addr = k.address();
3114 Note note = npt.note(addr);
3115 notes.push_back(note);
3116 commitments.push_back(note.cm());
3120 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
3121 pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
3123 assert(witnesses.size() == notes.size());
3124 assert(notes.size() == keys.size());
3127 for (size_t i = 0; i < witnesses.size(); i++) {
3128 if (!witnesses[i]) {
3129 throw runtime_error(
3130 "joinsplit input could not be found in tree"
3134 vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
3138 while (vjsin.size() < ZC_NUM_JS_INPUTS) {
3139 vjsin.push_back(JSInput());
3142 for (const string& name_ : outputs.getKeys()) {
3143 CZCPaymentAddress pubaddr(name_);
3144 PaymentAddress addrTo = pubaddr.Get();
3145 CAmount nAmount = AmountFromValue(outputs[name_]);
3147 vjsout.push_back(JSOutput(addrTo, nAmount));
3150 while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
3151 vjsout.push_back(JSOutput());
3155 if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
3156 throw runtime_error("unsupported joinsplit input/output counts");
3159 uint256 joinSplitPubKey;
3160 unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
3161 crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
3163 CMutableTransaction mtx(tx);
3165 mtx.joinSplitPubKey = joinSplitPubKey;
3167 JSDescription jsdesc(*pzcashParams,
3170 {vjsin[0], vjsin[1]},
3171 {vjsout[0], vjsout[1]},
3176 auto verifier = libzcash::ProofVerifier::Strict();
3177 assert(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey));
3180 mtx.vjoinsplit.push_back(jsdesc);
3182 // Empty output script.
3184 CTransaction signTx(mtx);
3185 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
3186 uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
3188 // Add the signature
3189 assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
3190 dataToBeSigned.begin(), 32,
3195 assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
3196 dataToBeSigned.begin(), 32,
3197 mtx.joinSplitPubKey.begin()
3200 CTransaction rawTx(mtx);
3202 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
3205 std::string encryptedNote1;
3206 std::string encryptedNote2;
3208 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
3209 ss2 << ((unsigned char) 0x00);
3210 ss2 << jsdesc.ephemeralKey;
3211 ss2 << jsdesc.ciphertexts[0];
3212 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
3214 encryptedNote1 = HexStr(ss2.begin(), ss2.end());
3217 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
3218 ss2 << ((unsigned char) 0x01);
3219 ss2 << jsdesc.ephemeralKey;
3220 ss2 << jsdesc.ciphertexts[1];
3221 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
3223 encryptedNote2 = HexStr(ss2.begin(), ss2.end());
3226 UniValue result(UniValue::VOBJ);
3227 result.push_back(Pair("encryptednote1", encryptedNote1));
3228 result.push_back(Pair("encryptednote2", encryptedNote2));
3229 result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
3233 UniValue zc_raw_keygen(const UniValue& params, bool fHelp)
3235 if (!EnsureWalletIsAvailable(fHelp)) {
3236 return NullUniValue;
3239 if (fHelp || params.size() != 0) {
3240 throw runtime_error(
3243 "DEPRECATED. Generate a zcaddr which can send and receive confidential values.\n"
3246 " \"zcaddress\": zcaddr,\n"
3247 " \"zcsecretkey\": zcsecretkey,\n"
3248 " \"zcviewingkey\": zcviewingkey,\n"
3253 auto k = SpendingKey::random();
3254 auto addr = k.address();
3255 auto viewing_key = k.viewing_key();
3257 CZCPaymentAddress pubaddr(addr);
3258 CZCSpendingKey spendingkey(k);
3259 CZCViewingKey viewingkey(viewing_key);
3261 UniValue result(UniValue::VOBJ);
3262 result.push_back(Pair("zcaddress", pubaddr.ToString()));
3263 result.push_back(Pair("zcsecretkey", spendingkey.ToString()));
3264 result.push_back(Pair("zcviewingkey", viewingkey.ToString()));
3269 UniValue z_getnewaddress(const UniValue& params, bool fHelp)
3271 if (!EnsureWalletIsAvailable(fHelp))
3272 return NullUniValue;
3274 if (fHelp || params.size() > 0)
3275 throw runtime_error(
3277 "\nReturns a new zaddr for receiving payments.\n"
3280 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) The new zaddr\n"
3282 + HelpExampleCli("z_getnewaddress", "")
3283 + HelpExampleRpc("z_getnewaddress", "")
3286 LOCK2(cs_main, pwalletMain->cs_wallet);
3288 EnsureWalletIsUnlocked();
3290 CZCPaymentAddress pubaddr = pwalletMain->GenerateNewZKey();
3291 std::string result = pubaddr.ToString();
3296 UniValue z_listaddresses(const UniValue& params, bool fHelp)
3298 if (!EnsureWalletIsAvailable(fHelp))
3299 return NullUniValue;
3301 if (fHelp || params.size() > 1)
3302 throw runtime_error(
3303 "z_listaddresses ( includeWatchonly )\n"
3304 "\nReturns the list of zaddr belonging to the wallet.\n"
3306 "1. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n"
3308 "[ (json array of string)\n"
3309 " \"zaddr\" (string) a zaddr belonging to the wallet\n"
3313 + HelpExampleCli("z_listaddresses", "")
3314 + HelpExampleRpc("z_listaddresses", "")
3317 LOCK2(cs_main, pwalletMain->cs_wallet);
3319 bool fIncludeWatchonly = false;
3320 if (params.size() > 0) {
3321 fIncludeWatchonly = params[0].get_bool();
3324 UniValue ret(UniValue::VARR);
3325 std::set<libzcash::PaymentAddress> addresses;
3326 pwalletMain->GetPaymentAddresses(addresses);
3327 for (auto addr : addresses ) {
3328 if (fIncludeWatchonly || pwalletMain->HaveSpendingKey(addr)) {
3329 ret.push_back(CZCPaymentAddress(addr).ToString());
3335 CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ignoreUnspendable=true) {
3336 set<CBitcoinAddress> setAddress;
3337 vector<COutput> vecOutputs;
3338 CAmount balance = 0;
3340 if (transparentAddress.length() > 0) {
3341 CBitcoinAddress taddr = CBitcoinAddress(transparentAddress);
3342 if (!taddr.IsValid()) {
3343 throw std::runtime_error("invalid transparent address");
3345 setAddress.insert(taddr);
3348 LOCK2(cs_main, pwalletMain->cs_wallet);
3350 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
3352 BOOST_FOREACH(const COutput& out, vecOutputs) {
3353 if (out.nDepth < minDepth) {
3357 if (ignoreUnspendable && !out.fSpendable) {
3361 if (setAddress.size()) {
3362 CTxDestination address;
3363 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3367 if (!setAddress.count(address)) {
3372 CAmount nValue = out.tx->vout[out.i].nValue; // komodo_interest
3378 CAmount getBalanceZaddr(std::string address, int minDepth = 1, bool ignoreUnspendable=true) {
3379 CAmount balance = 0;
3380 std::vector<CNotePlaintextEntry> entries;
3381 LOCK2(cs_main, pwalletMain->cs_wallet);
3382 pwalletMain->GetFilteredNotes(entries, address, minDepth, true, ignoreUnspendable);
3383 for (auto & entry : entries) {
3384 balance += CAmount(entry.plaintext.value);
3390 UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
3392 if (!EnsureWalletIsAvailable(fHelp))
3393 return NullUniValue;
3395 if (fHelp || params.size()==0 || params.size() >2)
3396 throw runtime_error(
3397 "z_listreceivedbyaddress \"address\" ( minconf )\n"
3398 "\nReturn a list of amounts received by a zaddr belonging to the node’s wallet.\n"
3400 "1. \"address\" (string) The private address.\n"
3401 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3404 " \"txid\": xxxxx, (string) the transaction id\n"
3405 " \"amount\": xxxxx, (numeric) the amount of value in the note\n"
3406 " \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
3409 + HelpExampleCli("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3410 + HelpExampleRpc("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3413 LOCK2(cs_main, pwalletMain->cs_wallet);
3416 if (params.size() > 1) {
3417 nMinDepth = params[1].get_int();
3419 if (nMinDepth < 0) {
3420 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3423 // Check that the from address is valid.
3424 auto fromaddress = params[0].get_str();
3426 libzcash::PaymentAddress zaddr;
3427 CZCPaymentAddress address(fromaddress);
3429 zaddr = address.Get();
3430 } catch (const std::runtime_error&) {
3431 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
3434 if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) {
3435 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
3439 UniValue result(UniValue::VARR);
3440 std::vector<CNotePlaintextEntry> entries;
3441 pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false, false);
3442 for (CNotePlaintextEntry & entry : entries) {
3443 UniValue obj(UniValue::VOBJ);
3444 obj.push_back(Pair("txid",entry.jsop.hash.ToString()));
3445 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value))));
3446 std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end());
3447 obj.push_back(Pair("memo", HexStr(data)));
3448 result.push_back(obj);
3454 UniValue z_getbalance(const UniValue& params, bool fHelp)
3456 if (!EnsureWalletIsAvailable(fHelp))
3457 return NullUniValue;
3459 if (fHelp || params.size()==0 || params.size() >2)
3460 throw runtime_error(
3461 "z_getbalance \"address\" ( minconf )\n"
3462 "\nReturns the balance of a taddr or zaddr belonging to the node’s wallet.\n"
3463 "\nCAUTION: If address is a watch-only zaddr, the returned balance may be larger than the actual balance,"
3464 "\nbecause spends cannot be detected with incoming viewing keys.\n"
3466 "1. \"address\" (string) The selected address. It may be a transparent or private address.\n"
3467 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3469 "amount (numeric) The total amount in KMD received for this address.\n"
3471 "\nThe total amount received by address \"myaddress\"\n"
3472 + HelpExampleCli("z_getbalance", "\"myaddress\"") +
3473 "\nThe total amount received by address \"myaddress\" at least 5 blocks confirmed\n"
3474 + HelpExampleCli("z_getbalance", "\"myaddress\" 5") +
3475 "\nAs a json rpc call\n"
3476 + HelpExampleRpc("z_getbalance", "\"myaddress\", 5")
3479 LOCK2(cs_main, pwalletMain->cs_wallet);
3482 if (params.size() > 1) {
3483 nMinDepth = params[1].get_int();
3485 if (nMinDepth < 0) {
3486 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3489 // Check that the from address is valid.
3490 auto fromaddress = params[0].get_str();
3491 bool fromTaddr = false;
3492 CBitcoinAddress taddr(fromaddress);
3493 fromTaddr = taddr.IsValid();
3494 libzcash::PaymentAddress zaddr;
3496 CZCPaymentAddress address(fromaddress);
3498 zaddr = address.Get();
3499 } catch (const std::runtime_error&) {
3500 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3502 if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) {
3503 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
3507 CAmount nBalance = 0;
3509 nBalance = getBalanceTaddr(fromaddress, nMinDepth, false);
3511 nBalance = getBalanceZaddr(fromaddress, nMinDepth, false);
3514 return ValueFromAmount(nBalance);
3518 UniValue z_gettotalbalance(const UniValue& params, bool fHelp)
3520 if (!EnsureWalletIsAvailable(fHelp))
3521 return NullUniValue;
3523 if (fHelp || params.size() > 2)
3524 throw runtime_error(
3525 "z_gettotalbalance ( minconf includeWatchonly )\n"
3526 "\nReturn the total value of funds stored in the node’s wallet.\n"
3527 "\nCAUTION: If the wallet contains watch-only zaddrs, the returned private balance may be larger than the actual balance,"
3528 "\nbecause spends cannot be detected with incoming viewing keys.\n"
3530 "1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
3531 "2. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress' and 'z_importviewingkey')\n"
3534 " \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
3535 " \"private\": xxxxx, (numeric) the total balance of private funds\n"
3536 " \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n"
3539 "\nThe total amount in the wallet\n"
3540 + HelpExampleCli("z_gettotalbalance", "") +
3541 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3542 + HelpExampleCli("z_gettotalbalance", "5") +
3543 "\nAs a json rpc call\n"
3544 + HelpExampleRpc("z_gettotalbalance", "5")
3547 LOCK2(cs_main, pwalletMain->cs_wallet);
3550 if (params.size() > 0) {
3551 nMinDepth = params[0].get_int();
3553 if (nMinDepth < 0) {
3554 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3557 bool fIncludeWatchonly = false;
3558 if (params.size() > 1) {
3559 fIncludeWatchonly = params[1].get_bool();
3562 // getbalance and "getbalance * 1 true" should return the same number
3563 // but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
3564 // pwalletMain->GetBalance() does not accept min depth parameter
3565 // so we use our own method to get balance of utxos.
3566 CAmount nBalance = getBalanceTaddr("", nMinDepth, !fIncludeWatchonly);
3567 CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth, !fIncludeWatchonly);
3568 uint64_t interest = komodo_interestsum();
3569 CAmount nTotalBalance = nBalance + nPrivateBalance;
3570 UniValue result(UniValue::VOBJ);
3571 result.push_back(Pair("transparent", FormatMoney(nBalance)));
3572 result.push_back(Pair("interest", FormatMoney(interest)));
3573 result.push_back(Pair("private", FormatMoney(nPrivateBalance)));
3574 result.push_back(Pair("total", FormatMoney(nTotalBalance)));
3578 UniValue z_getoperationresult(const UniValue& params, bool fHelp)
3580 if (!EnsureWalletIsAvailable(fHelp))
3581 return NullUniValue;
3583 if (fHelp || params.size() > 1)
3584 throw runtime_error(
3585 "z_getoperationresult ([\"operationid\", ... ]) \n"
3586 "\nRetrieve the result and status of an operation which has finished, and then remove the operation from memory."
3587 + HelpRequiringPassphrase() + "\n"
3589 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3591 "\" [object, ...]\" (array) A list of JSON objects\n"
3593 + HelpExampleCli("z_getoperationresult", "'[\"operationid\", ... ]'")
3594 + HelpExampleRpc("z_getoperationresult", "'[\"operationid\", ... ]'")
3597 // This call will remove finished operations
3598 return z_getoperationstatus_IMPL(params, true);
3601 UniValue z_getoperationstatus(const UniValue& params, bool fHelp)
3603 if (!EnsureWalletIsAvailable(fHelp))
3604 return NullUniValue;
3606 if (fHelp || params.size() > 1)
3607 throw runtime_error(
3608 "z_getoperationstatus ([\"operationid\", ... ]) \n"
3609 "\nGet operation status and any associated result or error data. The operation will remain in memory."
3610 + HelpRequiringPassphrase() + "\n"
3612 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3614 "\" [object, ...]\" (array) A list of JSON objects\n"
3616 + HelpExampleCli("z_getoperationstatus", "'[\"operationid\", ... ]'")
3617 + HelpExampleRpc("z_getoperationstatus", "'[\"operationid\", ... ]'")
3620 // This call is idempotent so we don't want to remove finished operations
3621 return z_getoperationstatus_IMPL(params, false);
3624 UniValue z_getoperationstatus_IMPL(const UniValue& params, bool fRemoveFinishedOperations=false)
3626 LOCK2(cs_main, pwalletMain->cs_wallet);
3628 std::set<AsyncRPCOperationId> filter;
3629 if (params.size()==1) {
3630 UniValue ids = params[0].get_array();
3631 for (const UniValue & v : ids.getValues()) {
3632 filter.insert(v.get_str());
3635 bool useFilter = (filter.size()>0);
3637 UniValue ret(UniValue::VARR);
3638 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3639 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3641 for (auto id : ids) {
3642 if (useFilter && !filter.count(id))
3645 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3648 // It's possible that the operation was removed from the internal queue and map during this loop
3649 // throw JSONRPCError(RPC_INVALID_PARAMETER, "No operation exists for that id.");
3652 UniValue obj = operation->getStatus();
3653 std::string s = obj["status"].get_str();
3654 if (fRemoveFinishedOperations) {
3655 // Caller is only interested in retrieving finished results
3656 if ("success"==s || "failed"==s || "cancelled"==s) {
3658 q->popOperationForId(id);
3665 std::vector<UniValue> arrTmp = ret.getValues();
3667 // sort results chronologically by creation_time
3668 std::sort(arrTmp.begin(), arrTmp.end(), [](UniValue a, UniValue b) -> bool {
3669 const int64_t t1 = find_value(a.get_obj(), "creation_time").get_int64();
3670 const int64_t t2 = find_value(b.get_obj(), "creation_time").get_int64();
3676 ret.push_backV(arrTmp);
3682 // Here we define the maximum number of zaddr outputs that can be included in a transaction.
3683 // If input notes are small, we might actually require more than one joinsplit per zaddr output.
3684 // For now though, we assume we use one joinsplit per zaddr output (and the second output note is change).
3685 // We reduce the result by 1 to ensure there is room for non-joinsplit CTransaction data.
3686 #define Z_SENDMANY_MAX_ZADDR_OUTPUTS ((MAX_TX_SIZE / JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)) - 1)
3688 // transaction.h comment: spending taddr output requires CTxIn >= 148 bytes and typical taddr txout is 34 bytes
3689 #define CTXIN_SPEND_DUST_SIZE 148
3690 #define CTXOUT_REGULAR_SIZE 34
3692 UniValue z_sendmany(const UniValue& params, bool fHelp)
3694 if (!EnsureWalletIsAvailable(fHelp))
3695 return NullUniValue;
3697 if (fHelp || params.size() < 2 || params.size() > 4)
3698 throw runtime_error(
3699 "z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee )\n"
3700 "\nSend multiple times. Amounts are double-precision floating point numbers."
3701 "\nChange from a taddr flows to a new taddr address, while change from zaddr returns to itself."
3702 "\nWhen sending coinbase UTXOs to a zaddr, change is not allowed. The entire value of the UTXO(s) must be consumed."
3703 + strprintf("\nCurrently, the maximum number of zaddr outputs is %d due to transaction size limits.\n", Z_SENDMANY_MAX_ZADDR_OUTPUTS)
3704 + HelpRequiringPassphrase() + "\n"
3706 "1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from.\n"
3707 "2. \"amounts\" (array, required) An array of json objects representing the amounts to send.\n"
3709 " \"address\":address (string, required) The address is a taddr or zaddr\n"
3710 " \"amount\":amount (numeric, required) The numeric amount in KMD is the value\n"
3711 " \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
3713 "3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
3714 "4. fee (numeric, optional, default="
3715 + strprintf("%s", FormatMoney(ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
3717 "\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
3719 + HelpExampleCli("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" '[{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]'")
3720 + HelpExampleRpc("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", [{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]")
3723 LOCK2(cs_main, pwalletMain->cs_wallet);
3725 // Check that the from address is valid.
3726 auto fromaddress = params[0].get_str();
3727 bool fromTaddr = false;
3728 CBitcoinAddress taddr(fromaddress);
3729 fromTaddr = taddr.IsValid();
3730 libzcash::PaymentAddress zaddr;
3732 CZCPaymentAddress address(fromaddress);
3734 zaddr = address.Get();
3735 } catch (const std::runtime_error&) {
3737 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3741 // Check that we have the spending key
3743 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3744 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3748 UniValue outputs = params[1].get_array();
3750 if (outputs.size()==0)
3751 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
3753 // Keep track of addresses to spot duplicates
3754 set<std::string> setAddress;
3757 std::vector<SendManyRecipient> taddrRecipients;
3758 std::vector<SendManyRecipient> zaddrRecipients;
3759 CAmount nTotalOut = 0;
3761 for (const UniValue& o : outputs.getValues()) {
3763 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
3765 // sanity check, report error if unknown key-value pairs
3766 for (const string& name_ : o.getKeys()) {
3767 std::string s = name_;
3768 if (s != "address" && s != "amount" && s!="memo")
3769 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown key: ")+s);
3772 string address = find_value(o, "address").get_str();
3773 bool isZaddr = false;
3774 CBitcoinAddress taddr(address);
3775 if (!taddr.IsValid())
3778 CZCPaymentAddress zaddr(address);
3781 } catch (const std::runtime_error&) {
3782 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
3785 else if ( ASSETCHAINS_PRIVATE != 0 )
3786 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
3788 if (setAddress.count(address))
3789 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address);
3790 setAddress.insert(address);
3792 UniValue memoValue = find_value(o, "memo");
3794 if (!memoValue.isNull()) {
3795 memo = memoValue.get_str();
3797 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo cannot be used with a taddr. It can only be used with a zaddr.");
3798 } else if (!IsHex(memo)) {
3799 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
3801 if (memo.length() > ZC_MEMO_SIZE*2) {
3802 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
3806 UniValue av = find_value(o, "amount");
3807 CAmount nAmount = AmountFromValue( av );
3809 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
3812 zaddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3814 taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3817 nTotalOut += nAmount;
3820 // Check the number of zaddr outputs does not exceed the limit.
3821 if (zaddrRecipients.size() > Z_SENDMANY_MAX_ZADDR_OUTPUTS) {
3822 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, too many zaddr outputs");
3825 // As a sanity check, estimate and verify that the size of the transaction will be valid.
3826 // Depending on the input notes, the actual tx size may turn out to be larger and perhaps invalid.
3828 CMutableTransaction mtx;
3830 for (int i = 0; i < zaddrRecipients.size(); i++) {
3831 mtx.vjoinsplit.push_back(JSDescription());
3833 CTransaction tx(mtx);
3834 txsize += tx.GetSerializeSize(SER_NETWORK, tx.nVersion);
3836 txsize += CTXIN_SPEND_DUST_SIZE;
3837 txsize += CTXOUT_REGULAR_SIZE; // There will probably be taddr change
3839 txsize += CTXOUT_REGULAR_SIZE * taddrRecipients.size();
3840 if (txsize > MAX_TX_SIZE) {
3841 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Too many outputs, size of raw transaction would be larger than limit of %d bytes", MAX_TX_SIZE ));
3844 // Minimum confirmations
3846 if (params.size() > 2) {
3847 nMinDepth = params[2].get_int();
3849 if (nMinDepth < 0) {
3850 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3853 // Fee in Zatoshis, not currency format)
3854 CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE;
3855 if (params.size() > 3) {
3856 if (params[3].get_real() == 0.0) {
3859 nFee = AmountFromValue( params[3] );
3862 // Check that the user specified fee is sane.
3863 if (nFee > nTotalOut) {
3864 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the sum of outputs %s", FormatMoney(nFee), FormatMoney(nTotalOut)));
3868 // Use input parameters as the optional context info to be returned by z_getoperationstatus and z_getoperationresult.
3869 UniValue o(UniValue::VOBJ);
3870 o.push_back(Pair("fromaddress", params[0]));
3871 o.push_back(Pair("amounts", params[1]));
3872 o.push_back(Pair("minconf", nMinDepth));
3873 o.push_back(Pair("fee", std::stod(FormatMoney(nFee))));
3874 UniValue contextInfo = o;
3876 // Contextual transaction we will build on
3877 int nextBlockHeight = chainActive.Height() + 1;
3878 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextBlockHeight);
3879 bool isShielded = !fromTaddr || zaddrRecipients.size() > 0;
3880 if (contextualTx.nVersion == 1 && isShielded) {
3881 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
3883 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
3884 contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta;
3887 // Create operation and add to global queue
3888 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3889 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(contextualTx, fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee, contextInfo) );
3890 q->addOperation(operation);
3891 AsyncRPCOperationId operationId = operation->getId();
3897 When estimating the number of coinbase utxos we can shield in a single transaction:
3898 1. Joinsplit description is 1802 bytes.
3899 2. Transaction overhead ~ 100 bytes
3900 3. Spending a typical P2PKH is >=148 bytes, as defined in CTXIN_SPEND_DUST_SIZE.
3901 4. Spending a multi-sig P2SH address can vary greatly:
3902 https://github.com/bitcoin/bitcoin/blob/c3ad56f4e0b587d8d763af03d743fdfc2d180c9b/src/main.cpp#L517
3903 In real-world coinbase utxos, we consider a 3-of-3 multisig, where the size is roughly:
3904 (3*(33+1))+3 = 105 byte redeem script
3905 105 + 1 + 3*(73+1) = 328 bytes of scriptSig, rounded up to 400 based on testnet experiments.
3907 #define CTXIN_SPEND_P2SH_SIZE 400
3909 #define SHIELD_COINBASE_DEFAULT_LIMIT 50
3911 UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
3913 if (!EnsureWalletIsAvailable(fHelp))
3914 return NullUniValue;
3916 if (fHelp || params.size() < 2 || params.size() > 4)
3917 throw runtime_error(
3918 "z_shieldcoinbase \"fromaddress\" \"tozaddress\" ( fee ) ( limit )\n"
3919 "\nShield transparent coinbase funds by sending to a shielded zaddr. This is an asynchronous operation and utxos"
3920 "\nselected for shielding will be locked. If there is an error, they are unlocked. The RPC call `listlockunspent`"
3921 "\ncan be used to return a list of locked utxos. The number of coinbase utxos selected for shielding can be limited"
3922 "\nby the caller. If the limit parameter is set to zero, the -mempooltxinputlimit option will determine the number"
3923 "\nof uxtos. Any limit is constrained by the consensus rule defining a maximum transaction size of "
3924 + strprintf("%d bytes.", MAX_TX_SIZE)
3925 + HelpRequiringPassphrase() + "\n"
3927 "1. \"fromaddress\" (string, required) The address is a taddr or \"*\" for all taddrs belonging to the wallet.\n"
3928 "2. \"toaddress\" (string, required) The address is a zaddr.\n"
3929 "3. fee (numeric, optional, default="
3930 + strprintf("%s", FormatMoney(SHIELD_COINBASE_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
3931 "4. limit (numeric, optional, default="
3932 + strprintf("%d", SHIELD_COINBASE_DEFAULT_LIMIT) + ") Limit on the maximum number of utxos to shield. Set to 0 to use node option -mempooltxinputlimit.\n"
3935 " \"remainingUTXOs\": xxx (numeric) Number of coinbase utxos still available for shielding.\n"
3936 " \"remainingValue\": xxx (numeric) Value of coinbase utxos still available for shielding.\n"
3937 " \"shieldingUTXOs\": xxx (numeric) Number of coinbase utxos being shielded.\n"
3938 " \"shieldingValue\": xxx (numeric) Value of coinbase utxos being shielded.\n"
3939 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
3942 + HelpExampleCli("z_shieldcoinbase", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3943 + HelpExampleRpc("z_shieldcoinbase", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3946 LOCK2(cs_main, pwalletMain->cs_wallet);
3948 // Validate the from address
3949 auto fromaddress = params[0].get_str();
3950 bool isFromWildcard = fromaddress == "*";
3951 CBitcoinAddress taddr;
3952 if (!isFromWildcard) {
3953 taddr = CBitcoinAddress(fromaddress);
3954 if (!taddr.IsValid()) {
3955 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or \"*\".");
3959 // Validate the destination address
3960 auto destaddress = params[1].get_str();
3962 CZCPaymentAddress pa(destaddress);
3963 libzcash::PaymentAddress zaddr = pa.Get();
3964 } catch (const std::runtime_error&) {
3965 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
3968 // Convert fee from currency format to zatoshis
3969 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
3970 if (params.size() > 2) {
3971 if (params[2].get_real() == 0.0) {
3974 nFee = AmountFromValue( params[2] );
3978 int nLimit = SHIELD_COINBASE_DEFAULT_LIMIT;
3979 if (params.size() > 3) {
3980 nLimit = params[3].get_int();
3982 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of utxos cannot be negative");
3986 // Prepare to get coinbase utxos
3987 std::vector<ShieldCoinbaseUTXO> inputs;
3988 CAmount shieldedValue = 0;
3989 CAmount remainingValue = 0;
3990 size_t estimatedTxSize = 2000; // 1802 joinsplit description + tx overhead + wiggle room
3993 uint64_t utxoCounter = 0;
3995 size_t utxoCounter = 0;
3998 bool maxedOutFlag = false;
3999 size_t mempoolLimit = (nLimit != 0) ? nLimit : (size_t)GetArg("-mempooltxinputlimit", 0);
4001 // Set of addresses to filter utxos by
4002 set<CBitcoinAddress> setAddress = {};
4003 if (!isFromWildcard) {
4004 setAddress.insert(taddr);
4007 // Get available utxos
4008 vector<COutput> vecOutputs;
4009 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true);
4011 // Find unspent coinbase utxos and update estimated size
4012 BOOST_FOREACH(const COutput& out, vecOutputs) {
4013 if (!out.fSpendable) {
4017 CTxDestination address;
4018 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
4021 // If taddr is not wildcard "*", filter utxos
4022 if (setAddress.size()>0 && !setAddress.count(address)) {
4026 if (!out.tx->IsCoinBase()) {
4031 CAmount nValue = out.tx->vout[out.i].nValue;
4033 if (!maxedOutFlag) {
4034 CBitcoinAddress ba(address);
4035 size_t increase = (ba.IsScript()) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
4036 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
4037 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
4039 maxedOutFlag = true;
4041 estimatedTxSize += increase;
4042 ShieldCoinbaseUTXO utxo = {out.tx->GetHash(), out.i, nValue};
4043 inputs.push_back(utxo);
4044 shieldedValue += nValue;
4049 remainingValue += nValue;
4054 uint64_t numUtxos = inputs.size();
4056 size_t numUtxos = inputs.size();
4059 if (numUtxos == 0) {
4060 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any coinbase funds to shield.");
4063 if (shieldedValue < nFee) {
4064 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
4065 strprintf("Insufficient coinbase funds, have %s, which is less than miners fee %s",
4066 FormatMoney(shieldedValue), FormatMoney(nFee)));
4069 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
4070 CAmount netAmount = shieldedValue - nFee;
4071 if (nFee > netAmount) {
4072 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
4075 // Keep record of parameters in context object
4076 UniValue contextInfo(UniValue::VOBJ);
4077 contextInfo.push_back(Pair("fromaddress", params[0]));
4078 contextInfo.push_back(Pair("toaddress", params[1]));
4079 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
4081 // Contextual transaction we will build on
4082 int nextBlockHeight = chainActive.Height() + 1;
4083 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
4084 Params().GetConsensus(), nextBlockHeight);
4085 if (contextualTx.nVersion == 1) {
4086 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
4088 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
4089 contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta;
4092 // Create operation and add to global queue
4093 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4094 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(contextualTx, inputs, destaddress, nFee, contextInfo) );
4095 q->addOperation(operation);
4096 AsyncRPCOperationId operationId = operation->getId();
4098 // Return continuation information
4099 UniValue o(UniValue::VOBJ);
4100 o.push_back(Pair("remainingUTXOs", utxoCounter - numUtxos));
4101 o.push_back(Pair("remainingValue", ValueFromAmount(remainingValue)));
4102 o.push_back(Pair("shieldingUTXOs", numUtxos));
4103 o.push_back(Pair("shieldingValue", ValueFromAmount(shieldedValue)));
4104 o.push_back(Pair("opid", operationId));
4109 #define MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT 50
4110 #define MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT 10
4112 #define JOINSPLIT_SIZE JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)
4114 UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
4116 if (!EnsureWalletIsAvailable(fHelp))
4117 return NullUniValue;
4119 auto fEnableMergeToAddress = true; //fExperimentalMode && GetBoolArg("-zmergetoaddress", false);
4120 std::string strDisabledMsg = "";
4121 if (!fEnableMergeToAddress) {
4122 strDisabledMsg = "\nWARNING: z_mergetoaddress is DISABLED but can be enabled as an experimental feature.\n";
4125 if (fHelp || params.size() < 2 || params.size() > 6)
4126 throw runtime_error(
4127 "z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n"
4129 "\nMerge multiple UTXOs and notes into a single UTXO or note. Coinbase UTXOs are ignored; use `z_shieldcoinbase`"
4130 "\nto combine those into a single note."
4131 "\n\nThis is an asynchronous operation, and UTXOs selected for merging will be locked. If there is an error, they"
4132 "\nare unlocked. The RPC call `listlockunspent` can be used to return a list of locked UTXOs."
4133 "\n\nThe number of UTXOs and notes selected for merging can be limited by the caller. If the transparent limit"
4134 "\nparameter is set to zero, the -mempooltxinputlimit option will determine the number of UTXOs. Any limit is"
4135 "\nconstrained by the consensus rule defining a maximum transaction size of "
4136 + strprintf("%d bytes.", MAX_TX_SIZE)
4137 + HelpRequiringPassphrase() + "\n"
4139 "1. fromaddresses (string, required) A JSON array with addresses.\n"
4140 " The following special strings are accepted inside the array:\n"
4141 " - \"*\": Merge both UTXOs and notes from all addresses belonging to the wallet.\n"
4142 " - \"ANY_TADDR\": Merge UTXOs from all t-addrs belonging to the wallet.\n"
4143 " - \"ANY_ZADDR\": Merge notes from all z-addrs belonging to the wallet.\n"
4144 " If a special string is given, any given addresses of that type will be ignored.\n"
4146 " \"address\" (string) Can be a t-addr or a z-addr\n"
4149 "2. \"toaddress\" (string, required) The t-addr or z-addr to send the funds to.\n"
4150 "3. fee (numeric, optional, default="
4151 + strprintf("%s", FormatMoney(MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
4152 "4. transparent_limit (numeric, optional, default="
4153 + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT) + ") Limit on the maximum number of UTXOs to merge. Set to 0 to use node option -mempooltxinputlimit.\n"
4154 "4. shielded_limit (numeric, optional, default="
4155 + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT) + ") Limit on the maximum number of notes to merge. Set to 0 to merge as many as will fit in the transaction.\n"
4156 "5. \"memo\" (string, optional) Encoded as hex. When toaddress is a z-addr, this will be stored in the memo field of the new note.\n"
4159 " \"remainingUTXOs\": xxx (numeric) Number of UTXOs still available for merging.\n"
4160 " \"remainingTransparentValue\": xxx (numeric) Value of UTXOs still available for merging.\n"
4161 " \"remainingNotes\": xxx (numeric) Number of notes still available for merging.\n"
4162 " \"remainingShieldedValue\": xxx (numeric) Value of notes still available for merging.\n"
4163 " \"mergingUTXOs\": xxx (numeric) Number of UTXOs being merged.\n"
4164 " \"mergingTransparentValue\": xxx (numeric) Value of UTXOs being merged.\n"
4165 " \"mergingNotes\": xxx (numeric) Number of notes being merged.\n"
4166 " \"mergingShieldedValue\": xxx (numeric) Value of notes being merged.\n"
4167 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
4170 + HelpExampleCli("z_mergetoaddress", "'[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"]' ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf")
4171 + HelpExampleRpc("z_mergetoaddress", "[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"], \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
4174 if (!fEnableMergeToAddress) {
4175 throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_mergetoaddress is disabled.");
4178 LOCK2(cs_main, pwalletMain->cs_wallet);
4180 bool useAny = false;
4181 bool useAnyUTXO = false;
4182 bool useAnyNote = false;
4183 std::set<CBitcoinAddress> taddrs = {};
4184 std::set<libzcash::PaymentAddress> zaddrs = {};
4186 UniValue addresses = params[0].get_array();
4187 if (addresses.size()==0)
4188 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, fromaddresses array is empty.");
4190 // Keep track of addresses to spot duplicates
4191 std::set<std::string> setAddress;
4194 for (const UniValue& o : addresses.getValues()) {
4196 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
4198 std::string address = o.get_str();
4199 if (address == "*") {
4201 } else if (address == "ANY_TADDR") {
4203 } else if (address == "ANY_ZADDR") {
4206 CBitcoinAddress taddr(address);
4207 if (taddr.IsValid()) {
4208 // Ignore any listed t-addrs if we are using all of them
4209 if (!(useAny || useAnyUTXO)) {
4210 taddrs.insert(taddr);
4214 CZCPaymentAddress zaddr(address);
4215 // Ignore listed z-addrs if we are using all of them
4216 if (!(useAny || useAnyNote)) {
4217 zaddrs.insert(zaddr.Get());
4219 } catch (const std::runtime_error&) {
4221 RPC_INVALID_PARAMETER,
4222 string("Invalid parameter, unknown address format: ") + address);
4227 if (setAddress.count(address))
4228 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + address);
4229 setAddress.insert(address);
4232 // Validate the destination address
4233 auto destaddress = params[1].get_str();
4234 bool isToZaddr = false;
4235 CBitcoinAddress taddr(destaddress);
4236 if (!taddr.IsValid()) {
4238 CZCPaymentAddress zaddr(destaddress);
4241 } catch (const std::runtime_error&) {
4242 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
4245 else if ( ASSETCHAINS_PRIVATE != 0 )
4246 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
4248 // Convert fee from currency format to zatoshis
4249 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
4250 if (params.size() > 2) {
4251 if (params[2].get_real() == 0.0) {
4254 nFee = AmountFromValue( params[2] );
4258 int nUTXOLimit = MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT;
4259 if (params.size() > 3) {
4260 nUTXOLimit = params[3].get_int();
4261 if (nUTXOLimit < 0) {
4262 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of UTXOs cannot be negative");
4266 int nNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT;
4267 if (params.size() > 4) {
4268 nNoteLimit = params[4].get_int();
4269 if (nNoteLimit < 0) {
4270 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of notes cannot be negative");
4275 if (params.size() > 5) {
4276 memo = params[5].get_str();
4278 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
4279 } else if (!IsHex(memo)) {
4280 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
4282 if (memo.length() > ZC_MEMO_SIZE*2) {
4283 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
4287 MergeToAddressRecipient recipient(destaddress, memo);
4289 // Prepare to get UTXOs and notes
4290 std::vector<MergeToAddressInputUTXO> utxoInputs;
4291 std::vector<MergeToAddressInputNote> noteInputs;
4292 CAmount mergedUTXOValue = 0;
4293 CAmount mergedNoteValue = 0;
4294 CAmount remainingUTXOValue = 0;
4295 CAmount remainingNoteValue = 0;
4297 uint64_t utxoCounter = 0;
4298 uint64_t noteCounter = 0;
4300 size_t utxoCounter = 0;
4301 size_t noteCounter = 0;
4303 bool maxedOutUTXOsFlag = false;
4304 bool maxedOutNotesFlag = false;
4305 size_t mempoolLimit = (nUTXOLimit != 0) ? nUTXOLimit : (size_t)GetArg("-mempooltxinputlimit", 0);
4307 size_t estimatedTxSize = 200; // tx overhead + wiggle room
4309 estimatedTxSize += JOINSPLIT_SIZE;
4312 if (useAny || useAnyUTXO || taddrs.size() > 0) {
4313 // Get available utxos
4314 vector<COutput> vecOutputs;
4315 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, false);
4317 // Find unspent utxos and update estimated size
4318 for (const COutput& out : vecOutputs) {
4319 if (!out.fSpendable) {
4323 CTxDestination address;
4324 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
4327 // If taddr is not wildcard "*", filter utxos
4328 if (taddrs.size() > 0 && !taddrs.count(address)) {
4333 CAmount nValue = out.tx->vout[out.i].nValue;
4335 if (!maxedOutUTXOsFlag) {
4336 CBitcoinAddress ba(address);
4337 size_t increase = (ba.IsScript()) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
4338 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
4339 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
4341 maxedOutUTXOsFlag = true;
4343 estimatedTxSize += increase;
4344 COutPoint utxo(out.tx->GetHash(), out.i);
4345 utxoInputs.emplace_back(utxo, nValue);
4346 mergedUTXOValue += nValue;
4350 if (maxedOutUTXOsFlag) {
4351 remainingUTXOValue += nValue;
4356 if (useAny || useAnyNote || zaddrs.size() > 0) {
4357 // Get available notes
4358 std::vector<CNotePlaintextEntry> entries;
4359 pwalletMain->GetFilteredNotes(entries, zaddrs);
4361 // Find unspent notes and update estimated size
4362 for (CNotePlaintextEntry& entry : entries) {
4364 CAmount nValue = entry.plaintext.value;
4366 if (!maxedOutNotesFlag) {
4367 // If we haven't added any notes yet and the merge is to a
4368 // z-address, we have already accounted for the first JoinSplit.
4369 size_t increase = (noteInputs.empty() && !isToZaddr) || (noteInputs.size() % 2 == 0) ? JOINSPLIT_SIZE : 0;
4370 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
4371 (nNoteLimit > 0 && noteCounter > nNoteLimit))
4373 maxedOutNotesFlag = true;
4375 estimatedTxSize += increase;
4377 pwalletMain->GetSpendingKey(entry.address, zkey);
4378 noteInputs.emplace_back(entry.jsop, entry.plaintext.note(entry.address), nValue, zkey);
4379 mergedNoteValue += nValue;
4383 if (maxedOutNotesFlag) {
4384 remainingNoteValue += nValue;
4390 uint64_t numUtxos = utxoInputs.size(); //ca333
4391 uint64_t numNotes = noteInputs.size();
4393 size_t numUtxos = utxoInputs.size();
4394 size_t numNotes = noteInputs.size();
4398 if (numUtxos == 0 && numNotes == 0) {
4399 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any funds to merge.");
4402 // Sanity check: Don't do anything if:
4403 // - We only have one from address
4404 // - It's equal to toaddress
4405 // - The address only contains a single UTXO or note
4406 if (setAddress.size() == 1 && setAddress.count(destaddress) && (numUtxos + numNotes) == 1) {
4407 throw JSONRPCError(RPC_INVALID_PARAMETER, "Destination address is also the only source address, and all its funds are already merged.");
4410 CAmount mergedValue = mergedUTXOValue + mergedNoteValue;
4411 if (mergedValue < nFee) {
4412 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
4413 strprintf("Insufficient funds, have %s, which is less than miners fee %s",
4414 FormatMoney(mergedValue), FormatMoney(nFee)));
4417 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
4418 CAmount netAmount = mergedValue - nFee;
4419 if (nFee > netAmount) {
4420 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
4423 // Keep record of parameters in context object
4424 UniValue contextInfo(UniValue::VOBJ);
4425 contextInfo.push_back(Pair("fromaddresses", params[0]));
4426 contextInfo.push_back(Pair("toaddress", params[1]));
4427 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
4429 // Contextual transaction we will build on
4430 int nextBlockHeight = chainActive.Height() + 1;
4431 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
4432 Params().GetConsensus(),
4434 bool isShielded = numNotes > 0 || isToZaddr;
4435 if (contextualTx.nVersion == 1 && isShielded) {
4436 contextualTx.nVersion = 2; // Tx format should support vjoinsplit
4438 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
4439 contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta;
4442 // Create operation and add to global queue
4443 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4444 std::shared_ptr<AsyncRPCOperation> operation(
4445 new AsyncRPCOperation_mergetoaddress(contextualTx, utxoInputs, noteInputs, recipient, nFee, contextInfo) );
4446 q->addOperation(operation);
4447 AsyncRPCOperationId operationId = operation->getId();
4449 // Return continuation information
4450 UniValue o(UniValue::VOBJ);
4451 o.push_back(Pair("remainingUTXOs", utxoCounter - numUtxos));
4452 o.push_back(Pair("remainingTransparentValue", ValueFromAmount(remainingUTXOValue)));
4453 o.push_back(Pair("remainingNotes", noteCounter - numNotes));
4454 o.push_back(Pair("remainingShieldedValue", ValueFromAmount(remainingNoteValue)));
4455 o.push_back(Pair("mergingUTXOs", numUtxos));
4456 o.push_back(Pair("mergingTransparentValue", ValueFromAmount(mergedUTXOValue)));
4457 o.push_back(Pair("mergingNotes", numNotes));
4458 o.push_back(Pair("mergingShieldedValue", ValueFromAmount(mergedNoteValue)));
4459 o.push_back(Pair("opid", operationId));
4464 UniValue z_listoperationids(const UniValue& params, bool fHelp)
4466 if (!EnsureWalletIsAvailable(fHelp))
4467 return NullUniValue;
4469 if (fHelp || params.size() > 1)
4470 throw runtime_error(
4471 "z_listoperationids\n"
4472 "\nReturns the list of operation ids currently known to the wallet.\n"
4474 "1. \"status\" (string, optional) Filter result by the operation's state e.g. \"success\".\n"
4476 "[ (json array of string)\n"
4477 " \"operationid\" (string) an operation id belonging to the wallet\n"
4481 + HelpExampleCli("z_listoperationids", "")
4482 + HelpExampleRpc("z_listoperationids", "")
4485 LOCK2(cs_main, pwalletMain->cs_wallet);
4488 bool useFilter = false;
4489 if (params.size()==1) {
4490 filter = params[0].get_str();
4494 UniValue ret(UniValue::VARR);
4495 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4496 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
4497 for (auto id : ids) {
4498 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
4502 std::string state = operation->getStateAsString();
4503 if (useFilter && filter.compare(state)!=0)
4512 #include "script/sign.h"
4513 int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
4514 extern std::string NOTARY_PUBKEY;
4515 uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime,char *destaddr);
4516 int8_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256 txid,int32_t vout);
4517 int32_t komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n);
4519 int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33)
4521 set<CBitcoinAddress> setAddress; uint8_t *script,utxosig[128]; uint256 utxotxid; uint64_t utxovalue; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector<COutput> vecOutputs; uint32_t utxovout,eligible,earliest = 0; CScript best_scriptPubKey; bool fNegative,fOverflow;
4522 bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr;
4523 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
4524 const CKeyStore& keystore = *pwalletMain;
4525 assert(pwalletMain != NULL);
4526 LOCK2(cs_main, pwalletMain->cs_wallet);
4528 memset(&utxotxid,0,sizeof(utxotxid));
4529 memset(&utxovout,0,sizeof(utxovout));
4530 memset(utxosig,0,sizeof(utxosig));
4531 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
4532 BOOST_FOREACH(const COutput& out, vecOutputs)
4534 if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth )
4536 if ( setAddress.size() )
4538 CTxDestination address;
4539 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
4541 if (!setAddress.count(address))
4544 CAmount nValue = out.tx->vout[out.i].nValue;
4545 if ( nValue != 10000 )
4547 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
4548 CTxDestination address;
4549 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
4551 //entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
4552 //if (pwalletMain->mapAddressBook.count(address))
4553 // entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
4555 script = (uint8_t *)out.tx->vout[out.i].scriptPubKey.data();
4556 if ( out.tx->vout[out.i].scriptPubKey.size() != 35 || script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(notarypub33,script+1,33) != 0 )
4558 //fprintf(stderr,"scriptsize.%d [0] %02x\n",(int32_t)out.tx->vout[out.i].scriptPubKey.size(),script[0]);
4561 utxovalue = (uint64_t)nValue;
4562 //decode_hex((uint8_t *)&utxotxid,32,(char *)out.tx->GetHash().GetHex().c_str());
4563 utxotxid = out.tx->GetHash();
4565 best_scriptPubKey = out.tx->vout[out.i].scriptPubKey;
4566 //fprintf(stderr,"check %s/v%d %llu\n",(char *)utxotxid.GetHex().c_str(),utxovout,(long long)utxovalue);
4568 txNew.vin.resize(1);
4569 txNew.vout.resize(1);
4570 txfee = utxovalue / 2;
4571 //for (i=0; i<32; i++)
4572 // ((uint8_t *)&revtxid)[i] = ((uint8_t *)&utxotxid)[31 - i];
4573 txNew.vin[0].prevout.hash = utxotxid; //revtxid;
4574 txNew.vin[0].prevout.n = utxovout;
4575 txNew.vout[0].scriptPubKey = CScript() << ParseHex(CRYPTO777_PUBSECPSTR) << OP_CHECKSIG;
4576 txNew.vout[0].nValue = utxovalue - txfee;
4577 CTransaction txNewConst(txNew);
4578 signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, utxovalue, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId);
4580 fprintf(stderr,"notaryvin failed to create signature\n");
4583 UpdateTransaction(txNew,0,sigdata);
4584 ptr = (uint8_t *)sigdata.scriptSig.data();
4585 siglen = sigdata.scriptSig.size();
4586 for (i=0; i<siglen; i++)
4587 utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]);
4588 //fprintf(stderr," siglen.%d notaryvin %s/v%d\n",siglen,utxotxid.GetHex().c_str(),utxovout);
4595 struct komodo_staking
4599 arith_uint256 hashval;
4601 uint32_t segid32,txtime;
4603 CScript scriptPubKey;
4606 struct komodo_staking *komodo_addutxo(struct komodo_staking *array,int32_t *numkp,int32_t *maxkp,uint32_t txtime,uint64_t nValue,uint256 txid,int32_t vout,char *address,uint8_t *hashbuf,CScript pk)
4608 uint256 hash; uint32_t segid32; struct komodo_staking *kp;
4609 segid32 = komodo_stakehash(&hash,address,hashbuf,txid,vout);
4610 if ( *numkp >= *maxkp )
4613 array = (struct komodo_staking *)realloc(array,sizeof(*array) * (*maxkp));
4615 kp = &array[(*numkp)++];
4616 memset(kp,0,sizeof(*kp));
4617 strcpy(kp->address,address);
4620 kp->hashval = UintToArith256(hash);
4621 kp->txtime = txtime;
4622 kp->segid32 = segid32;
4623 kp->nValue = nValue;
4624 kp->scriptPubKey = pk;
4628 arith_uint256 _komodo_eligible(struct komodo_staking *kp,arith_uint256 ratio,uint32_t blocktime,int32_t iter,int32_t minage,int32_t segid,int32_t nHeight,uint32_t prevtime)
4630 int32_t diff; uint64_t coinage; arith_uint256 coinage256,hashval;
4631 diff = (iter + blocktime - kp->txtime - minage);
4634 else if ( diff > 3600*24*30 )
4638 coinage = ((uint64_t)kp->nValue/COIN * diff);
4639 if ( blocktime+iter+segid*2 > prevtime+480 )
4640 coinage *= ((blocktime+iter+segid*2) - (prevtime+400));
4641 //if ( nHeight >= 2500 && blocktime+iter+segid*2 > prevtime+180 )
4642 // coinage *= ((blocktime+iter+segid*2) - (prevtime+60));
4643 coinage256 = arith_uint256(coinage+1);
4644 hashval = ratio * (kp->hashval / coinage256);
4645 //if ( nHeight >= 900 && nHeight < 916 )
4646 // hashval = (hashval / coinage256);
4650 uint32_t komodo_eligible(arith_uint256 bnTarget,arith_uint256 ratio,struct komodo_staking *kp,int32_t nHeight,uint32_t blocktime,uint32_t prevtime,int32_t minage,uint8_t *hashbuf)
4652 int32_t maxiters = 600; uint256 hash;
4653 int32_t segid,iter,diff; uint64_t coinage; arith_uint256 hashval,coinage256;
4654 komodo_stakehash(&hash,kp->address,hashbuf,kp->txid,kp->vout);
4655 kp->hashval = UintToArith256(hash);
4656 segid = ((nHeight + kp->segid32) & 0x3f);
4657 hashval = _komodo_eligible(kp,ratio,blocktime,maxiters,minage,segid,nHeight,prevtime);
4658 //for (int i=32; i>=0; i--)
4659 // fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
4660 //fprintf(stderr," b.%u minage.%d segid.%d ht.%d prev.%u\n",blocktime,minage,segid,nHeight,prevtime);
4661 if ( hashval <= bnTarget )
4663 for (iter=0; iter<maxiters; iter++)
4665 if ( blocktime+iter+segid*2 < kp->txtime+minage )
4667 hashval = _komodo_eligible(kp,ratio,blocktime,iter,minage,segid,nHeight,prevtime);
4668 if ( hashval <= bnTarget )
4670 //fprintf(stderr,"winner %.8f blocktime.%u iter.%d segid.%d\n",(double)kp->nValue/COIN,blocktime,iter,segid);
4672 blocktime += segid * 2;
4680 int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig)
4682 static struct komodo_staking *array; static int32_t numkp,maxkp; static uint32_t lasttime;
4683 set<CBitcoinAddress> setAddress; struct komodo_staking *kp; int32_t winners,segid,minage,nHeight,counter=0,i,m,siglen=0,nMinDepth = 1,nMaxDepth = 99999999; vector<COutput> vecOutputs; uint32_t block_from_future_rejecttime,besttime,eligible,eligible2,earliest = 0; CScript best_scriptPubKey; arith_uint256 mindiff,ratio,bnTarget; CBlockIndex *tipindex,*pindex; CTxDestination address; bool fNegative,fOverflow; uint8_t hashbuf[256]; CTransaction tx; uint256 hashBlock;
4684 bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
4685 mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
4686 ratio = (mindiff / bnTarget);
4687 assert(pwalletMain != NULL);
4688 LOCK2(cs_main, pwalletMain->cs_wallet);
4690 memset(utxotxidp,0,sizeof(*utxotxidp));
4691 memset(utxovoutp,0,sizeof(*utxovoutp));
4692 memset(utxosig,0,72);
4693 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
4694 if ( (tipindex= chainActive.Tip()) == 0 )
4696 nHeight = tipindex->nHeight + 1;
4697 if ( (minage= nHeight*3) > 6000 ) // about 100 blocks
4699 komodo_segids(hashbuf,nHeight-101,100);
4700 if ( *blocktimep > tipindex->nTime+60 )
4701 *blocktimep = tipindex->nTime+60;
4702 //fprintf(stderr,"Start scan of utxo for staking %u ht.%d\n",(uint32_t)time(NULL),nHeight);
4703 if ( time(NULL) > lasttime+600 )
4712 BOOST_FOREACH(const COutput& out, vecOutputs)
4714 if ( (tipindex= chainActive.Tip()) == 0 || tipindex->nHeight+1 > nHeight )
4716 fprintf(stderr,"chain tip changed during staking loop t.%u counter.%d\n",(uint32_t)time(NULL),counter);
4720 if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth )
4722 //fprintf(stderr,"komodo_staked invalid depth %d\n",(int32_t)out.nDepth);
4725 CAmount nValue = out.tx->vout[out.i].nValue;
4726 if ( nValue < COIN || !out.fSpendable )
4728 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
4729 if ( ExtractDestination(pk,address) != 0 )
4731 if ( IsMine(*pwalletMain,address) == 0 )
4733 if ( GetTransaction(out.tx->GetHash(),tx,hashBlock,true) != 0 && (pindex= mapBlockIndex[hashBlock]) != 0 )
4735 array = komodo_addutxo(array,&numkp,&maxkp,(uint32_t)pindex->nTime,(uint64_t)nValue,out.tx->GetHash(),out.i,(char *)CBitcoinAddress(address).ToString().c_str(),hashbuf,(CScript)pk);
4739 lasttime = (uint32_t)time(NULL);
4740 //fprintf(stderr,"finished kp data of utxo for staking %u ht.%d numkp.%d maxkp.%d\n",(uint32_t)time(NULL),nHeight,numkp,maxkp);
4742 block_from_future_rejecttime = (uint32_t)GetAdjustedTime() + 57;
4743 for (i=winners=0; i<numkp; i++)
4745 if ( (tipindex= chainActive.Tip()) == 0 || tipindex->nHeight+1 > nHeight )
4747 fprintf(stderr,"chain tip changed during staking loop t.%u counter.%d\n",(uint32_t)time(NULL),counter);
4751 if ( (eligible2= komodo_eligible(bnTarget,ratio,kp,nHeight,*blocktimep,(uint32_t)tipindex->nTime+27,minage,hashbuf)) == 0 )
4753 eligible = komodo_stake(0,bnTarget,nHeight,kp->txid,kp->vout,0,(uint32_t)tipindex->nTime+27,kp->address);
4754 //fprintf(stderr,"i.%d %u vs %u\n",i,eligible2,eligible);
4758 if ( eligible == komodo_stake(1,bnTarget,nHeight,kp->txid,kp->vout,eligible,(uint32_t)tipindex->nTime+27,kp->address) )
4760 while ( eligible == komodo_stake(1,bnTarget,nHeight,kp->txid,kp->vout,eligible,(uint32_t)tipindex->nTime+27,kp->address) )
4762 besttime = eligible;
4764 if ( eligible < block_from_future_rejecttime ) // nothing gained by going earlier
4767 //fprintf(stderr,"m.%d ht.%d validated winning blocktime %u -> %.8f eligible.%u test prior\n",m,nHeight,*blocktimep,(double)kp->nValue/COIN,eligible);
4772 fprintf(stderr,"ht.%d error validating winning blocktime %u -> %.8f eligible.%u test prior\n",nHeight,*blocktimep,(double)kp->nValue/COIN,eligible);
4775 eligible = besttime;
4777 //fprintf(stderr,"ht.%d validated winning [%d] -> %.8f eligible.%u test prior\n",nHeight,(int32_t)(eligible - tipindex->nTime),(double)kp->nValue/COIN,eligible);
4778 if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || kp->nValue < *utxovaluep)) )
4780 earliest = eligible;
4781 best_scriptPubKey = kp->scriptPubKey; //out.tx->vout[out.i].scriptPubKey;
4782 *utxovaluep = (uint64_t)kp->nValue;
4783 //decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str());
4784 decode_hex((uint8_t *)utxotxidp,32,(char *)kp->txid.GetHex().c_str());
4785 *utxovoutp = kp->vout;
4786 *txtimep = kp->txtime;//(uint32_t)out.tx->nLockTime;
4787 fprintf(stderr,"ht.%d earliest.%u [%d].%d (%s) nValue %.8f locktime.%u counter.%d winners.%d\n",nHeight,earliest,(int32_t)(earliest - tipindex->nTime),m,kp->address,(double)kp->nValue/COIN,*txtimep,counter,winners);
4789 } //else fprintf(stderr,"utxo not eligible\n");
4790 } //else fprintf(stderr,"no tipindex\n");
4791 if ( numkp < 10000 && array != 0 )
4798 if ( earliest != 0 )
4800 bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid;
4801 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
4802 const CKeyStore& keystore = *pwalletMain;
4803 txNew.vin.resize(1);
4804 txNew.vout.resize(1);
4806 for (i=0; i<32; i++)
4807 ((uint8_t *)&revtxid)[i] = ((uint8_t *)utxotxidp)[31 - i];
4808 txNew.vin[0].prevout.hash = revtxid;
4809 txNew.vin[0].prevout.n = *utxovoutp;
4810 txNew.vout[0].scriptPubKey = best_scriptPubKey;// CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG;
4811 txNew.vout[0].nValue = *utxovaluep - txfee;
4812 txNew.nLockTime = earliest;
4813 CTransaction txNewConst(txNew);
4814 signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, *utxovaluep, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId);
4816 fprintf(stderr,"failed to create signature\n");
4819 UpdateTransaction(txNew,0,sigdata);
4820 ptr = (uint8_t *)sigdata.scriptSig.data();
4821 siglen = sigdata.scriptSig.size();
4822 for (i=0; i<siglen; i++)
4823 utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]);
4824 //fprintf(stderr," siglen.%d\n",siglen);
4825 //fprintf(stderr,"best %u from %u, gap %d lag.%d\n",earliest,*blocktimep,(int32_t)(earliest - *blocktimep),(int32_t)(time(NULL) - *blocktimep));
4826 *blocktimep = earliest;
4828 } //else fprintf(stderr,"no earliest utxo for staking\n");
4829 //fprintf(stderr,"end scan of utxo for staking t.%u counter.%d numkp.%d winners.%d\n",(uint32_t)time(NULL),counter,numkp,winners);
4833 UniValue getbalance64(const UniValue& params, bool fHelp)
4835 set<CBitcoinAddress> setAddress; vector<COutput> vecOutputs;
4836 UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR),b(UniValue::VARR); CTxDestination address;
4837 const CKeyStore& keystore = *pwalletMain;
4838 CAmount nValues[64],nValues2[64],nValue,total,total2; int32_t i,segid;
4839 assert(pwalletMain != NULL);
4840 if (fHelp || params.size() > 0)
4841 throw runtime_error("getbalance64\n");
4843 memset(nValues,0,sizeof(nValues));
4844 memset(nValues2,0,sizeof(nValues2));
4845 LOCK2(cs_main, pwalletMain->cs_wallet);
4846 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
4847 BOOST_FOREACH(const COutput& out, vecOutputs)
4849 nValue = out.tx->vout[out.i].nValue;
4850 if ( ExtractDestination(out.tx->vout[out.i].scriptPubKey, address) )
4852 segid = (komodo_segid32((char *)CBitcoinAddress(address).ToString().c_str()) & 0x3f);
4853 if ( out.nDepth < 100 )
4854 nValues2[segid] += nValue, total2 += nValue;
4855 else nValues[segid] += nValue, total += nValue;
4856 //fprintf(stderr,"%s %.8f depth.%d segid.%d\n",(char *)CBitcoinAddress(address).ToString().c_str(),(double)nValue/COIN,(int32_t)out.nDepth,segid);
4857 } else fprintf(stderr,"no destination\n");
4859 ret.push_back(Pair("mature",(double)total/COIN));
4860 ret.push_back(Pair("immature",(double)total2/COIN));
4861 for (i=0; i<64; i++)
4863 a.push_back((uint64_t)nValues[i]);
4864 b.push_back((uint64_t)nValues2[i]);
4866 ret.push_back(Pair("staking", a));
4867 ret.push_back(Pair("notstaking", b));