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);
48 int64_t nWalletUnlockTime;
49 static CCriticalSection cs_nWalletUnlockTime;
52 UniValue z_getoperationstatus_IMPL(const UniValue&, bool);
54 std::string HelpRequiringPassphrase()
56 return pwalletMain && pwalletMain->IsCrypted()
57 ? "\nRequires wallet passphrase to be set with walletpassphrase call."
61 bool EnsureWalletIsAvailable(bool avoidException)
66 throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
73 void EnsureWalletIsUnlocked()
75 if (pwalletMain->IsLocked())
76 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
79 uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight);
81 void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
83 //int32_t i,n,txheight; uint32_t locktime; uint64_t interest = 0;
84 int confirms = wtx.GetDepthInMainChain();
85 entry.push_back(Pair("confirmations", confirms));
87 entry.push_back(Pair("generated", true));
90 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
91 entry.push_back(Pair("blockindex", wtx.nIndex));
92 entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
93 entry.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight));
95 uint256 hash = wtx.GetHash();
96 entry.push_back(Pair("txid", hash.GetHex()));
97 UniValue conflicts(UniValue::VARR);
98 BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
99 conflicts.push_back(conflict.GetHex());
100 entry.push_back(Pair("walletconflicts", conflicts));
101 entry.push_back(Pair("time", wtx.GetTxTime()));
102 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
103 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
104 entry.push_back(Pair(item.first, item.second));
106 entry.push_back(Pair("vjoinsplit", TxJoinSplitToJSON(wtx)));
109 string AccountFromValue(const UniValue& value)
111 string strAccount = value.get_str();
112 //if (strAccount != "")
113 // throw JSONRPCError(RPC_WALLET_ACCOUNTS_UNSUPPORTED, "Accounts are unsupported");
117 char *komodo_chainname()
119 return(ASSETCHAINS_SYMBOL[0] == 0 ? (char *)"KMD" : ASSETCHAINS_SYMBOL);
122 UniValue getnewaddress(const UniValue& params, bool fHelp)
124 if (!EnsureWalletIsAvailable(fHelp))
127 if (fHelp || params.size() > 1)
129 "getnewaddress ( \"account\" )\n"
130 "\nReturns a new " + strprintf("%s",komodo_chainname()) + " address for receiving payments.\n"
132 "1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
134 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) The new " + strprintf("%s",komodo_chainname()) + " address\n"
136 + HelpExampleCli("getnewaddress", "")
137 + HelpExampleRpc("getnewaddress", "")
140 LOCK2(cs_main, pwalletMain->cs_wallet);
142 // Parse the account first so we don't generate a key if there's an error
144 if (params.size() > 0)
145 strAccount = AccountFromValue(params[0]);
147 if (!pwalletMain->IsLocked())
148 pwalletMain->TopUpKeyPool();
150 // Generate a new key that is added to wallet
152 if (!pwalletMain->GetKeyFromPool(newKey))
153 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
154 CKeyID keyID = newKey.GetID();
156 pwalletMain->SetAddressBook(keyID, strAccount, "receive");
158 return CBitcoinAddress(keyID).ToString();
162 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
164 CWalletDB walletdb(pwalletMain->strWalletFile);
167 walletdb.ReadAccount(strAccount, account);
169 bool bKeyUsed = false;
171 // Check if the current key has been used
172 if (account.vchPubKey.IsValid())
174 CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
175 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
176 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
179 const CWalletTx& wtx = (*it).second;
180 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
181 if (txout.scriptPubKey == scriptPubKey)
186 // Generate a new key
187 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
189 if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
190 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
192 pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
193 walletdb.WriteAccount(strAccount, account);
196 return CBitcoinAddress(account.vchPubKey.GetID());
199 UniValue getaccountaddress(const UniValue& params, bool fHelp)
201 if (!EnsureWalletIsAvailable(fHelp))
204 if (fHelp || params.size() != 1)
206 "getaccountaddress \"account\"\n"
207 "\nDEPRECATED. Returns the current " + strprintf("%s",komodo_chainname()) + " address for receiving payments to this account.\n"
209 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
211 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) The account " + strprintf("%s",komodo_chainname()) + " address\n"
213 + HelpExampleCli("getaccountaddress", "")
214 + HelpExampleCli("getaccountaddress", "\"\"")
215 + HelpExampleCli("getaccountaddress", "\"myaccount\"")
216 + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
219 LOCK2(cs_main, pwalletMain->cs_wallet);
221 // Parse the account first so we don't generate a key if there's an error
222 string strAccount = AccountFromValue(params[0]);
224 UniValue ret(UniValue::VSTR);
226 ret = GetAccountAddress(strAccount).ToString();
231 UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
233 if (!EnsureWalletIsAvailable(fHelp))
236 if (fHelp || params.size() > 1)
238 "getrawchangeaddress\n"
239 "\nReturns a new " + strprintf("%s",komodo_chainname()) + " address, for receiving change.\n"
240 "This is for use with raw transactions, NOT normal use.\n"
242 "\"address\" (string) The address\n"
244 + HelpExampleCli("getrawchangeaddress", "")
245 + HelpExampleRpc("getrawchangeaddress", "")
248 LOCK2(cs_main, pwalletMain->cs_wallet);
250 if (!pwalletMain->IsLocked())
251 pwalletMain->TopUpKeyPool();
253 CReserveKey reservekey(pwalletMain);
255 if (!reservekey.GetReservedKey(vchPubKey))
256 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
258 reservekey.KeepKey();
260 CKeyID keyID = vchPubKey.GetID();
262 return CBitcoinAddress(keyID).ToString();
266 UniValue setaccount(const UniValue& params, bool fHelp)
268 if (!EnsureWalletIsAvailable(fHelp))
271 if (fHelp || params.size() < 1 || params.size() > 2)
273 "setaccount \"" + strprintf("%s",komodo_chainname()) + "_address\" \"account\"\n"
274 "\nDEPRECATED. Sets the account associated with the given address.\n"
276 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to be associated with an account.\n"
277 "2. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
279 + HelpExampleCli("setaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"tabby\"")
280 + HelpExampleRpc("setaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"tabby\"")
283 LOCK2(cs_main, pwalletMain->cs_wallet);
285 CBitcoinAddress address(params[0].get_str());
286 if (!address.IsValid())
287 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
290 if (params.size() > 1)
291 strAccount = AccountFromValue(params[1]);
293 // Only add the account if the address is yours.
294 if (IsMine(*pwalletMain, address.Get()))
296 // Detect when changing the account of an address that is the 'unused current key' of another account:
297 if (pwalletMain->mapAddressBook.count(address.Get()))
299 string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name;
300 if (address == GetAccountAddress(strOldAccount))
301 GetAccountAddress(strOldAccount, true);
303 pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
306 throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
312 UniValue getaccount(const UniValue& params, bool fHelp)
314 if (!EnsureWalletIsAvailable(fHelp))
317 if (fHelp || params.size() != 1)
319 "getaccount \"" + strprintf("%s",komodo_chainname()) + "_address\"\n"
320 "\nDEPRECATED. Returns the account associated with the given address.\n"
322 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address for account lookup.\n"
324 "\"accountname\" (string) the account address\n"
326 + HelpExampleCli("getaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"")
327 + HelpExampleRpc("getaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"")
330 LOCK2(cs_main, pwalletMain->cs_wallet);
332 CBitcoinAddress address(params[0].get_str());
333 if (!address.IsValid())
334 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
337 map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
338 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty())
339 strAccount = (*mi).second.name;
344 UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
346 if (!EnsureWalletIsAvailable(fHelp))
349 if (fHelp || params.size() != 1)
351 "getaddressesbyaccount \"account\"\n"
352 "\nDEPRECATED. Returns the list of addresses for the given account.\n"
354 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
356 "[ (json array of string)\n"
357 " \"" + strprintf("%s",komodo_chainname()) + "_address\" (string) a " + strprintf("%s",komodo_chainname()) + " address associated with the given account\n"
361 + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
362 + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
365 LOCK2(cs_main, pwalletMain->cs_wallet);
367 string strAccount = AccountFromValue(params[0]);
369 // Find all addresses that have the given account
370 UniValue ret(UniValue::VARR);
371 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
373 const CBitcoinAddress& address = item.first;
374 const string& strName = item.second.name;
375 if (strName == strAccount)
376 ret.push_back(address.ToString());
381 static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew,uint8_t *opretbuf,int32_t opretlen,long int opretValue)
383 CAmount curBalance = pwalletMain->GetBalance();
387 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
389 if (nValue > curBalance)
390 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
392 // Parse Zcash address
393 CScript scriptPubKey = GetScriptForDestination(address);
395 // Create and send the transaction
396 CReserveKey reservekey(pwalletMain);
397 CAmount nFeeRequired;
398 std::string strError;
399 vector<CRecipient> vecSend;
400 int nChangePosRet = -1;
401 CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
402 vecSend.push_back(recipient);
403 if ( opretlen > 0 && opretbuf != 0 )
405 CScript opretpubkey; int32_t i; uint8_t *ptr;
406 opretpubkey.resize(opretlen);
407 ptr = (uint8_t *)opretpubkey.data();
408 for (i=0; i<opretlen; i++)
410 ptr[i] = opretbuf[i];
411 //printf("%02x",ptr[i]);
413 //printf(" opretbuf[%d]\n",opretlen);
414 CRecipient opret = { opretpubkey, opretValue, false };
415 vecSend.push_back(opret);
417 if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
418 if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
419 strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired));
420 throw JSONRPCError(RPC_WALLET_ERROR, strError);
422 if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
423 throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
426 UniValue sendtoaddress(const UniValue& params, bool fHelp)
428 if (!EnsureWalletIsAvailable(fHelp))
431 if (fHelp || params.size() < 2 || params.size() > 5)
433 "sendtoaddress \"" + strprintf("%s",komodo_chainname()) + "_address\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
434 "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
435 + HelpRequiringPassphrase() +
437 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to send to.\n"
438 "2. \"amount\" (numeric, required) The amount in " + strprintf("%s",komodo_chainname()) + " to send. eg 0.1\n"
439 "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
440 " This is not part of the transaction, just kept in your wallet.\n"
441 "4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
442 " to which you're sending the transaction. This is not part of the \n"
443 " transaction, just kept in your wallet.\n"
444 "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
445 " The recipient will receive less " + strprintf("%s",komodo_chainname()) + " than you enter in the amount field.\n"
447 "\"transactionid\" (string) The transaction id.\n"
449 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.1")
450 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.1 \"donation\" \"seans outpost\"")
451 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.1 \"\" \"\" true")
452 + HelpExampleRpc("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", 0.1, \"donation\", \"seans outpost\"")
455 LOCK2(cs_main, pwalletMain->cs_wallet);
457 CBitcoinAddress address(params[0].get_str());
458 if (!address.IsValid())
459 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
462 CAmount nAmount = AmountFromValue(params[1]);
464 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
468 if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty())
469 wtx.mapValue["comment"] = params[2].get_str();
470 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
471 wtx.mapValue["to"] = params[3].get_str();
473 bool fSubtractFeeFromAmount = false;
474 if (params.size() > 4)
475 fSubtractFeeFromAmount = params[4].get_bool();
477 EnsureWalletIsUnlocked();
479 SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, wtx,0,0,0);
481 return wtx.GetHash().GetHex();
483 #include "komodo_defs.h"
485 #define KOMODO_KVPROTECTED 1
486 #define KOMODO_KVBINARY 2
487 #define KOMODO_KVDURATION 1440
488 #define IGUANA_MAXSCRIPTSIZE 10001
489 uint64_t PAX_fiatdest(uint64_t *seedp,int32_t tokomodo,char *destaddr,uint8_t pubkey37[37],char *coinaddr,int32_t height,char *base,int64_t fiatoshis);
490 int32_t komodo_opreturnscript(uint8_t *script,uint8_t type,uint8_t *opret,int32_t opretlen);
491 #define CRYPTO777_KMDADDR "RXL3YXG2ceaB6C5hfJcN4fvmLH2C34knhA"
492 extern int32_t KOMODO_PAX;
493 extern uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE;
494 int32_t komodo_is_issuer();
495 int32_t iguana_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp);
496 int32_t komodo_isrealtime(int32_t *kmdheightp);
497 int32_t pax_fiatstatus(uint64_t *available,uint64_t *deposited,uint64_t *issued,uint64_t *withdrawn,uint64_t *approved,uint64_t *redeemed,char *base);
498 int32_t komodo_kvsearch(uint256 *refpubkeyp,int32_t current_height,uint32_t *flagsp,int32_t *heightp,uint8_t value[IGUANA_MAXSCRIPTSIZE],uint8_t *key,int32_t keylen);
499 int32_t komodo_kvcmp(uint8_t *refvalue,uint16_t refvaluesize,uint8_t *value,uint16_t valuesize);
500 uint64_t komodo_kvfee(uint32_t flags,int32_t opretlen,int32_t keylen);
501 uint256 komodo_kvsig(uint8_t *buf,int32_t len,uint256 privkey);
502 int32_t komodo_kvduration(uint32_t flags);
503 uint256 komodo_kvprivkey(uint256 *pubkeyp,char *passphrase);
504 int32_t komodo_kvsigverify(uint8_t *buf,int32_t len,uint256 _pubkey,uint256 sig);
506 UniValue kvupdate(const UniValue& params, bool fHelp)
508 static uint256 zeroes;
509 CWalletTx wtx; UniValue ret(UniValue::VOBJ);
510 uint8_t keyvalue[IGUANA_MAXSCRIPTSIZE],opretbuf[IGUANA_MAXSCRIPTSIZE]; int32_t i,coresize,haveprivkey,duration,opretlen,height; uint16_t keylen=0,valuesize=0,refvaluesize=0; uint8_t *key,*value=0; uint32_t flags,tmpflags,n; struct komodo_kv *ptr; uint64_t fee; uint256 privkey,pubkey,refpubkey,sig;
511 if (fHelp || params.size() < 3 )
512 throw runtime_error("kvupdate key value flags/passphrase");
513 if (!EnsureWalletIsAvailable(fHelp))
515 if ( ASSETCHAINS_SYMBOL[0] == 0 )
518 memset(&sig,0,sizeof(sig));
519 memset(&privkey,0,sizeof(privkey));
520 memset(&refpubkey,0,sizeof(refpubkey));
521 memset(&pubkey,0,sizeof(pubkey));
522 if ( (n= (int32_t)params.size()) >= 3 )
524 flags = atoi(params[2].get_str().c_str());
525 //printf("flags.%d (%s) n.%d\n",flags,params[2].get_str().c_str(),n);
528 privkey = komodo_kvprivkey(&pubkey,(char *)(n >= 4 ? params[3].get_str().c_str() : "password"));
531 /*for (i=0; i<32; i++)
532 printf("%02x",((uint8_t *)&privkey)[i]);
535 printf("%02x",((uint8_t *)&pubkey)[i]);
536 printf(" pubkey, privkey derived from (%s)\n",(char *)params[3].get_str().c_str());
538 LOCK2(cs_main, pwalletMain->cs_wallet);
539 if ( (keylen= (int32_t)strlen(params[0].get_str().c_str())) > 0 )
541 key = (uint8_t *)params[0].get_str().c_str();
542 if ( n >= 2 && params[1].get_str().c_str() != 0 )
544 value = (uint8_t *)params[1].get_str().c_str();
545 valuesize = (int32_t)strlen(params[1].get_str().c_str());
547 memcpy(keyvalue,key,keylen);
548 if ( (refvaluesize= komodo_kvsearch(&refpubkey,chainActive.Tip()->nHeight,&tmpflags,&height,&keyvalue[keylen],key,keylen)) >= 0 )
550 if ( (tmpflags & KOMODO_KVPROTECTED) != 0 )
552 if ( memcmp(&refpubkey,&pubkey,sizeof(refpubkey)) != 0 )
554 ret.push_back(Pair("error",(char *)"cant modify write once key without passphrase"));
558 if ( keylen+refvaluesize <= sizeof(keyvalue) )
560 sig = komodo_kvsig(keyvalue,keylen+refvaluesize,privkey);
561 if ( komodo_kvsigverify(keyvalue,keylen+refvaluesize,refpubkey,sig) < 0 )
563 ret.push_back(Pair("error",(char *)"error verifying sig, passphrase is probably wrong"));
564 printf("VERIFY ERROR\n");
566 } // else printf("verified immediately\n");
569 //for (i=0; i<32; i++)
570 // printf("%02x",((uint8_t *)&sig)[i]);
571 //printf(" sig for keylen.%d + valuesize.%d\n",keylen,refvaluesize);
572 ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)));
573 height = chainActive.Tip()->nHeight;
574 if ( memcmp(&zeroes,&refpubkey,sizeof(refpubkey)) != 0 )
575 ret.push_back(Pair("owner",refpubkey.GetHex()));
576 ret.push_back(Pair("height", (int64_t)height));
577 duration = komodo_kvduration(flags); //((flags >> 2) + 1) * KOMODO_KVDURATION;
578 ret.push_back(Pair("expiration", (int64_t)(height+duration)));
579 ret.push_back(Pair("flags",(int64_t)flags));
580 ret.push_back(Pair("key",params[0].get_str()));
581 ret.push_back(Pair("keylen",(int64_t)keylen));
582 if ( n >= 2 && params[1].get_str().c_str() != 0 )
584 ret.push_back(Pair("value",params[1].get_str()));
585 ret.push_back(Pair("valuesize",valuesize));
587 iguana_rwnum(1,&keyvalue[0],sizeof(keylen),&keylen);
588 iguana_rwnum(1,&keyvalue[2],sizeof(valuesize),&valuesize);
589 iguana_rwnum(1,&keyvalue[4],sizeof(height),&height);
590 iguana_rwnum(1,&keyvalue[8],sizeof(flags),&flags);
591 memcpy(&keyvalue[12],key,keylen);
593 memcpy(&keyvalue[12 + keylen],value,valuesize);
594 coresize = (int32_t)(sizeof(flags)+sizeof(height)+sizeof(uint16_t)*2+keylen+valuesize);
595 if ( haveprivkey != 0 )
598 keyvalue[12 + keylen + valuesize + i] = ((uint8_t *)&pubkey)[i];
600 if ( refvaluesize >=0 )
603 keyvalue[12 + keylen + valuesize + 32 + i] = ((uint8_t *)&sig)[i];
607 if ( (opretlen= komodo_opreturnscript(opretbuf,'K',keyvalue,coresize)) == 40 )
609 //for (i=0; i<opretlen; i++)
610 // printf("%02x",opretbuf[i]);
611 //printf(" opretbuf keylen.%d valuesize.%d height.%d (%02x %02x %02x)\n",*(uint16_t *)&keyvalue[0],*(uint16_t *)&keyvalue[2],*(uint32_t *)&keyvalue[4],keyvalue[8],keyvalue[9],keyvalue[10]);
612 EnsureWalletIsUnlocked();
613 fee = komodo_kvfee(flags,opretlen,keylen);
614 ret.push_back(Pair("fee",(double)fee/COIN));
615 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
616 if (!destaddress.IsValid())
617 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
618 SendMoney(destaddress.Get(),10000,false,wtx,opretbuf,opretlen,fee);
619 ret.push_back(Pair("txid",wtx.GetHash().GetHex()));
620 } else ret.push_back(Pair("error",(char *)"null key"));
624 UniValue paxdeposit(const UniValue& params, bool fHelp)
626 uint64_t available,deposited,issued,withdrawn,approved,redeemed,seed,komodoshis = 0; int32_t height; char destaddr[64]; uint8_t i,pubkey37[33];
627 bool fSubtractFeeFromAmount = false;
628 if ( KOMODO_PAX == 0 )
630 throw runtime_error("paxdeposit disabled without -pax");
632 if ( komodo_is_issuer() != 0 )
633 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "paxdeposit only from KMD");
634 if (!EnsureWalletIsAvailable(fHelp))
635 throw runtime_error("paxdeposit needs wallet"); //return Value::null;
636 if (fHelp || params.size() != 3)
637 throw runtime_error("paxdeposit address fiatoshis base");
638 LOCK2(cs_main, pwalletMain->cs_wallet);
639 CBitcoinAddress address(params[0].get_str());
640 if (!address.IsValid())
641 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
642 int64_t fiatoshis = atof(params[1].get_str().c_str()) * COIN;
643 std::string base = params[2].get_str();
645 height = chainActive.Tip()->nHeight;
646 if ( pax_fiatstatus(&available,&deposited,&issued,&withdrawn,&approved,&redeemed,(char *)base.c_str()) != 0 || available < fiatoshis )
648 fprintf(stderr,"available %llu vs fiatoshis %llu\n",(long long)available,(long long)fiatoshis);
649 throw runtime_error("paxdeposit not enough available inventory");
651 komodoshis = PAX_fiatdest(&seed,0,destaddr,pubkey37,(char *)params[0].get_str().c_str(),height,(char *)base.c_str(),fiatoshis);
652 dest.append(destaddr);
653 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
654 if (!destaddress.IsValid())
655 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
657 fprintf(stderr,"%02x",pubkey37[i]);
658 fprintf(stderr," ht.%d srcaddr.(%s) %s fiatoshis.%lld -> dest.(%s) komodoshis.%llu seed.%llx\n",height,(char *)params[0].get_str().c_str(),(char *)base.c_str(),(long long)fiatoshis,destaddr,(long long)komodoshis,(long long)seed);
659 EnsureWalletIsUnlocked();
661 uint8_t opretbuf[64]; int32_t opretlen; uint64_t fee = komodoshis / 1000;
664 iguana_rwnum(1,&pubkey37[33],sizeof(height),&height);
665 opretlen = komodo_opreturnscript(opretbuf,'D',pubkey37,37);
666 SendMoney(address.Get(),fee,fSubtractFeeFromAmount,wtx,opretbuf,opretlen,komodoshis);
667 return wtx.GetHash().GetHex();
670 UniValue paxwithdraw(const UniValue& params, bool fHelp)
672 CWalletTx wtx; std::string dest; int32_t kmdheight; uint64_t seed,komodoshis = 0; char destaddr[64]; uint8_t i,pubkey37[37]; bool fSubtractFeeFromAmount = false;
673 if ( ASSETCHAINS_SYMBOL[0] == 0 )
675 if (!EnsureWalletIsAvailable(fHelp))
677 throw runtime_error("paxwithdraw deprecated");
678 if (fHelp || params.size() != 2)
679 throw runtime_error("paxwithdraw address fiatamount");
680 if ( komodo_isrealtime(&kmdheight) == 0 )
682 LOCK2(cs_main, pwalletMain->cs_wallet);
683 CBitcoinAddress address(params[0].get_str());
684 if (!address.IsValid())
685 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
686 int64_t fiatoshis = atof(params[1].get_str().c_str()) * COIN;
687 komodoshis = PAX_fiatdest(&seed,1,destaddr,pubkey37,(char *)params[0].get_str().c_str(),kmdheight,ASSETCHAINS_SYMBOL,fiatoshis);
688 dest.append(destaddr);
689 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
690 if (!destaddress.IsValid())
691 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
693 printf("%02x",pubkey37[i]);
694 printf(" kmdheight.%d srcaddr.(%s) %s fiatoshis.%lld -> dest.(%s) komodoshis.%llu seed.%llx\n",kmdheight,(char *)params[0].get_str().c_str(),ASSETCHAINS_SYMBOL,(long long)fiatoshis,destaddr,(long long)komodoshis,(long long)seed);
695 EnsureWalletIsUnlocked();
696 uint8_t opretbuf[64]; int32_t opretlen; uint64_t fee = fiatoshis / 1000;
699 iguana_rwnum(1,&pubkey37[33],sizeof(kmdheight),&kmdheight);
700 opretlen = komodo_opreturnscript(opretbuf,'W',pubkey37,37);
701 SendMoney(destaddress.Get(),fee,fSubtractFeeFromAmount,wtx,opretbuf,opretlen,fiatoshis);
702 return wtx.GetHash().GetHex();
705 UniValue listaddressgroupings(const UniValue& params, bool fHelp)
707 if (!EnsureWalletIsAvailable(fHelp))
712 "listaddressgroupings\n"
713 "\nLists groups of addresses which have had their common ownership\n"
714 "made public by common use as inputs or as the resulting change\n"
715 "in past transactions\n"
720 " \"" + strprintf("%s",komodo_chainname()) + " address\", (string) The " + strprintf("%s",komodo_chainname()) + " address\n"
721 " amount, (numeric) The amount in " + strprintf("%s",komodo_chainname()) + "\n"
722 " \"account\" (string, optional) The account (DEPRECATED)\n"
729 + HelpExampleCli("listaddressgroupings", "")
730 + HelpExampleRpc("listaddressgroupings", "")
733 LOCK2(cs_main, pwalletMain->cs_wallet);
735 UniValue jsonGroupings(UniValue::VARR);
736 map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
737 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
739 UniValue jsonGrouping(UniValue::VARR);
740 BOOST_FOREACH(CTxDestination address, grouping)
742 UniValue addressInfo(UniValue::VARR);
743 addressInfo.push_back(CBitcoinAddress(address).ToString());
744 addressInfo.push_back(ValueFromAmount(balances[address]));
746 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
747 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
749 jsonGrouping.push_back(addressInfo);
751 jsonGroupings.push_back(jsonGrouping);
753 return jsonGroupings;
756 UniValue signmessage(const UniValue& params, bool fHelp)
758 if (!EnsureWalletIsAvailable(fHelp))
761 if (fHelp || params.size() != 2)
763 "signmessage \"" + strprintf("%s",komodo_chainname()) + " address\" \"message\"\n"
764 "\nSign a message with the private key of an address"
765 + HelpRequiringPassphrase() + "\n"
767 "1. \"" + strprintf("%s",komodo_chainname()) + " address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to use for the private key.\n"
768 "2. \"message\" (string, required) The message to create a signature of.\n"
770 "\"signature\" (string) The signature of the message encoded in base 64\n"
772 "\nUnlock the wallet for 30 seconds\n"
773 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
774 "\nCreate the signature\n"
775 + HelpExampleCli("signmessage", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"my message\"") +
776 "\nVerify the signature\n"
777 + HelpExampleCli("verifymessage", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"signature\" \"my message\"") +
779 + HelpExampleRpc("signmessage", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"my message\"")
782 LOCK2(cs_main, pwalletMain->cs_wallet);
784 EnsureWalletIsUnlocked();
786 string strAddress = params[0].get_str();
787 string strMessage = params[1].get_str();
789 CBitcoinAddress addr(strAddress);
791 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
794 if (!addr.GetKeyID(keyID))
795 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
798 if (!pwalletMain->GetKey(keyID, key))
799 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
801 CHashWriter ss(SER_GETHASH, 0);
802 ss << strMessageMagic;
805 vector<unsigned char> vchSig;
806 if (!key.SignCompact(ss.GetHash(), vchSig))
807 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
809 return EncodeBase64(&vchSig[0], vchSig.size());
812 UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
814 if (!EnsureWalletIsAvailable(fHelp))
817 if (fHelp || params.size() < 1 || params.size() > 2)
819 "getreceivedbyaddress \"" + strprintf("%s",komodo_chainname()) + "_address\" ( minconf )\n"
820 "\nReturns the total amount received by the given " + strprintf("%s",komodo_chainname()) + " address in transactions with at least minconf confirmations.\n"
822 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address for transactions.\n"
823 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
825 "amount (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received at this address.\n"
827 "\nThe amount from transactions with at least 1 confirmation\n"
828 + HelpExampleCli("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"") +
829 "\nThe amount including unconfirmed transactions, zero confirmations\n"
830 + HelpExampleCli("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0") +
831 "\nThe amount with at least 6 confirmations, very safe\n"
832 + HelpExampleCli("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 6") +
833 "\nAs a json rpc call\n"
834 + HelpExampleRpc("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", 6")
837 LOCK2(cs_main, pwalletMain->cs_wallet);
840 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
841 if (!address.IsValid())
842 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
843 CScript scriptPubKey = GetScriptForDestination(address.Get());
844 if (!IsMine(*pwalletMain,scriptPubKey))
847 // Minimum confirmations
849 if (params.size() > 1)
850 nMinDepth = params[1].get_int();
854 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
856 const CWalletTx& wtx = (*it).second;
857 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
860 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
861 if (txout.scriptPubKey == scriptPubKey)
862 if (wtx.GetDepthInMainChain() >= nMinDepth)
863 nAmount += txout.nValue; // komodo_interest?
866 return ValueFromAmount(nAmount);
870 UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
872 if (!EnsureWalletIsAvailable(fHelp))
875 if (fHelp || params.size() < 1 || params.size() > 2)
877 "getreceivedbyaccount \"account\" ( minconf )\n"
878 "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
880 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
881 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
883 "amount (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received for this account.\n"
885 "\nAmount received by the default account with at least 1 confirmation\n"
886 + HelpExampleCli("getreceivedbyaccount", "\"\"") +
887 "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
888 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
889 "\nThe amount with at least 6 confirmation, very safe\n"
890 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
891 "\nAs a json rpc call\n"
892 + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
895 LOCK2(cs_main, pwalletMain->cs_wallet);
897 // Minimum confirmations
899 if (params.size() > 1)
900 nMinDepth = params[1].get_int();
902 // Get the set of pub keys assigned to account
903 string strAccount = AccountFromValue(params[0]);
904 set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
908 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
910 const CWalletTx& wtx = (*it).second;
911 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
914 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
916 CTxDestination address;
917 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
918 if (wtx.GetDepthInMainChain() >= nMinDepth)
919 nAmount += txout.nValue; // komodo_interest?
923 return (double)nAmount / (double)COIN;
927 CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
929 CAmount nBalance = 0;
931 // Tally wallet transactions
932 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
934 const CWalletTx& wtx = (*it).second;
935 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
938 CAmount nReceived, nSent, nFee;
939 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
941 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
942 nBalance += nReceived;
943 nBalance -= nSent + nFee;
946 // Tally internal accounting entries
947 nBalance += walletdb.GetAccountCreditDebit(strAccount);
952 CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
954 CWalletDB walletdb(pwalletMain->strWalletFile);
955 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
959 UniValue getbalance(const UniValue& params, bool fHelp)
961 if (!EnsureWalletIsAvailable(fHelp))
964 if (fHelp || params.size() > 3)
966 "getbalance ( \"account\" minconf includeWatchonly )\n"
967 "\nReturns the server's total available balance.\n"
969 "1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" or to the string \"*\", either of which will give the total available balance. Passing any other string will result in an error.\n"
970 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
971 "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
973 "amount (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received for this account.\n"
975 "\nThe total amount in the wallet\n"
976 + HelpExampleCli("getbalance", "") +
977 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
978 + HelpExampleCli("getbalance", "\"*\" 6") +
979 "\nAs a json rpc call\n"
980 + HelpExampleRpc("getbalance", "\"*\", 6")
983 LOCK2(cs_main, pwalletMain->cs_wallet);
985 if (params.size() == 0)
986 return ValueFromAmount(pwalletMain->GetBalance());
989 if (params.size() > 1)
990 nMinDepth = params[1].get_int();
991 isminefilter filter = ISMINE_SPENDABLE;
992 if(params.size() > 2)
993 if(params[2].get_bool())
994 filter = filter | ISMINE_WATCH_ONLY;
996 if (params[0].get_str() == "*") {
997 // Calculate total balance a different way from GetBalance()
998 // (GetBalance() sums up all unspent TxOuts)
999 // getbalance and "getbalance * 1 true" should return the same number
1000 CAmount nBalance = 0;
1001 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1003 const CWalletTx& wtx = (*it).second;
1004 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
1008 string strSentAccount;
1009 list<COutputEntry> listReceived;
1010 list<COutputEntry> listSent;
1011 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
1012 if (wtx.GetDepthInMainChain() >= nMinDepth)
1014 BOOST_FOREACH(const COutputEntry& r, listReceived)
1015 nBalance += r.amount;
1017 BOOST_FOREACH(const COutputEntry& s, listSent)
1018 nBalance -= s.amount;
1021 return ValueFromAmount(nBalance);
1024 string strAccount = AccountFromValue(params[0]);
1026 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
1028 return ValueFromAmount(nBalance);
1031 UniValue getunconfirmedbalance(const UniValue ¶ms, bool fHelp)
1033 if (!EnsureWalletIsAvailable(fHelp))
1034 return NullUniValue;
1036 if (fHelp || params.size() > 0)
1037 throw runtime_error(
1038 "getunconfirmedbalance\n"
1039 "Returns the server's total unconfirmed balance\n");
1041 LOCK2(cs_main, pwalletMain->cs_wallet);
1043 return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
1047 UniValue movecmd(const UniValue& params, bool fHelp)
1049 if (!EnsureWalletIsAvailable(fHelp))
1050 return NullUniValue;
1052 if (fHelp || params.size() < 3 || params.size() > 5)
1053 throw runtime_error(
1054 "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
1055 "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
1057 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1058 "2. \"toaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1059 "3. amount (numeric) Quantity of " + strprintf("%s",komodo_chainname()) + " to move between accounts.\n"
1060 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
1061 "5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
1063 "true|false (boolean) true if successful.\n"
1065 "\nMove 0.01 " + strprintf("%s",komodo_chainname()) + " from the default account to the account named tabby\n"
1066 + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
1067 "\nMove 0.01 " + strprintf("%s",komodo_chainname()) + " timotei to akiko with a comment and funds have 6 confirmations\n"
1068 + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
1069 "\nAs a json rpc call\n"
1070 + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
1073 LOCK2(cs_main, pwalletMain->cs_wallet);
1075 string strFrom = AccountFromValue(params[0]);
1076 string strTo = AccountFromValue(params[1]);
1077 CAmount nAmount = AmountFromValue(params[2]);
1079 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1080 if (params.size() > 3)
1081 // unused parameter, used to be nMinDepth, keep type-checking it though
1082 (void)params[3].get_int();
1084 if (params.size() > 4)
1085 strComment = params[4].get_str();
1087 CWalletDB walletdb(pwalletMain->strWalletFile);
1088 if (!walletdb.TxnBegin())
1089 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
1091 int64_t nNow = GetAdjustedTime();
1094 CAccountingEntry debit;
1095 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
1096 debit.strAccount = strFrom;
1097 debit.nCreditDebit = -nAmount;
1099 debit.strOtherAccount = strTo;
1100 debit.strComment = strComment;
1101 walletdb.WriteAccountingEntry(debit);
1104 CAccountingEntry credit;
1105 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
1106 credit.strAccount = strTo;
1107 credit.nCreditDebit = nAmount;
1108 credit.nTime = nNow;
1109 credit.strOtherAccount = strFrom;
1110 credit.strComment = strComment;
1111 walletdb.WriteAccountingEntry(credit);
1113 if (!walletdb.TxnCommit())
1114 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
1120 UniValue sendfrom(const UniValue& params, bool fHelp)
1122 if (!EnsureWalletIsAvailable(fHelp))
1123 return NullUniValue;
1125 if (fHelp || params.size() < 3 || params.size() > 6)
1126 throw runtime_error(
1127 "sendfrom \"fromaccount\" \"to" + strprintf("%s",komodo_chainname()) + "address\" amount ( minconf \"comment\" \"comment-to\" )\n"
1128 "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a " + strprintf("%s",komodo_chainname()) + " address.\n"
1129 "The amount is a real and is rounded to the nearest 0.00000001."
1130 + HelpRequiringPassphrase() + "\n"
1132 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1133 "2. \"to" + strprintf("%s",komodo_chainname()) + "address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to send funds to.\n"
1134 "3. amount (numeric, required) The amount in " + strprintf("%s",komodo_chainname()) + " (transaction fee is added on top).\n"
1135 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
1136 "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
1137 " This is not part of the transaction, just kept in your wallet.\n"
1138 "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n"
1139 " to which you're sending the transaction. This is not part of the transaction, \n"
1140 " it is just kept in your wallet.\n"
1142 "\"transactionid\" (string) The transaction id.\n"
1144 "\nSend 0.01 " + strprintf("%s",komodo_chainname()) + " from the default account to the address, must have at least 1 confirmation\n"
1145 + HelpExampleCli("sendfrom", "\"\" \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.01") +
1146 "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
1147 + HelpExampleCli("sendfrom", "\"tabby\" \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.01 6 \"donation\" \"seans outpost\"") +
1148 "\nAs a json rpc call\n"
1149 + HelpExampleRpc("sendfrom", "\"tabby\", \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", 0.01, 6, \"donation\", \"seans outpost\"")
1152 LOCK2(cs_main, pwalletMain->cs_wallet);
1154 string strAccount = AccountFromValue(params[0]);
1155 CBitcoinAddress address(params[1].get_str());
1156 if (!address.IsValid())
1157 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
1158 CAmount nAmount = AmountFromValue(params[2]);
1160 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1162 if (params.size() > 3)
1163 nMinDepth = params[3].get_int();
1166 wtx.strFromAccount = strAccount;
1167 if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty())
1168 wtx.mapValue["comment"] = params[4].get_str();
1169 if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty())
1170 wtx.mapValue["to"] = params[5].get_str();
1172 EnsureWalletIsUnlocked();
1175 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
1176 if (nAmount > nBalance)
1177 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
1179 SendMoney(address.Get(), nAmount, false, wtx,0,0,0);
1181 return wtx.GetHash().GetHex();
1185 UniValue sendmany(const UniValue& params, bool fHelp)
1187 if (!EnsureWalletIsAvailable(fHelp))
1188 return NullUniValue;
1190 if (fHelp || params.size() < 2 || params.size() > 5)
1191 throw runtime_error(
1192 "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
1193 "\nSend multiple times. Amounts are double-precision floating point numbers."
1194 + HelpRequiringPassphrase() + "\n"
1196 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1197 "2. \"amounts\" (string, required) A json object with addresses and amounts\n"
1199 " \"address\":amount (numeric) The " + strprintf("%s",komodo_chainname()) + " address is the key, the numeric amount in " + strprintf("%s",komodo_chainname()) + " is the value\n"
1202 "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
1203 "4. \"comment\" (string, optional) A comment\n"
1204 "5. subtractfeefromamount (string, optional) A json array with addresses.\n"
1205 " The fee will be equally deducted from the amount of each selected address.\n"
1206 " Those recipients will receive less " + strprintf("%s",komodo_chainname()) + " than you enter in their corresponding amount field.\n"
1207 " If no addresses are specified here, the sender pays the fee.\n"
1209 " \"address\" (string) Subtract fee from this address\n"
1213 "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
1214 " the number of addresses.\n"
1216 "\nSend two amounts to two different addresses:\n"
1217 + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\"") +
1218 "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
1219 + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\" 6 \"testing\"") +
1220 "\nSend two amounts to two different addresses, subtract fee from amount:\n"
1221 + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\" 1 \"\" \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"") +
1222 "\nAs a json rpc call\n"
1223 + HelpExampleRpc("sendmany", "\"\", \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\", 6, \"testing\"")
1226 LOCK2(cs_main, pwalletMain->cs_wallet);
1228 string strAccount = AccountFromValue(params[0]);
1229 UniValue sendTo = params[1].get_obj();
1231 if (params.size() > 2)
1232 nMinDepth = params[2].get_int();
1235 wtx.strFromAccount = strAccount;
1236 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
1237 wtx.mapValue["comment"] = params[3].get_str();
1239 UniValue subtractFeeFromAmount(UniValue::VARR);
1240 if (params.size() > 4)
1241 subtractFeeFromAmount = params[4].get_array();
1243 set<CBitcoinAddress> setAddress;
1244 vector<CRecipient> vecSend;
1246 CAmount totalAmount = 0;
1247 vector<string> keys = sendTo.getKeys();
1248 BOOST_FOREACH(const string& name_, keys)
1250 CBitcoinAddress address(name_);
1251 if (!address.IsValid())
1252 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid " + strprintf("%s",komodo_chainname()) + " address: ")+name_);
1254 //if (setAddress.count(address))
1255 // throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
1256 setAddress.insert(address);
1258 CScript scriptPubKey = GetScriptForDestination(address.Get());
1259 CAmount nAmount = AmountFromValue(sendTo[name_]);
1261 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1262 totalAmount += nAmount;
1264 bool fSubtractFeeFromAmount = false;
1265 for (size_t idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
1266 const UniValue& addr = subtractFeeFromAmount[idx];
1267 if (addr.get_str() == name_)
1268 fSubtractFeeFromAmount = true;
1271 CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
1272 vecSend.push_back(recipient);
1275 EnsureWalletIsUnlocked();
1278 CAmount nBalance = pwalletMain->GetBalance();
1279 //CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
1280 if (totalAmount > nBalance)
1281 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
1284 CReserveKey keyChange(pwalletMain);
1285 CAmount nFeeRequired = 0;
1286 int nChangePosRet = -1;
1287 string strFailReason;
1288 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
1290 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
1291 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1292 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
1294 return wtx.GetHash().GetHex();
1297 // Defined in rpcmisc.cpp
1298 extern CScript _createmultisig_redeemScript(const UniValue& params);
1300 UniValue addmultisigaddress(const UniValue& params, bool fHelp)
1302 if (!EnsureWalletIsAvailable(fHelp))
1303 return NullUniValue;
1305 if (fHelp || params.size() < 2 || params.size() > 3)
1307 string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
1308 "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
1309 "Each key is a " + strprintf("%s",komodo_chainname()) + " address or hex-encoded public key.\n"
1310 "If 'account' is specified (DEPRECATED), assign address to that account.\n"
1313 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
1314 "2. \"keysobject\" (string, required) A json array of " + strprintf("%s",komodo_chainname()) + " addresses or hex-encoded public keys\n"
1316 " \"address\" (string) " + strprintf("%s",komodo_chainname()) + " address or hex-encoded public key\n"
1319 "3. \"account\" (string, optional) DEPRECATED. If provided, MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1322 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) A " + strprintf("%s",komodo_chainname()) + " address associated with the keys.\n"
1325 "\nAdd a multisig address from 2 addresses\n"
1326 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"") +
1327 "\nAs json rpc call\n"
1328 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"")
1330 throw runtime_error(msg);
1333 LOCK2(cs_main, pwalletMain->cs_wallet);
1336 if (params.size() > 2)
1337 strAccount = AccountFromValue(params[2]);
1339 // Construct using pay-to-script-hash:
1340 CScript inner = _createmultisig_redeemScript(params);
1341 CScriptID innerID(inner);
1342 pwalletMain->AddCScript(inner);
1344 pwalletMain->SetAddressBook(innerID, strAccount, "send");
1345 return CBitcoinAddress(innerID).ToString();
1353 vector<uint256> txids;
1358 nConf = std::numeric_limits<int>::max();
1359 fIsWatchonly = false;
1363 UniValue ListReceived(const UniValue& params, bool fByAccounts)
1365 // Minimum confirmations
1367 if (params.size() > 0)
1368 nMinDepth = params[0].get_int();
1370 // Whether to include empty accounts
1371 bool fIncludeEmpty = false;
1372 if (params.size() > 1)
1373 fIncludeEmpty = params[1].get_bool();
1375 isminefilter filter = ISMINE_SPENDABLE;
1376 if(params.size() > 2)
1377 if(params[2].get_bool())
1378 filter = filter | ISMINE_WATCH_ONLY;
1381 map<CBitcoinAddress, tallyitem> mapTally;
1382 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1384 const CWalletTx& wtx = (*it).second;
1386 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
1389 int nDepth = wtx.GetDepthInMainChain();
1390 if (nDepth < nMinDepth)
1393 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1395 CTxDestination address;
1396 if (!ExtractDestination(txout.scriptPubKey, address))
1399 isminefilter mine = IsMine(*pwalletMain, address);
1400 if(!(mine & filter))
1403 tallyitem& item = mapTally[address];
1404 item.nAmount += txout.nValue; // komodo_interest?
1405 item.nConf = min(item.nConf, nDepth);
1406 item.txids.push_back(wtx.GetHash());
1407 if (mine & ISMINE_WATCH_ONLY)
1408 item.fIsWatchonly = true;
1413 UniValue ret(UniValue::VARR);
1414 map<string, tallyitem> mapAccountTally;
1415 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
1417 const CBitcoinAddress& address = item.first;
1418 const string& strAccount = item.second.name;
1419 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1420 if (it == mapTally.end() && !fIncludeEmpty)
1423 CAmount nAmount = 0;
1424 int nConf = std::numeric_limits<int>::max();
1425 bool fIsWatchonly = false;
1426 if (it != mapTally.end())
1428 nAmount = (*it).second.nAmount;
1429 nConf = (*it).second.nConf;
1430 fIsWatchonly = (*it).second.fIsWatchonly;
1435 tallyitem& item = mapAccountTally[strAccount];
1436 item.nAmount += nAmount;
1437 item.nConf = min(item.nConf, nConf);
1438 item.fIsWatchonly = fIsWatchonly;
1442 UniValue obj(UniValue::VOBJ);
1444 obj.push_back(Pair("involvesWatchonly", true));
1445 obj.push_back(Pair("address", address.ToString()));
1446 obj.push_back(Pair("account", strAccount));
1447 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1448 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1449 UniValue transactions(UniValue::VARR);
1450 if (it != mapTally.end())
1452 BOOST_FOREACH(const uint256& item, (*it).second.txids)
1454 transactions.push_back(item.GetHex());
1457 obj.push_back(Pair("txids", transactions));
1464 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1466 CAmount nAmount = (*it).second.nAmount;
1467 int nConf = (*it).second.nConf;
1468 UniValue obj(UniValue::VOBJ);
1469 if((*it).second.fIsWatchonly)
1470 obj.push_back(Pair("involvesWatchonly", true));
1471 obj.push_back(Pair("account", (*it).first));
1472 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1473 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1481 UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
1483 if (!EnsureWalletIsAvailable(fHelp))
1484 return NullUniValue;
1486 if (fHelp || params.size() > 3)
1487 throw runtime_error(
1488 "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
1489 "\nList balances by receiving address.\n"
1491 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1492 "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n"
1493 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1498 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
1499 " \"address\" : \"receivingaddress\", (string) The receiving address\n"
1500 " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
1501 " \"amount\" : x.xxx, (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received by the address\n"
1502 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1508 + HelpExampleCli("listreceivedbyaddress", "")
1509 + HelpExampleCli("listreceivedbyaddress", "6 true")
1510 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
1513 LOCK2(cs_main, pwalletMain->cs_wallet);
1515 return ListReceived(params, false);
1518 UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
1520 if (!EnsureWalletIsAvailable(fHelp))
1521 return NullUniValue;
1523 if (fHelp || params.size() > 3)
1524 throw runtime_error(
1525 "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
1526 "\nDEPRECATED. List balances by account.\n"
1528 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1529 "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
1530 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1535 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
1536 " \"account\" : \"accountname\", (string) The account name of the receiving account\n"
1537 " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
1538 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1544 + HelpExampleCli("listreceivedbyaccount", "")
1545 + HelpExampleCli("listreceivedbyaccount", "6 true")
1546 + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
1549 LOCK2(cs_main, pwalletMain->cs_wallet);
1551 return ListReceived(params, true);
1554 static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
1556 CBitcoinAddress addr;
1558 entry.push_back(Pair("address", addr.ToString()));
1561 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
1564 string strSentAccount;
1565 list<COutputEntry> listReceived;
1566 list<COutputEntry> listSent;
1568 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
1570 bool fAllAccounts = (strAccount == string("*"));
1571 bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
1574 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1576 BOOST_FOREACH(const COutputEntry& s, listSent)
1578 UniValue entry(UniValue::VOBJ);
1579 if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
1580 entry.push_back(Pair("involvesWatchonly", true));
1581 entry.push_back(Pair("account", strSentAccount));
1582 MaybePushAddress(entry, s.destination);
1583 entry.push_back(Pair("category", "send"));
1584 entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
1585 entry.push_back(Pair("vout", s.vout));
1586 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1588 WalletTxToJSON(wtx, entry);
1590 entry.push_back(Pair("size", (uint64_t)static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1592 entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1594 ret.push_back(entry);
1599 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1601 BOOST_FOREACH(const COutputEntry& r, listReceived)
1604 if (pwalletMain->mapAddressBook.count(r.destination))
1605 account = pwalletMain->mapAddressBook[r.destination].name;
1606 if (fAllAccounts || (account == strAccount))
1608 UniValue entry(UniValue::VOBJ);
1609 if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
1610 entry.push_back(Pair("involvesWatchonly", true));
1611 entry.push_back(Pair("account", account));
1612 MaybePushAddress(entry, r.destination);
1613 if (wtx.IsCoinBase())
1615 if (wtx.GetDepthInMainChain() < 1)
1616 entry.push_back(Pair("category", "orphan"));
1617 else if (wtx.GetBlocksToMaturity() > 0)
1618 entry.push_back(Pair("category", "immature"));
1620 entry.push_back(Pair("category", "generate"));
1624 entry.push_back(Pair("category", "receive"));
1626 entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
1627 entry.push_back(Pair("vout", r.vout));
1629 WalletTxToJSON(wtx, entry);
1631 entry.push_back(Pair("size", (uint64_t)static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1633 entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1635 ret.push_back(entry);
1641 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret)
1643 bool fAllAccounts = (strAccount == string("*"));
1645 if (fAllAccounts || acentry.strAccount == strAccount)
1647 UniValue entry(UniValue::VOBJ);
1648 entry.push_back(Pair("account", acentry.strAccount));
1649 entry.push_back(Pair("category", "move"));
1650 entry.push_back(Pair("time", acentry.nTime));
1651 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1652 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1653 entry.push_back(Pair("comment", acentry.strComment));
1654 ret.push_back(entry);
1658 UniValue listtransactions(const UniValue& params, bool fHelp)
1660 if (!EnsureWalletIsAvailable(fHelp))
1661 return NullUniValue;
1663 if (fHelp || params.size() > 4)
1664 throw runtime_error(
1665 "listtransactions ( \"account\" count from includeWatchonly)\n"
1666 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
1668 "1. \"account\" (string, optional) DEPRECATED. The account name. Should be \"*\".\n"
1669 "2. count (numeric, optional, default=10) The number of transactions to return\n"
1670 "3. from (numeric, optional, default=0) The number of transactions to skip\n"
1671 "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
1675 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n"
1676 " It will be \"\" for the default account.\n"
1677 " \"address\":\"" + strprintf("%s",komodo_chainname()) + "_address\", (string) The " + strprintf("%s",komodo_chainname()) + " address of the transaction. Not present for \n"
1678 " move transactions (category = move).\n"
1679 " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
1680 " transaction between accounts, and not associated with an address,\n"
1681 " transaction id or block. 'send' and 'receive' transactions are \n"
1682 " associated with an address, transaction id and block details\n"
1683 " \"amount\": x.xxx, (numeric) The amount in " + strprintf("%s",komodo_chainname()) + ". This is negative for the 'send' category, and for the\n"
1684 " 'move' category for moves outbound. It is positive for the 'receive' category,\n"
1685 " and for the 'move' category for inbound funds.\n"
1686 " \"vout\" : n, (numeric) the vout value\n"
1687 " \"fee\": x.xxx, (numeric) The amount of the fee in " + strprintf("%s",komodo_chainname()) + ". This is negative and only available for the \n"
1688 " 'send' category of transactions.\n"
1689 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
1690 " 'receive' category of transactions.\n"
1691 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
1692 " category of transactions.\n"
1693 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
1694 " category of transactions.\n"
1695 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1696 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1697 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
1698 " for 'send' and 'receive' category of transactions.\n"
1699 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1700 " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
1701 " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
1702 " negative amounts).\n"
1703 " \"size\": n, (numeric) Transaction size in bytes\n"
1708 "\nList the most recent 10 transactions in the systems\n"
1709 + HelpExampleCli("listtransactions", "") +
1710 "\nList transactions 100 to 120\n"
1711 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
1712 "\nAs a json rpc call\n"
1713 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
1716 LOCK2(cs_main, pwalletMain->cs_wallet);
1718 string strAccount = "*";
1719 if (params.size() > 0)
1720 strAccount = params[0].get_str();
1722 if (params.size() > 1)
1723 nCount = params[1].get_int();
1725 if (params.size() > 2)
1726 nFrom = params[2].get_int();
1727 isminefilter filter = ISMINE_SPENDABLE;
1728 if(params.size() > 3)
1729 if(params[3].get_bool())
1730 filter = filter | ISMINE_WATCH_ONLY;
1733 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1735 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1737 UniValue ret(UniValue::VARR);
1739 std::list<CAccountingEntry> acentries;
1740 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1742 // iterate backwards until we have nCount items to return:
1743 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1745 CWalletTx *const pwtx = (*it).second.first;
1747 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1748 CAccountingEntry *const pacentry = (*it).second.second;
1750 AcentryToJSON(*pacentry, strAccount, ret);
1752 if ((int)ret.size() >= (nCount+nFrom)) break;
1754 // ret is newest to oldest
1756 if (nFrom > (int)ret.size())
1758 if ((nFrom + nCount) > (int)ret.size())
1759 nCount = ret.size() - nFrom;
1761 vector<UniValue> arrTmp = ret.getValues();
1763 vector<UniValue>::iterator first = arrTmp.begin();
1764 std::advance(first, nFrom);
1765 vector<UniValue>::iterator last = arrTmp.begin();
1766 std::advance(last, nFrom+nCount);
1768 if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
1769 if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
1771 std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
1775 ret.push_backV(arrTmp);
1780 UniValue listaccounts(const UniValue& params, bool fHelp)
1782 if (!EnsureWalletIsAvailable(fHelp))
1783 return NullUniValue;
1785 if (fHelp || params.size() > 2)
1786 throw runtime_error(
1787 "listaccounts ( minconf includeWatchonly)\n"
1788 "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
1790 "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
1791 "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
1793 "{ (json object where keys are account names, and values are numeric balances\n"
1794 " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
1798 "\nList account balances where there at least 1 confirmation\n"
1799 + HelpExampleCli("listaccounts", "") +
1800 "\nList account balances including zero confirmation transactions\n"
1801 + HelpExampleCli("listaccounts", "0") +
1802 "\nList account balances for 6 or more confirmations\n"
1803 + HelpExampleCli("listaccounts", "6") +
1804 "\nAs json rpc call\n"
1805 + HelpExampleRpc("listaccounts", "6")
1808 LOCK2(cs_main, pwalletMain->cs_wallet);
1811 if (params.size() > 0)
1812 nMinDepth = params[0].get_int();
1813 isminefilter includeWatchonly = ISMINE_SPENDABLE;
1814 if(params.size() > 1)
1815 if(params[1].get_bool())
1816 includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
1818 map<string, CAmount> mapAccountBalances;
1819 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
1820 if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
1821 mapAccountBalances[entry.second.name] = 0;
1824 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1826 const CWalletTx& wtx = (*it).second;
1828 string strSentAccount;
1829 list<COutputEntry> listReceived;
1830 list<COutputEntry> listSent;
1831 int nDepth = wtx.GetDepthInMainChain();
1832 if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
1834 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1835 mapAccountBalances[strSentAccount] -= nFee;
1836 BOOST_FOREACH(const COutputEntry& s, listSent)
1837 mapAccountBalances[strSentAccount] -= s.amount;
1838 if (nDepth >= nMinDepth)
1840 BOOST_FOREACH(const COutputEntry& r, listReceived)
1841 if (pwalletMain->mapAddressBook.count(r.destination))
1842 mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
1844 mapAccountBalances[""] += r.amount;
1848 list<CAccountingEntry> acentries;
1849 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1850 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1851 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1853 UniValue ret(UniValue::VOBJ);
1854 BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
1855 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1860 UniValue listsinceblock(const UniValue& params, bool fHelp)
1862 if (!EnsureWalletIsAvailable(fHelp))
1863 return NullUniValue;
1866 throw runtime_error(
1867 "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
1868 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
1870 "1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
1871 "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
1872 "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
1875 " \"transactions\": [\n"
1876 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
1877 " \"address\":\"" + strprintf("%s",komodo_chainname()) + "_address\", (string) The " + strprintf("%s",komodo_chainname()) + " address of the transaction. Not present for move transactions (category = move).\n"
1878 " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
1879 " \"amount\": x.xxx, (numeric) The amount in " + strprintf("%s",komodo_chainname()) + ". This is negative for the 'send' category, and for the 'move' category for moves \n"
1880 " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
1881 " \"vout\" : n, (numeric) the vout value\n"
1882 " \"fee\": x.xxx, (numeric) The amount of the fee in " + strprintf("%s",komodo_chainname()) + ". This is negative and only available for the 'send' category of transactions.\n"
1883 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
1884 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1885 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1886 " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
1887 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1888 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
1889 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
1890 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1891 " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
1893 " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
1896 + HelpExampleCli("listsinceblock", "")
1897 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1898 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1901 LOCK2(cs_main, pwalletMain->cs_wallet);
1903 CBlockIndex *pindex = NULL;
1904 int target_confirms = 1;
1905 isminefilter filter = ISMINE_SPENDABLE;
1907 if (params.size() > 0)
1911 blockId.SetHex(params[0].get_str());
1912 BlockMap::iterator it = mapBlockIndex.find(blockId);
1913 if (it != mapBlockIndex.end())
1914 pindex = it->second;
1917 if (params.size() > 1)
1919 target_confirms = params[1].get_int();
1921 if (target_confirms < 1)
1922 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1925 if(params.size() > 2)
1926 if(params[2].get_bool())
1927 filter = filter | ISMINE_WATCH_ONLY;
1929 int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
1931 UniValue transactions(UniValue::VARR);
1933 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1935 CWalletTx tx = (*it).second;
1937 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1938 ListTransactions(tx, "*", 0, true, transactions, filter);
1941 CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
1942 uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
1944 UniValue ret(UniValue::VOBJ);
1945 ret.push_back(Pair("transactions", transactions));
1946 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1951 UniValue gettransaction(const UniValue& params, bool fHelp)
1953 if (!EnsureWalletIsAvailable(fHelp))
1954 return NullUniValue;
1956 if (fHelp || params.size() < 1 || params.size() > 2)
1957 throw runtime_error(
1958 "gettransaction \"txid\" ( includeWatchonly )\n"
1959 "\nGet detailed information about in-wallet transaction <txid>\n"
1961 "1. \"txid\" (string, required) The transaction id\n"
1962 "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
1965 " \"amount\" : x.xxx, (numeric) The transaction amount in " + strprintf("%s",komodo_chainname()) + "\n"
1966 " \"confirmations\" : n, (numeric) The number of confirmations\n"
1967 " \"blockhash\" : \"hash\", (string) The block hash\n"
1968 " \"blockindex\" : xx, (numeric) The block index\n"
1969 " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
1970 " \"txid\" : \"transactionid\", (string) The transaction id.\n"
1971 " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
1972 " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
1973 " \"details\" : [\n"
1975 " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
1976 " \"address\" : \"" + strprintf("%s",komodo_chainname()) + "_address\", (string) The " + strprintf("%s",komodo_chainname()) + " address involved in the transaction\n"
1977 " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
1978 " \"amount\" : x.xxx (numeric) The amount in " + strprintf("%s",komodo_chainname()) + "\n"
1979 " \"vout\" : n, (numeric) the vout value\n"
1983 " \"vjoinsplit\" : [\n"
1985 " \"anchor\" : \"treestateref\", (string) Merkle root of note commitment tree\n"
1986 " \"nullifiers\" : [ string, ... ] (string) Nullifiers of input notes\n"
1987 " \"commitments\" : [ string, ... ] (string) Note commitments for note outputs\n"
1988 " \"macs\" : [ string, ... ] (string) Message authentication tags\n"
1989 " \"vpub_old\" : x.xxx (numeric) The amount removed from the transparent value pool\n"
1990 " \"vpub_new\" : x.xxx, (numeric) The amount added to the transparent value pool\n"
1994 " \"hex\" : \"data\" (string) Raw data for transaction\n"
1998 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1999 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
2000 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
2003 LOCK2(cs_main, pwalletMain->cs_wallet);
2006 hash.SetHex(params[0].get_str());
2008 isminefilter filter = ISMINE_SPENDABLE;
2009 if(params.size() > 1)
2010 if(params[1].get_bool())
2011 filter = filter | ISMINE_WATCH_ONLY;
2013 UniValue entry(UniValue::VOBJ);
2014 if (!pwalletMain->mapWallet.count(hash))
2015 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
2016 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
2018 CAmount nCredit = wtx.GetCredit(filter);
2019 CAmount nDebit = wtx.GetDebit(filter);
2020 CAmount nNet = nCredit - nDebit;
2021 CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
2023 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
2024 if (wtx.IsFromMe(filter))
2025 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
2027 WalletTxToJSON(wtx, entry);
2029 UniValue details(UniValue::VARR);
2030 ListTransactions(wtx, "*", 0, false, details, filter);
2031 entry.push_back(Pair("details", details));
2033 string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
2034 entry.push_back(Pair("hex", strHex));
2040 UniValue backupwallet(const UniValue& params, bool fHelp)
2042 if (!EnsureWalletIsAvailable(fHelp))
2043 return NullUniValue;
2045 if (fHelp || params.size() != 1)
2046 throw runtime_error(
2047 "backupwallet \"destination\"\n"
2048 "\nSafely copies wallet.dat to destination filename\n"
2050 "1. \"destination\" (string, required) The destination filename, saved in the directory set by -exportdir option.\n"
2052 "\"path\" (string) The full path of the destination file\n"
2054 + HelpExampleCli("backupwallet", "\"backupdata\"")
2055 + HelpExampleRpc("backupwallet", "\"backupdata\"")
2058 LOCK2(cs_main, pwalletMain->cs_wallet);
2060 boost::filesystem::path exportdir;
2062 exportdir = GetExportDir();
2063 } catch (const std::runtime_error& e) {
2064 throw JSONRPCError(RPC_INTERNAL_ERROR, e.what());
2066 if (exportdir.empty()) {
2067 throw JSONRPCError(RPC_WALLET_ERROR, "Cannot backup wallet until the -exportdir option has been set");
2069 std::string unclean = params[0].get_str();
2070 std::string clean = SanitizeFilename(unclean);
2071 if (clean.compare(unclean) != 0) {
2072 throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Filename is invalid as only alphanumeric characters are allowed. Try '%s' instead.", clean));
2074 boost::filesystem::path exportfilepath = exportdir / clean;
2076 if (!BackupWallet(*pwalletMain, exportfilepath.string()))
2077 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
2079 return exportfilepath.string();
2083 UniValue keypoolrefill(const UniValue& params, bool fHelp)
2085 if (!EnsureWalletIsAvailable(fHelp))
2086 return NullUniValue;
2088 if (fHelp || params.size() > 1)
2089 throw runtime_error(
2090 "keypoolrefill ( newsize )\n"
2091 "\nFills the keypool."
2092 + HelpRequiringPassphrase() + "\n"
2094 "1. newsize (numeric, optional, default=100) The new keypool size\n"
2096 + HelpExampleCli("keypoolrefill", "")
2097 + HelpExampleRpc("keypoolrefill", "")
2100 LOCK2(cs_main, pwalletMain->cs_wallet);
2102 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
2103 unsigned int kpSize = 0;
2104 if (params.size() > 0) {
2105 if (params[0].get_int() < 0)
2106 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
2107 kpSize = (unsigned int)params[0].get_int();
2110 EnsureWalletIsUnlocked();
2111 pwalletMain->TopUpKeyPool(kpSize);
2113 if (pwalletMain->GetKeyPoolSize() < kpSize)
2114 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
2116 return NullUniValue;
2120 static void LockWallet(CWallet* pWallet)
2122 LOCK(cs_nWalletUnlockTime);
2123 nWalletUnlockTime = 0;
2127 UniValue walletpassphrase(const UniValue& params, bool fHelp)
2129 if (!EnsureWalletIsAvailable(fHelp))
2130 return NullUniValue;
2132 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
2133 throw runtime_error(
2134 "walletpassphrase \"passphrase\" timeout\n"
2135 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
2136 "This is needed prior to performing transactions related to private keys such as sending " + strprintf("%s",komodo_chainname()) + "\n"
2138 "1. \"passphrase\" (string, required) The wallet passphrase\n"
2139 "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
2141 "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
2142 "time that overrides the old one.\n"
2144 "\nunlock the wallet for 60 seconds\n"
2145 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
2146 "\nLock the wallet again (before 60 seconds)\n"
2147 + HelpExampleCli("walletlock", "") +
2148 "\nAs json rpc call\n"
2149 + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
2152 LOCK2(cs_main, pwalletMain->cs_wallet);
2156 if (!pwalletMain->IsCrypted())
2157 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
2159 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
2160 SecureString strWalletPass;
2161 strWalletPass.reserve(100);
2162 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2163 // Alternately, find a way to make params[0] mlock()'d to begin with.
2164 strWalletPass = params[0].get_str().c_str();
2166 if (strWalletPass.length() > 0)
2168 if (!pwalletMain->Unlock(strWalletPass))
2169 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
2172 throw runtime_error(
2173 "walletpassphrase <passphrase> <timeout>\n"
2174 "Stores the wallet decryption key in memory for <timeout> seconds.");
2176 // No need to check return values, because the wallet was unlocked above
2177 pwalletMain->UpdateNullifierNoteMap();
2178 pwalletMain->TopUpKeyPool();
2180 int64_t nSleepTime = params[1].get_int64();
2181 LOCK(cs_nWalletUnlockTime);
2182 nWalletUnlockTime = GetTime() + nSleepTime;
2183 RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
2185 return NullUniValue;
2189 UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
2191 if (!EnsureWalletIsAvailable(fHelp))
2192 return NullUniValue;
2194 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
2195 throw runtime_error(
2196 "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
2197 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
2199 "1. \"oldpassphrase\" (string) The current passphrase\n"
2200 "2. \"newpassphrase\" (string) The new passphrase\n"
2202 + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
2203 + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
2206 LOCK2(cs_main, pwalletMain->cs_wallet);
2210 if (!pwalletMain->IsCrypted())
2211 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
2213 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
2214 // Alternately, find a way to make params[0] mlock()'d to begin with.
2215 SecureString strOldWalletPass;
2216 strOldWalletPass.reserve(100);
2217 strOldWalletPass = params[0].get_str().c_str();
2219 SecureString strNewWalletPass;
2220 strNewWalletPass.reserve(100);
2221 strNewWalletPass = params[1].get_str().c_str();
2223 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
2224 throw runtime_error(
2225 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
2226 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
2228 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
2229 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
2231 return NullUniValue;
2235 UniValue walletlock(const UniValue& params, bool fHelp)
2237 if (!EnsureWalletIsAvailable(fHelp))
2238 return NullUniValue;
2240 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
2241 throw runtime_error(
2243 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
2244 "After calling this method, you will need to call walletpassphrase again\n"
2245 "before being able to call any methods which require the wallet to be unlocked.\n"
2247 "\nSet the passphrase for 2 minutes to perform a transaction\n"
2248 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
2249 "\nPerform a send (requires passphrase set)\n"
2250 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 1.0") +
2251 "\nClear the passphrase since we are done before 2 minutes is up\n"
2252 + HelpExampleCli("walletlock", "") +
2253 "\nAs json rpc call\n"
2254 + HelpExampleRpc("walletlock", "")
2257 LOCK2(cs_main, pwalletMain->cs_wallet);
2261 if (!pwalletMain->IsCrypted())
2262 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
2265 LOCK(cs_nWalletUnlockTime);
2266 pwalletMain->Lock();
2267 nWalletUnlockTime = 0;
2270 return NullUniValue;
2274 UniValue encryptwallet(const UniValue& params, bool fHelp)
2276 if (!EnsureWalletIsAvailable(fHelp))
2277 return NullUniValue;
2279 auto fEnableWalletEncryption = fExperimentalMode && GetBoolArg("-developerencryptwallet", false);
2281 std::string strWalletEncryptionDisabledMsg = "";
2282 if (!fEnableWalletEncryption) {
2283 strWalletEncryptionDisabledMsg = "\nWARNING: Wallet encryption is DISABLED. This call always fails.\n";
2286 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
2287 throw runtime_error(
2288 "encryptwallet \"passphrase\"\n"
2289 + strWalletEncryptionDisabledMsg +
2290 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
2291 "After this, any calls that interact with private keys such as sending or signing \n"
2292 "will require the passphrase to be set prior the making these calls.\n"
2293 "Use the walletpassphrase call for this, and then walletlock call.\n"
2294 "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
2295 "Note that this will shutdown the server.\n"
2297 "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
2299 "\nEncrypt you wallet\n"
2300 + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
2301 "\nNow set the passphrase to use the wallet, such as for signing or sending " + strprintf("%s",komodo_chainname()) + "\n"
2302 + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
2303 "\nNow we can so something like sign\n"
2304 + HelpExampleCli("signmessage", "\"" + strprintf("%s",komodo_chainname()) + "_address\" \"test message\"") +
2305 "\nNow lock the wallet again by removing the passphrase\n"
2306 + HelpExampleCli("walletlock", "") +
2307 "\nAs a json rpc call\n"
2308 + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
2311 LOCK2(cs_main, pwalletMain->cs_wallet);
2315 if (!fEnableWalletEncryption) {
2316 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet encryption is disabled.");
2318 if (pwalletMain->IsCrypted())
2319 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
2321 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2322 // Alternately, find a way to make params[0] mlock()'d to begin with.
2323 SecureString strWalletPass;
2324 strWalletPass.reserve(100);
2325 strWalletPass = params[0].get_str().c_str();
2327 if (strWalletPass.length() < 1)
2328 throw runtime_error(
2329 "encryptwallet <passphrase>\n"
2330 "Encrypts the wallet with <passphrase>.");
2332 if (!pwalletMain->EncryptWallet(strWalletPass))
2333 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
2335 // BDB seems to have a bad habit of writing old data into
2336 // slack space in .dat files; that is bad if the old data is
2337 // unencrypted private keys. So:
2339 return "wallet encrypted; Komodo server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
2342 UniValue lockunspent(const UniValue& params, bool fHelp)
2344 if (!EnsureWalletIsAvailable(fHelp))
2345 return NullUniValue;
2347 if (fHelp || params.size() < 1 || params.size() > 2)
2348 throw runtime_error(
2349 "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
2350 "\nUpdates list of temporarily unspendable outputs.\n"
2351 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
2352 "A locked transaction output will not be chosen by automatic coin selection, when spending " + strprintf("%s",komodo_chainname()) + ".\n"
2353 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2354 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
2355 "Also see the listunspent call\n"
2357 "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
2358 "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
2359 " [ (json array of json objects)\n"
2361 " \"txid\":\"id\", (string) The transaction id\n"
2362 " \"vout\": n (numeric) The output number\n"
2368 "true|false (boolean) Whether the command was successful or not\n"
2371 "\nList the unspent transactions\n"
2372 + HelpExampleCli("listunspent", "") +
2373 "\nLock an unspent transaction\n"
2374 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2375 "\nList the locked transactions\n"
2376 + HelpExampleCli("listlockunspent", "") +
2377 "\nUnlock the transaction again\n"
2378 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2379 "\nAs a json rpc call\n"
2380 + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
2383 LOCK2(cs_main, pwalletMain->cs_wallet);
2385 if (params.size() == 1)
2386 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL));
2388 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
2390 bool fUnlock = params[0].get_bool();
2392 if (params.size() == 1) {
2394 pwalletMain->UnlockAllCoins();
2398 UniValue outputs = params[1].get_array();
2399 for (size_t idx = 0; idx < outputs.size(); idx++) {
2400 const UniValue& output = outputs[idx];
2401 if (!output.isObject())
2402 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
2403 const UniValue& o = output.get_obj();
2405 RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM));
2407 string txid = find_value(o, "txid").get_str();
2409 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
2411 int nOutput = find_value(o, "vout").get_int();
2413 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
2415 COutPoint outpt(uint256S(txid), nOutput);
2418 pwalletMain->UnlockCoin(outpt);
2420 pwalletMain->LockCoin(outpt);
2426 UniValue listlockunspent(const UniValue& params, bool fHelp)
2428 if (!EnsureWalletIsAvailable(fHelp))
2429 return NullUniValue;
2431 if (fHelp || params.size() > 0)
2432 throw runtime_error(
2434 "\nReturns list of temporarily unspendable outputs.\n"
2435 "See the lockunspent call to lock and unlock transactions for spending.\n"
2439 " \"txid\" : \"transactionid\", (string) The transaction id locked\n"
2440 " \"vout\" : n (numeric) The vout value\n"
2445 "\nList the unspent transactions\n"
2446 + HelpExampleCli("listunspent", "") +
2447 "\nLock an unspent transaction\n"
2448 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2449 "\nList the locked transactions\n"
2450 + HelpExampleCli("listlockunspent", "") +
2451 "\nUnlock the transaction again\n"
2452 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2453 "\nAs a json rpc call\n"
2454 + HelpExampleRpc("listlockunspent", "")
2457 LOCK2(cs_main, pwalletMain->cs_wallet);
2459 vector<COutPoint> vOutpts;
2460 pwalletMain->ListLockedCoins(vOutpts);
2462 UniValue ret(UniValue::VARR);
2464 BOOST_FOREACH(COutPoint &outpt, vOutpts) {
2465 UniValue o(UniValue::VOBJ);
2467 o.push_back(Pair("txid", outpt.hash.GetHex()));
2468 o.push_back(Pair("vout", (int)outpt.n));
2475 UniValue settxfee(const UniValue& params, bool fHelp)
2477 if (!EnsureWalletIsAvailable(fHelp))
2478 return NullUniValue;
2480 if (fHelp || params.size() < 1 || params.size() > 1)
2481 throw runtime_error(
2483 "\nSet the transaction fee per kB.\n"
2485 "1. amount (numeric, required) The transaction fee in " + strprintf("%s",komodo_chainname()) + "/kB rounded to the nearest 0.00000001\n"
2487 "true|false (boolean) Returns true if successful\n"
2489 + HelpExampleCli("settxfee", "0.00001")
2490 + HelpExampleRpc("settxfee", "0.00001")
2493 LOCK2(cs_main, pwalletMain->cs_wallet);
2496 CAmount nAmount = AmountFromValue(params[0]);
2498 payTxFee = CFeeRate(nAmount, 1000);
2502 UniValue getwalletinfo(const UniValue& params, bool fHelp)
2504 if (!EnsureWalletIsAvailable(fHelp))
2505 return NullUniValue;
2507 if (fHelp || params.size() != 0)
2508 throw runtime_error(
2510 "Returns an object containing various wallet state info.\n"
2513 " \"walletversion\": xxxxx, (numeric) the wallet version\n"
2514 " \"balance\": xxxxxxx, (numeric) the total confirmed balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
2515 " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
2516 " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
2517 " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
2518 " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
2519 " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
2520 " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
2521 " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in KMD/KB\n"
2524 + HelpExampleCli("getwalletinfo", "")
2525 + HelpExampleRpc("getwalletinfo", "")
2528 LOCK2(cs_main, pwalletMain->cs_wallet);
2530 UniValue obj(UniValue::VOBJ);
2531 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
2532 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
2533 obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
2534 obj.push_back(Pair("immature_balance", ValueFromAmount(pwalletMain->GetImmatureBalance())));
2535 obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size()));
2536 obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
2537 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
2538 if (pwalletMain->IsCrypted())
2539 obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
2540 obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
2544 UniValue resendwallettransactions(const UniValue& params, bool fHelp)
2546 if (!EnsureWalletIsAvailable(fHelp))
2547 return NullUniValue;
2549 if (fHelp || params.size() != 0)
2550 throw runtime_error(
2551 "resendwallettransactions\n"
2552 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
2553 "Intended only for testing; the wallet code periodically re-broadcasts\n"
2555 "Returns array of transaction ids that were re-broadcast.\n"
2558 LOCK2(cs_main, pwalletMain->cs_wallet);
2560 std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
2561 UniValue result(UniValue::VARR);
2562 BOOST_FOREACH(const uint256& txid, txids)
2564 result.push_back(txid.ToString());
2569 UniValue listunspent(const UniValue& params, bool fHelp)
2571 if (!EnsureWalletIsAvailable(fHelp))
2572 return NullUniValue;
2574 if (fHelp || params.size() > 3)
2575 throw runtime_error(
2576 "listunspent ( minconf maxconf [\"address\",...] )\n"
2577 "\nReturns array of unspent transaction outputs\n"
2578 "with between minconf and maxconf (inclusive) confirmations.\n"
2579 "Optionally filter to only include txouts paid to specified addresses.\n"
2580 "Results are an array of Objects, each of which has:\n"
2581 "{txid, vout, scriptPubKey, amount, confirmations}\n"
2583 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
2584 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
2585 "3. \"addresses\" (string) A json array of " + strprintf("%s",komodo_chainname()) + " addresses to filter\n"
2587 " \"address\" (string) " + strprintf("%s",komodo_chainname()) + " address\n"
2591 "[ (array of json object)\n"
2593 " \"txid\" : \"txid\", (string) the transaction id \n"
2594 " \"vout\" : n, (numeric) the vout value\n"
2595 " \"generated\" : true|false (boolean) true if txout is a coinbase transaction output\n"
2596 " \"address\" : \"address\", (string) the " + strprintf("%s",komodo_chainname()) + " address\n"
2597 " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
2598 " \"scriptPubKey\" : \"key\", (string) the script key\n"
2599 " \"amount\" : x.xxx, (numeric) the transaction amount in " + strprintf("%s",komodo_chainname()) + "\n"
2600 " \"confirmations\" : n (numeric) The number of confirmations\n"
2606 + HelpExampleCli("listunspent", "")
2607 + HelpExampleCli("listunspent", "6 9999999 \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"")
2608 + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"")
2611 RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
2614 if (params.size() > 0)
2615 nMinDepth = params[0].get_int();
2617 int nMaxDepth = 9999999;
2618 if (params.size() > 1)
2619 nMaxDepth = params[1].get_int();
2621 set<CBitcoinAddress> setAddress;
2622 if (params.size() > 2) {
2623 UniValue inputs = params[2].get_array();
2624 for (size_t idx = 0; idx < inputs.size(); idx++) {
2625 const UniValue& input = inputs[idx];
2626 CBitcoinAddress address(input.get_str());
2627 if (!address.IsValid())
2628 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid " + strprintf("%s",komodo_chainname()) + " address: ")+input.get_str());
2629 if (setAddress.count(address))
2630 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
2631 setAddress.insert(address);
2635 UniValue results(UniValue::VARR);
2636 vector<COutput> vecOutputs;
2637 assert(pwalletMain != NULL);
2638 LOCK2(cs_main, pwalletMain->cs_wallet);
2639 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2640 BOOST_FOREACH(const COutput& out, vecOutputs) {
2641 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
2644 if (setAddress.size()) {
2645 CTxDestination address;
2646 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
2649 if (!setAddress.count(address))
2653 CAmount nValue = out.tx->vout[out.i].nValue;
2654 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
2655 UniValue entry(UniValue::VOBJ);
2656 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
2657 entry.push_back(Pair("vout", out.i));
2658 entry.push_back(Pair("generated", out.tx->IsCoinBase()));
2659 CTxDestination address;
2660 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
2661 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
2662 if (pwalletMain->mapAddressBook.count(address))
2663 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
2665 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
2666 if (pk.IsPayToScriptHash()) {
2667 CTxDestination address;
2668 if (ExtractDestination(pk, address)) {
2669 const CScriptID& hash = boost::get<CScriptID>(address);
2670 CScript redeemScript;
2671 if (pwalletMain->GetCScript(hash, redeemScript))
2672 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
2675 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
2676 if ( out.tx->nLockTime != 0 )
2678 BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
2679 CBlockIndex *tipindex,*pindex = it->second;
2680 uint64_t interest; uint32_t locktime; int32_t txheight;
2681 if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 )
2683 interest = komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight);
2684 //interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime);
2685 entry.push_back(Pair("interest",ValueFromAmount(interest)));
2687 //fprintf(stderr,"nValue %.8f pindex.%p tipindex.%p locktime.%u txheight.%d pindexht.%d\n",(double)nValue/COIN,pindex,chainActive.Tip(),locktime,txheight,pindex->nHeight);
2689 entry.push_back(Pair("confirmations",out.nDepth));
2690 entry.push_back(Pair("spendable", out.fSpendable));
2691 results.push_back(entry);
2697 uint64_t komodo_interestsum()
2699 #ifdef ENABLE_WALLET
2700 uint64_t interest,sum = 0; int32_t txheight; uint32_t locktime;
2701 vector<COutput> vecOutputs;
2702 assert(pwalletMain != NULL);
2703 LOCK2(cs_main, pwalletMain->cs_wallet);
2704 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2705 BOOST_FOREACH(const COutput& out,vecOutputs)
2707 CAmount nValue = out.tx->vout[out.i].nValue;
2708 if ( out.tx->nLockTime != 0 && out.fSpendable != 0 )
2710 BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
2711 CBlockIndex *tipindex,*pindex = it->second;
2712 if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 )
2714 interest = komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight);
2715 //interest = komodo_interest(pindex->nHeight,nValue,out.tx->nLockTime,tipindex->nTime);
2720 KOMODO_INTERESTSUM = sum;
2721 KOMODO_WALLETBALANCE = pwalletMain->GetBalance();
2728 UniValue fundrawtransaction(const UniValue& params, bool fHelp)
2730 if (!EnsureWalletIsAvailable(fHelp))
2731 return NullUniValue;
2733 if (fHelp || params.size() != 1)
2734 throw runtime_error(
2735 "fundrawtransaction \"hexstring\"\n"
2736 "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
2737 "This will not modify existing inputs, and will add one change output to the outputs.\n"
2738 "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
2739 "The inputs added will not be signed, use signrawtransaction for that.\n"
2741 "1. \"hexstring\" (string, required) The hex string of the raw transaction\n"
2744 " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
2745 " \"fee\": n, (numeric) The fee added to the transaction\n"
2746 " \"changepos\": n (numeric) The position of the added change output, or -1\n"
2750 "\nCreate a transaction with no inputs\n"
2751 + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
2752 "\nAdd sufficient unsigned inputs to meet the output value\n"
2753 + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
2754 "\nSign the transaction\n"
2755 + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
2756 "\nSend the transaction\n"
2757 + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
2760 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
2762 // parse hex string from parameter
2763 CTransaction origTx;
2764 if (!DecodeHexTx(origTx, params[0].get_str()))
2765 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2767 CMutableTransaction tx(origTx);
2769 string strFailReason;
2770 int nChangePos = -1;
2771 if(!pwalletMain->FundTransaction(tx, nFee, nChangePos, strFailReason))
2772 throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
2774 UniValue result(UniValue::VOBJ);
2775 result.push_back(Pair("hex", EncodeHexTx(tx)));
2776 result.push_back(Pair("changepos", nChangePos));
2777 result.push_back(Pair("fee", ValueFromAmount(nFee)));
2782 UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp)
2785 throw runtime_error(
2786 "zcsamplejoinsplit\n"
2788 "Perform a joinsplit and return the JSDescription.\n"
2795 uint256 anchor = ZCIncrementalMerkleTree().root();
2796 JSDescription samplejoinsplit(*pzcashParams,
2799 {JSInput(), JSInput()},
2800 {JSOutput(), JSOutput()},
2804 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2805 ss << samplejoinsplit;
2807 return HexStr(ss.begin(), ss.end());
2810 UniValue zc_benchmark(const UniValue& params, bool fHelp)
2812 if (!EnsureWalletIsAvailable(fHelp)) {
2813 return NullUniValue;
2816 if (fHelp || params.size() < 2) {
2817 throw runtime_error(
2818 "zcbenchmark benchmarktype samplecount\n"
2820 "Runs a benchmark of the selected type samplecount times,\n"
2821 "returning the running times of each sample.\n"
2825 " \"runningtime\": runningtime\n"
2828 " \"runningtime\": runningtime\n"
2837 std::string benchmarktype = params[0].get_str();
2838 int samplecount = params[1].get_int();
2840 if (samplecount <= 0) {
2841 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount");
2844 std::vector<double> sample_times;
2846 JSDescription samplejoinsplit;
2848 if (benchmarktype == "verifyjoinsplit") {
2849 CDataStream ss(ParseHexV(params[2].get_str(), "js"), SER_NETWORK, PROTOCOL_VERSION);
2850 ss >> samplejoinsplit;
2853 for (int i = 0; i < samplecount; i++) {
2854 if (benchmarktype == "sleep") {
2855 sample_times.push_back(benchmark_sleep());
2856 } else if (benchmarktype == "parameterloading") {
2857 sample_times.push_back(benchmark_parameter_loading());
2858 } else if (benchmarktype == "createjoinsplit") {
2859 if (params.size() < 3) {
2860 sample_times.push_back(benchmark_create_joinsplit());
2862 int nThreads = params[2].get_int();
2863 std::vector<double> vals = benchmark_create_joinsplit_threaded(nThreads);
2864 // Divide by nThreads^2 to get average seconds per JoinSplit because
2865 // we are running one JoinSplit per thread.
2866 sample_times.push_back(std::accumulate(vals.begin(), vals.end(), 0.0) / (nThreads*nThreads));
2868 } else if (benchmarktype == "verifyjoinsplit") {
2869 sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
2870 #ifdef ENABLE_MINING
2871 } else if (benchmarktype == "solveequihash") {
2872 if (params.size() < 3) {
2873 sample_times.push_back(benchmark_solve_equihash());
2875 int nThreads = params[2].get_int();
2876 std::vector<double> vals = benchmark_solve_equihash_threaded(nThreads);
2877 sample_times.insert(sample_times.end(), vals.begin(), vals.end());
2880 } else if (benchmarktype == "verifyequihash") {
2881 sample_times.push_back(benchmark_verify_equihash());
2882 } else if (benchmarktype == "validatelargetx") {
2883 // Number of inputs in the spending transaction that we will simulate
2885 if (params.size() >= 3) {
2886 nInputs = params[2].get_int();
2888 sample_times.push_back(benchmark_large_tx(nInputs));
2889 } else if (benchmarktype == "trydecryptnotes") {
2890 int nAddrs = params[2].get_int();
2891 sample_times.push_back(benchmark_try_decrypt_notes(nAddrs));
2892 } else if (benchmarktype == "incnotewitnesses") {
2893 int nTxs = params[2].get_int();
2894 sample_times.push_back(benchmark_increment_note_witnesses(nTxs));
2895 } else if (benchmarktype == "connectblockslow") {
2896 if (Params().NetworkIDString() != "regtest") {
2897 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2899 sample_times.push_back(benchmark_connectblock_slow());
2900 } else if (benchmarktype == "sendtoaddress") {
2901 if (Params().NetworkIDString() != "regtest") {
2902 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2904 auto amount = AmountFromValue(params[2]);
2905 sample_times.push_back(benchmark_sendtoaddress(amount));
2906 } else if (benchmarktype == "loadwallet") {
2907 if (Params().NetworkIDString() != "regtest") {
2908 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2910 sample_times.push_back(benchmark_loadwallet());
2911 } else if (benchmarktype == "listunspent") {
2912 sample_times.push_back(benchmark_listunspent());
2914 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
2918 UniValue results(UniValue::VARR);
2919 for (auto time : sample_times) {
2920 UniValue result(UniValue::VOBJ);
2921 result.push_back(Pair("runningtime", time));
2922 results.push_back(result);
2928 UniValue zc_raw_receive(const UniValue& params, bool fHelp)
2930 if (!EnsureWalletIsAvailable(fHelp)) {
2931 return NullUniValue;
2934 if (fHelp || params.size() != 2) {
2935 throw runtime_error(
2936 "zcrawreceive zcsecretkey encryptednote\n"
2938 "DEPRECATED. Decrypts encryptednote and checks if the coin commitments\n"
2939 "are in the blockchain as indicated by the \"exists\" result.\n"
2942 " \"amount\": value,\n"
2943 " \"note\": noteplaintext,\n"
2944 " \"exists\": exists\n"
2949 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR));
2953 CZCSpendingKey spendingkey(params[0].get_str());
2954 SpendingKey k = spendingkey.Get();
2957 unsigned char nonce;
2958 ZCNoteEncryption::Ciphertext ct;
2962 CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
2968 } catch(const std::exception &) {
2969 throw runtime_error(
2970 "encrypted_note could not be decoded"
2975 ZCNoteDecryption decryptor(k.receiving_key());
2977 NotePlaintext npt = NotePlaintext::decrypt(
2984 PaymentAddress payment_addr = k.address();
2985 Note decrypted_note = npt.note(payment_addr);
2987 assert(pwalletMain != NULL);
2988 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
2990 uint256 commitment = decrypted_note.cm();
2991 pwalletMain->WitnessNoteCommitment(
2997 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
3000 UniValue result(UniValue::VOBJ);
3001 result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value)));
3002 result.push_back(Pair("note", HexStr(ss.begin(), ss.end())));
3003 result.push_back(Pair("exists", (bool) witnesses[0]));
3009 UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
3011 if (!EnsureWalletIsAvailable(fHelp)) {
3012 return NullUniValue;
3015 if (fHelp || params.size() != 5) {
3016 throw runtime_error(
3017 "zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
3018 " inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
3019 " outputs: a JSON object mapping {zcaddr: value, ...}\n"
3021 "DEPRECATED. Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
3022 "Outputs are confidential between sender/receiver. The vpub_old and\n"
3023 "vpub_new values are globally public and move transparent value into\n"
3024 "or out of the confidential value store, respectively.\n"
3026 "Note: The caller is responsible for delivering the output enc1 and\n"
3027 "enc2 to the appropriate recipients, as well as signing rawtxout and\n"
3028 "ensuring it is mined. (A future RPC call will deliver the confidential\n"
3029 "payments in-band on the blockchain.)\n"
3032 " \"encryptednote1\": enc1,\n"
3033 " \"encryptednote2\": enc2,\n"
3034 " \"rawtxn\": rawtxout\n"
3042 if (!DecodeHexTx(tx, params[0].get_str()))
3043 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
3045 UniValue inputs = params[1].get_obj();
3046 UniValue outputs = params[2].get_obj();
3048 CAmount vpub_old(0);
3049 CAmount vpub_new(0);
3051 if (params[3].get_real() != 0.0)
3052 vpub_old = AmountFromValue(params[3]);
3054 if (params[4].get_real() != 0.0)
3055 vpub_new = AmountFromValue(params[4]);
3057 std::vector<JSInput> vjsin;
3058 std::vector<JSOutput> vjsout;
3059 std::vector<Note> notes;
3060 std::vector<SpendingKey> keys;
3061 std::vector<uint256> commitments;
3063 for (const string& name_ : inputs.getKeys()) {
3064 CZCSpendingKey spendingkey(inputs[name_].get_str());
3065 SpendingKey k = spendingkey.Get();
3072 CDataStream ssData(ParseHexV(name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
3076 PaymentAddress addr = k.address();
3077 Note note = npt.note(addr);
3078 notes.push_back(note);
3079 commitments.push_back(note.cm());
3083 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
3084 pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
3086 assert(witnesses.size() == notes.size());
3087 assert(notes.size() == keys.size());
3090 for (size_t i = 0; i < witnesses.size(); i++) {
3091 if (!witnesses[i]) {
3092 throw runtime_error(
3093 "joinsplit input could not be found in tree"
3097 vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
3101 while (vjsin.size() < ZC_NUM_JS_INPUTS) {
3102 vjsin.push_back(JSInput());
3105 for (const string& name_ : outputs.getKeys()) {
3106 CZCPaymentAddress pubaddr(name_);
3107 PaymentAddress addrTo = pubaddr.Get();
3108 CAmount nAmount = AmountFromValue(outputs[name_]);
3110 vjsout.push_back(JSOutput(addrTo, nAmount));
3113 while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
3114 vjsout.push_back(JSOutput());
3118 if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
3119 throw runtime_error("unsupported joinsplit input/output counts");
3122 uint256 joinSplitPubKey;
3123 unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
3124 crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
3126 CMutableTransaction mtx(tx);
3128 mtx.joinSplitPubKey = joinSplitPubKey;
3130 JSDescription jsdesc(*pzcashParams,
3133 {vjsin[0], vjsin[1]},
3134 {vjsout[0], vjsout[1]},
3139 auto verifier = libzcash::ProofVerifier::Strict();
3140 assert(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey));
3143 mtx.vjoinsplit.push_back(jsdesc);
3145 // Empty output script.
3147 CTransaction signTx(mtx);
3148 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
3149 uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
3151 // Add the signature
3152 assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
3153 dataToBeSigned.begin(), 32,
3158 assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
3159 dataToBeSigned.begin(), 32,
3160 mtx.joinSplitPubKey.begin()
3163 CTransaction rawTx(mtx);
3165 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
3168 std::string encryptedNote1;
3169 std::string encryptedNote2;
3171 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
3172 ss2 << ((unsigned char) 0x00);
3173 ss2 << jsdesc.ephemeralKey;
3174 ss2 << jsdesc.ciphertexts[0];
3175 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
3177 encryptedNote1 = HexStr(ss2.begin(), ss2.end());
3180 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
3181 ss2 << ((unsigned char) 0x01);
3182 ss2 << jsdesc.ephemeralKey;
3183 ss2 << jsdesc.ciphertexts[1];
3184 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
3186 encryptedNote2 = HexStr(ss2.begin(), ss2.end());
3189 UniValue result(UniValue::VOBJ);
3190 result.push_back(Pair("encryptednote1", encryptedNote1));
3191 result.push_back(Pair("encryptednote2", encryptedNote2));
3192 result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
3196 UniValue zc_raw_keygen(const UniValue& params, bool fHelp)
3198 if (!EnsureWalletIsAvailable(fHelp)) {
3199 return NullUniValue;
3202 if (fHelp || params.size() != 0) {
3203 throw runtime_error(
3206 "DEPRECATED. Generate a zcaddr which can send and receive confidential values.\n"
3209 " \"zcaddress\": zcaddr,\n"
3210 " \"zcsecretkey\": zcsecretkey,\n"
3211 " \"zcviewingkey\": zcviewingkey,\n"
3216 auto k = SpendingKey::random();
3217 auto addr = k.address();
3218 auto viewing_key = k.viewing_key();
3220 CZCPaymentAddress pubaddr(addr);
3221 CZCSpendingKey spendingkey(k);
3222 CZCViewingKey viewingkey(viewing_key);
3224 UniValue result(UniValue::VOBJ);
3225 result.push_back(Pair("zcaddress", pubaddr.ToString()));
3226 result.push_back(Pair("zcsecretkey", spendingkey.ToString()));
3227 result.push_back(Pair("zcviewingkey", viewingkey.ToString()));
3232 UniValue z_getnewaddress(const UniValue& params, bool fHelp)
3234 if (!EnsureWalletIsAvailable(fHelp))
3235 return NullUniValue;
3237 if (fHelp || params.size() > 0)
3238 throw runtime_error(
3240 "\nReturns a new zaddr for receiving payments.\n"
3243 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) The new zaddr\n"
3245 + HelpExampleCli("z_getnewaddress", "")
3246 + HelpExampleRpc("z_getnewaddress", "")
3249 LOCK2(cs_main, pwalletMain->cs_wallet);
3251 EnsureWalletIsUnlocked();
3253 CZCPaymentAddress pubaddr = pwalletMain->GenerateNewZKey();
3254 std::string result = pubaddr.ToString();
3259 UniValue z_listaddresses(const UniValue& params, bool fHelp)
3261 if (!EnsureWalletIsAvailable(fHelp))
3262 return NullUniValue;
3264 if (fHelp || params.size() > 1)
3265 throw runtime_error(
3266 "z_listaddresses ( includeWatchonly )\n"
3267 "\nReturns the list of zaddr belonging to the wallet.\n"
3269 "1. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n"
3271 "[ (json array of string)\n"
3272 " \"zaddr\" (string) a zaddr belonging to the wallet\n"
3276 + HelpExampleCli("z_listaddresses", "")
3277 + HelpExampleRpc("z_listaddresses", "")
3280 LOCK2(cs_main, pwalletMain->cs_wallet);
3282 bool fIncludeWatchonly = false;
3283 if (params.size() > 0) {
3284 fIncludeWatchonly = params[0].get_bool();
3287 UniValue ret(UniValue::VARR);
3288 std::set<libzcash::PaymentAddress> addresses;
3289 pwalletMain->GetPaymentAddresses(addresses);
3290 for (auto addr : addresses ) {
3291 if (fIncludeWatchonly || pwalletMain->HaveSpendingKey(addr)) {
3292 ret.push_back(CZCPaymentAddress(addr).ToString());
3298 CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ignoreUnspendable=true) {
3299 set<CBitcoinAddress> setAddress;
3300 vector<COutput> vecOutputs;
3301 CAmount balance = 0;
3303 if (transparentAddress.length() > 0) {
3304 CBitcoinAddress taddr = CBitcoinAddress(transparentAddress);
3305 if (!taddr.IsValid()) {
3306 throw std::runtime_error("invalid transparent address");
3308 setAddress.insert(taddr);
3311 LOCK2(cs_main, pwalletMain->cs_wallet);
3313 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
3315 BOOST_FOREACH(const COutput& out, vecOutputs) {
3316 if (out.nDepth < minDepth) {
3320 if (ignoreUnspendable && !out.fSpendable) {
3324 if (setAddress.size()) {
3325 CTxDestination address;
3326 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3330 if (!setAddress.count(address)) {
3335 CAmount nValue = out.tx->vout[out.i].nValue; // komodo_interest
3341 CAmount getBalanceZaddr(std::string address, int minDepth = 1, bool ignoreUnspendable=true) {
3342 CAmount balance = 0;
3343 std::vector<CNotePlaintextEntry> entries;
3344 LOCK2(cs_main, pwalletMain->cs_wallet);
3345 pwalletMain->GetFilteredNotes(entries, address, minDepth, true, ignoreUnspendable);
3346 for (auto & entry : entries) {
3347 balance += CAmount(entry.plaintext.value);
3353 UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
3355 if (!EnsureWalletIsAvailable(fHelp))
3356 return NullUniValue;
3358 if (fHelp || params.size()==0 || params.size() >2)
3359 throw runtime_error(
3360 "z_listreceivedbyaddress \"address\" ( minconf )\n"
3361 "\nReturn a list of amounts received by a zaddr belonging to the node’s wallet.\n"
3363 "1. \"address\" (string) The private address.\n"
3364 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3367 " \"txid\": xxxxx, (string) the transaction id\n"
3368 " \"amount\": xxxxx, (numeric) the amount of value in the note\n"
3369 " \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
3372 + HelpExampleCli("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3373 + HelpExampleRpc("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3376 LOCK2(cs_main, pwalletMain->cs_wallet);
3379 if (params.size() > 1) {
3380 nMinDepth = params[1].get_int();
3382 if (nMinDepth < 0) {
3383 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3386 // Check that the from address is valid.
3387 auto fromaddress = params[0].get_str();
3389 libzcash::PaymentAddress zaddr;
3390 CZCPaymentAddress address(fromaddress);
3392 zaddr = address.Get();
3393 } catch (const std::runtime_error&) {
3394 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
3397 if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) {
3398 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
3402 UniValue result(UniValue::VARR);
3403 std::vector<CNotePlaintextEntry> entries;
3404 pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false, false);
3405 for (CNotePlaintextEntry & entry : entries) {
3406 UniValue obj(UniValue::VOBJ);
3407 obj.push_back(Pair("txid",entry.jsop.hash.ToString()));
3408 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value))));
3409 std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end());
3410 obj.push_back(Pair("memo", HexStr(data)));
3411 result.push_back(obj);
3417 UniValue z_getbalance(const UniValue& params, bool fHelp)
3419 if (!EnsureWalletIsAvailable(fHelp))
3420 return NullUniValue;
3422 if (fHelp || params.size()==0 || params.size() >2)
3423 throw runtime_error(
3424 "z_getbalance \"address\" ( minconf )\n"
3425 "\nReturns the balance of a taddr or zaddr belonging to the node’s wallet.\n"
3426 "\nCAUTION: If address is a watch-only zaddr, the returned balance may be larger than the actual balance,"
3427 "\nbecause spends cannot be detected with incoming viewing keys.\n"
3429 "1. \"address\" (string) The selected address. It may be a transparent or private address.\n"
3430 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3432 "amount (numeric) The total amount in KMD received for this address.\n"
3434 "\nThe total amount received by address \"myaddress\"\n"
3435 + HelpExampleCli("z_getbalance", "\"myaddress\"") +
3436 "\nThe total amount received by address \"myaddress\" at least 5 blocks confirmed\n"
3437 + HelpExampleCli("z_getbalance", "\"myaddress\" 5") +
3438 "\nAs a json rpc call\n"
3439 + HelpExampleRpc("z_getbalance", "\"myaddress\", 5")
3442 LOCK2(cs_main, pwalletMain->cs_wallet);
3445 if (params.size() > 1) {
3446 nMinDepth = params[1].get_int();
3448 if (nMinDepth < 0) {
3449 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3452 // Check that the from address is valid.
3453 auto fromaddress = params[0].get_str();
3454 bool fromTaddr = false;
3455 CBitcoinAddress taddr(fromaddress);
3456 fromTaddr = taddr.IsValid();
3457 libzcash::PaymentAddress zaddr;
3459 CZCPaymentAddress address(fromaddress);
3461 zaddr = address.Get();
3462 } catch (const std::runtime_error&) {
3463 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3465 if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) {
3466 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
3470 CAmount nBalance = 0;
3472 nBalance = getBalanceTaddr(fromaddress, nMinDepth, false);
3474 nBalance = getBalanceZaddr(fromaddress, nMinDepth, false);
3477 return ValueFromAmount(nBalance);
3481 UniValue z_gettotalbalance(const UniValue& params, bool fHelp)
3483 if (!EnsureWalletIsAvailable(fHelp))
3484 return NullUniValue;
3486 if (fHelp || params.size() > 2)
3487 throw runtime_error(
3488 "z_gettotalbalance ( minconf includeWatchonly )\n"
3489 "\nReturn the total value of funds stored in the node’s wallet.\n"
3490 "\nCAUTION: If the wallet contains watch-only zaddrs, the returned private balance may be larger than the actual balance,"
3491 "\nbecause spends cannot be detected with incoming viewing keys.\n"
3493 "1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
3494 "2. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress' and 'z_importviewingkey')\n"
3497 " \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
3498 " \"private\": xxxxx, (numeric) the total balance of private funds\n"
3499 " \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n"
3502 "\nThe total amount in the wallet\n"
3503 + HelpExampleCli("z_gettotalbalance", "") +
3504 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3505 + HelpExampleCli("z_gettotalbalance", "5") +
3506 "\nAs a json rpc call\n"
3507 + HelpExampleRpc("z_gettotalbalance", "5")
3510 LOCK2(cs_main, pwalletMain->cs_wallet);
3513 if (params.size() > 0) {
3514 nMinDepth = params[0].get_int();
3516 if (nMinDepth < 0) {
3517 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3520 bool fIncludeWatchonly = false;
3521 if (params.size() > 1) {
3522 fIncludeWatchonly = params[1].get_bool();
3525 // getbalance and "getbalance * 1 true" should return the same number
3526 // but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
3527 // pwalletMain->GetBalance() does not accept min depth parameter
3528 // so we use our own method to get balance of utxos.
3529 CAmount nBalance = getBalanceTaddr("", nMinDepth, !fIncludeWatchonly);
3530 CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth, !fIncludeWatchonly);
3531 uint64_t interest = komodo_interestsum();
3532 CAmount nTotalBalance = nBalance + nPrivateBalance;
3533 UniValue result(UniValue::VOBJ);
3534 result.push_back(Pair("transparent", FormatMoney(nBalance)));
3535 result.push_back(Pair("interest", FormatMoney(interest)));
3536 result.push_back(Pair("private", FormatMoney(nPrivateBalance)));
3537 result.push_back(Pair("total", FormatMoney(nTotalBalance)));
3541 UniValue z_getoperationresult(const UniValue& params, bool fHelp)
3543 if (!EnsureWalletIsAvailable(fHelp))
3544 return NullUniValue;
3546 if (fHelp || params.size() > 1)
3547 throw runtime_error(
3548 "z_getoperationresult ([\"operationid\", ... ]) \n"
3549 "\nRetrieve the result and status of an operation which has finished, and then remove the operation from memory."
3550 + HelpRequiringPassphrase() + "\n"
3552 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3554 "\" [object, ...]\" (array) A list of JSON objects\n"
3556 + HelpExampleCli("z_getoperationresult", "'[\"operationid\", ... ]'")
3557 + HelpExampleRpc("z_getoperationresult", "'[\"operationid\", ... ]'")
3560 // This call will remove finished operations
3561 return z_getoperationstatus_IMPL(params, true);
3564 UniValue z_getoperationstatus(const UniValue& params, bool fHelp)
3566 if (!EnsureWalletIsAvailable(fHelp))
3567 return NullUniValue;
3569 if (fHelp || params.size() > 1)
3570 throw runtime_error(
3571 "z_getoperationstatus ([\"operationid\", ... ]) \n"
3572 "\nGet operation status and any associated result or error data. The operation will remain in memory."
3573 + HelpRequiringPassphrase() + "\n"
3575 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3577 "\" [object, ...]\" (array) A list of JSON objects\n"
3579 + HelpExampleCli("z_getoperationstatus", "'[\"operationid\", ... ]'")
3580 + HelpExampleRpc("z_getoperationstatus", "'[\"operationid\", ... ]'")
3583 // This call is idempotent so we don't want to remove finished operations
3584 return z_getoperationstatus_IMPL(params, false);
3587 UniValue z_getoperationstatus_IMPL(const UniValue& params, bool fRemoveFinishedOperations=false)
3589 LOCK2(cs_main, pwalletMain->cs_wallet);
3591 std::set<AsyncRPCOperationId> filter;
3592 if (params.size()==1) {
3593 UniValue ids = params[0].get_array();
3594 for (const UniValue & v : ids.getValues()) {
3595 filter.insert(v.get_str());
3598 bool useFilter = (filter.size()>0);
3600 UniValue ret(UniValue::VARR);
3601 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3602 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3604 for (auto id : ids) {
3605 if (useFilter && !filter.count(id))
3608 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3611 // It's possible that the operation was removed from the internal queue and map during this loop
3612 // throw JSONRPCError(RPC_INVALID_PARAMETER, "No operation exists for that id.");
3615 UniValue obj = operation->getStatus();
3616 std::string s = obj["status"].get_str();
3617 if (fRemoveFinishedOperations) {
3618 // Caller is only interested in retrieving finished results
3619 if ("success"==s || "failed"==s || "cancelled"==s) {
3621 q->popOperationForId(id);
3628 std::vector<UniValue> arrTmp = ret.getValues();
3630 // sort results chronologically by creation_time
3631 std::sort(arrTmp.begin(), arrTmp.end(), [](UniValue a, UniValue b) -> bool {
3632 const int64_t t1 = find_value(a.get_obj(), "creation_time").get_int64();
3633 const int64_t t2 = find_value(b.get_obj(), "creation_time").get_int64();
3639 ret.push_backV(arrTmp);
3645 // Here we define the maximum number of zaddr outputs that can be included in a transaction.
3646 // If input notes are small, we might actually require more than one joinsplit per zaddr output.
3647 // For now though, we assume we use one joinsplit per zaddr output (and the second output note is change).
3648 // We reduce the result by 1 to ensure there is room for non-joinsplit CTransaction data.
3649 #define Z_SENDMANY_MAX_ZADDR_OUTPUTS ((MAX_TX_SIZE / JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)) - 1)
3651 // transaction.h comment: spending taddr output requires CTxIn >= 148 bytes and typical taddr txout is 34 bytes
3652 #define CTXIN_SPEND_DUST_SIZE 148
3653 #define CTXOUT_REGULAR_SIZE 34
3655 UniValue z_sendmany(const UniValue& params, bool fHelp)
3657 if (!EnsureWalletIsAvailable(fHelp))
3658 return NullUniValue;
3660 if (fHelp || params.size() < 2 || params.size() > 4)
3661 throw runtime_error(
3662 "z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee )\n"
3663 "\nSend multiple times. Amounts are double-precision floating point numbers."
3664 "\nChange from a taddr flows to a new taddr address, while change from zaddr returns to itself."
3665 "\nWhen sending coinbase UTXOs to a zaddr, change is not allowed. The entire value of the UTXO(s) must be consumed."
3666 + strprintf("\nCurrently, the maximum number of zaddr outputs is %d due to transaction size limits.\n", Z_SENDMANY_MAX_ZADDR_OUTPUTS)
3667 + HelpRequiringPassphrase() + "\n"
3669 "1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from.\n"
3670 "2. \"amounts\" (array, required) An array of json objects representing the amounts to send.\n"
3672 " \"address\":address (string, required) The address is a taddr or zaddr\n"
3673 " \"amount\":amount (numeric, required) The numeric amount in KMD is the value\n"
3674 " \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
3676 "3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
3677 "4. fee (numeric, optional, default="
3678 + strprintf("%s", FormatMoney(ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
3680 "\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
3682 + HelpExampleCli("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" '[{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]'")
3683 + HelpExampleRpc("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", [{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]")
3686 LOCK2(cs_main, pwalletMain->cs_wallet);
3688 // Check that the from address is valid.
3689 auto fromaddress = params[0].get_str();
3690 bool fromTaddr = false;
3691 CBitcoinAddress taddr(fromaddress);
3692 fromTaddr = taddr.IsValid();
3693 libzcash::PaymentAddress zaddr;
3695 CZCPaymentAddress address(fromaddress);
3697 zaddr = address.Get();
3698 } catch (const std::runtime_error&) {
3700 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3704 // Check that we have the spending key
3706 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3707 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3711 UniValue outputs = params[1].get_array();
3713 if (outputs.size()==0)
3714 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
3716 // Keep track of addresses to spot duplicates
3717 set<std::string> setAddress;
3720 std::vector<SendManyRecipient> taddrRecipients;
3721 std::vector<SendManyRecipient> zaddrRecipients;
3722 CAmount nTotalOut = 0;
3724 for (const UniValue& o : outputs.getValues()) {
3726 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
3728 // sanity check, report error if unknown key-value pairs
3729 for (const string& name_ : o.getKeys()) {
3730 std::string s = name_;
3731 if (s != "address" && s != "amount" && s!="memo")
3732 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown key: ")+s);
3735 string address = find_value(o, "address").get_str();
3736 bool isZaddr = false;
3737 CBitcoinAddress taddr(address);
3738 if (!taddr.IsValid()) {
3740 CZCPaymentAddress zaddr(address);
3743 } catch (const std::runtime_error&) {
3744 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
3748 if (setAddress.count(address))
3749 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address);
3750 setAddress.insert(address);
3752 UniValue memoValue = find_value(o, "memo");
3754 if (!memoValue.isNull()) {
3755 memo = memoValue.get_str();
3757 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo cannot be used with a taddr. It can only be used with a zaddr.");
3758 } else if (!IsHex(memo)) {
3759 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
3761 if (memo.length() > ZC_MEMO_SIZE*2) {
3762 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
3766 UniValue av = find_value(o, "amount");
3767 CAmount nAmount = AmountFromValue( av );
3769 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
3772 zaddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3774 taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3777 nTotalOut += nAmount;
3780 // Check the number of zaddr outputs does not exceed the limit.
3781 if (zaddrRecipients.size() > Z_SENDMANY_MAX_ZADDR_OUTPUTS) {
3782 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, too many zaddr outputs");
3785 // As a sanity check, estimate and verify that the size of the transaction will be valid.
3786 // Depending on the input notes, the actual tx size may turn out to be larger and perhaps invalid.
3788 CMutableTransaction mtx;
3790 for (int i = 0; i < zaddrRecipients.size(); i++) {
3791 mtx.vjoinsplit.push_back(JSDescription());
3793 CTransaction tx(mtx);
3794 txsize += tx.GetSerializeSize(SER_NETWORK, tx.nVersion);
3796 txsize += CTXIN_SPEND_DUST_SIZE;
3797 txsize += CTXOUT_REGULAR_SIZE; // There will probably be taddr change
3799 txsize += CTXOUT_REGULAR_SIZE * taddrRecipients.size();
3800 if (txsize > MAX_TX_SIZE) {
3801 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Too many outputs, size of raw transaction would be larger than limit of %d bytes", MAX_TX_SIZE ));
3804 // Minimum confirmations
3806 if (params.size() > 2) {
3807 nMinDepth = params[2].get_int();
3809 if (nMinDepth < 0) {
3810 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3813 // Fee in Zatoshis, not currency format)
3814 CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE;
3815 if (params.size() > 3) {
3816 if (params[3].get_real() == 0.0) {
3819 nFee = AmountFromValue( params[3] );
3822 // Check that the user specified fee is sane.
3823 if (nFee > nTotalOut) {
3824 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the sum of outputs %s", FormatMoney(nFee), FormatMoney(nTotalOut)));
3828 // Use input parameters as the optional context info to be returned by z_getoperationstatus and z_getoperationresult.
3829 UniValue o(UniValue::VOBJ);
3830 o.push_back(Pair("fromaddress", params[0]));
3831 o.push_back(Pair("amounts", params[1]));
3832 o.push_back(Pair("minconf", nMinDepth));
3833 o.push_back(Pair("fee", std::stod(FormatMoney(nFee))));
3834 UniValue contextInfo = o;
3836 // Contextual transaction we will build on
3837 int nextBlockHeight = chainActive.Height() + 1;
3838 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextBlockHeight);
3839 bool isShielded = !fromTaddr || zaddrRecipients.size() > 0;
3840 if (contextualTx.nVersion == 1 && isShielded) {
3841 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
3843 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
3844 contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta;
3847 // Create operation and add to global queue
3848 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3849 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(contextualTx, fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee, contextInfo) );
3850 q->addOperation(operation);
3851 AsyncRPCOperationId operationId = operation->getId();
3857 When estimating the number of coinbase utxos we can shield in a single transaction:
3858 1. Joinsplit description is 1802 bytes.
3859 2. Transaction overhead ~ 100 bytes
3860 3. Spending a typical P2PKH is >=148 bytes, as defined in CTXIN_SPEND_DUST_SIZE.
3861 4. Spending a multi-sig P2SH address can vary greatly:
3862 https://github.com/bitcoin/bitcoin/blob/c3ad56f4e0b587d8d763af03d743fdfc2d180c9b/src/main.cpp#L517
3863 In real-world coinbase utxos, we consider a 3-of-3 multisig, where the size is roughly:
3864 (3*(33+1))+3 = 105 byte redeem script
3865 105 + 1 + 3*(73+1) = 328 bytes of scriptSig, rounded up to 400 based on testnet experiments.
3867 #define CTXIN_SPEND_P2SH_SIZE 400
3869 #define SHIELD_COINBASE_DEFAULT_LIMIT 50
3871 UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
3873 if (!EnsureWalletIsAvailable(fHelp))
3874 return NullUniValue;
3876 if (fHelp || params.size() < 2 || params.size() > 4)
3877 throw runtime_error(
3878 "z_shieldcoinbase \"fromaddress\" \"tozaddress\" ( fee ) ( limit )\n"
3879 "\nShield transparent coinbase funds by sending to a shielded zaddr. This is an asynchronous operation and utxos"
3880 "\nselected for shielding will be locked. If there is an error, they are unlocked. The RPC call `listlockunspent`"
3881 "\ncan be used to return a list of locked utxos. The number of coinbase utxos selected for shielding can be limited"
3882 "\nby the caller. If the limit parameter is set to zero, the -mempooltxinputlimit option will determine the number"
3883 "\nof uxtos. Any limit is constrained by the consensus rule defining a maximum transaction size of "
3884 + strprintf("%d bytes.", MAX_TX_SIZE)
3885 + HelpRequiringPassphrase() + "\n"
3887 "1. \"fromaddress\" (string, required) The address is a taddr or \"*\" for all taddrs belonging to the wallet.\n"
3888 "2. \"toaddress\" (string, required) The address is a zaddr.\n"
3889 "3. fee (numeric, optional, default="
3890 + strprintf("%s", FormatMoney(SHIELD_COINBASE_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
3891 "4. limit (numeric, optional, default="
3892 + strprintf("%d", SHIELD_COINBASE_DEFAULT_LIMIT) + ") Limit on the maximum number of utxos to shield. Set to 0 to use node option -mempooltxinputlimit.\n"
3895 " \"remainingUTXOs\": xxx (numeric) Number of coinbase utxos still available for shielding.\n"
3896 " \"remainingValue\": xxx (numeric) Value of coinbase utxos still available for shielding.\n"
3897 " \"shieldingUTXOs\": xxx (numeric) Number of coinbase utxos being shielded.\n"
3898 " \"shieldingValue\": xxx (numeric) Value of coinbase utxos being shielded.\n"
3899 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
3902 + HelpExampleCli("z_shieldcoinbase", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3903 + HelpExampleRpc("z_shieldcoinbase", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3906 LOCK2(cs_main, pwalletMain->cs_wallet);
3908 // Validate the from address
3909 auto fromaddress = params[0].get_str();
3910 bool isFromWildcard = fromaddress == "*";
3911 CBitcoinAddress taddr;
3912 if (!isFromWildcard) {
3913 taddr = CBitcoinAddress(fromaddress);
3914 if (!taddr.IsValid()) {
3915 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or \"*\".");
3919 // Validate the destination address
3920 auto destaddress = params[1].get_str();
3922 CZCPaymentAddress pa(destaddress);
3923 libzcash::PaymentAddress zaddr = pa.Get();
3924 } catch (const std::runtime_error&) {
3925 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
3928 // Convert fee from currency format to zatoshis
3929 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
3930 if (params.size() > 2) {
3931 if (params[2].get_real() == 0.0) {
3934 nFee = AmountFromValue( params[2] );
3938 int nLimit = SHIELD_COINBASE_DEFAULT_LIMIT;
3939 if (params.size() > 3) {
3940 nLimit = params[3].get_int();
3942 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of utxos cannot be negative");
3946 // Prepare to get coinbase utxos
3947 std::vector<ShieldCoinbaseUTXO> inputs;
3948 CAmount shieldedValue = 0;
3949 CAmount remainingValue = 0;
3950 size_t estimatedTxSize = 2000; // 1802 joinsplit description + tx overhead + wiggle room
3953 uint64_t utxoCounter = 0;
3955 size_t utxoCounter = 0;
3958 bool maxedOutFlag = false;
3959 size_t mempoolLimit = (nLimit != 0) ? nLimit : (size_t)GetArg("-mempooltxinputlimit", 0);
3961 // Set of addresses to filter utxos by
3962 set<CBitcoinAddress> setAddress = {};
3963 if (!isFromWildcard) {
3964 setAddress.insert(taddr);
3967 // Get available utxos
3968 vector<COutput> vecOutputs;
3969 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true);
3971 // Find unspent coinbase utxos and update estimated size
3972 BOOST_FOREACH(const COutput& out, vecOutputs) {
3973 if (!out.fSpendable) {
3977 CTxDestination address;
3978 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3981 // If taddr is not wildcard "*", filter utxos
3982 if (setAddress.size()>0 && !setAddress.count(address)) {
3986 if (!out.tx->IsCoinBase()) {
3991 CAmount nValue = out.tx->vout[out.i].nValue;
3993 if (!maxedOutFlag) {
3994 CBitcoinAddress ba(address);
3995 size_t increase = (ba.IsScript()) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
3996 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
3997 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
3999 maxedOutFlag = true;
4001 estimatedTxSize += increase;
4002 ShieldCoinbaseUTXO utxo = {out.tx->GetHash(), out.i, nValue};
4003 inputs.push_back(utxo);
4004 shieldedValue += nValue;
4009 remainingValue += nValue;
4014 uint64_t numUtxos = inputs.size();
4016 size_t numUtxos = inputs.size();
4019 if (numUtxos == 0) {
4020 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any coinbase funds to shield.");
4023 if (shieldedValue < nFee) {
4024 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
4025 strprintf("Insufficient coinbase funds, have %s, which is less than miners fee %s",
4026 FormatMoney(shieldedValue), FormatMoney(nFee)));
4029 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
4030 CAmount netAmount = shieldedValue - nFee;
4031 if (nFee > netAmount) {
4032 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
4035 // Keep record of parameters in context object
4036 UniValue contextInfo(UniValue::VOBJ);
4037 contextInfo.push_back(Pair("fromaddress", params[0]));
4038 contextInfo.push_back(Pair("toaddress", params[1]));
4039 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
4041 // Contextual transaction we will build on
4042 int nextBlockHeight = chainActive.Height() + 1;
4043 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
4044 Params().GetConsensus(), nextBlockHeight);
4045 if (contextualTx.nVersion == 1) {
4046 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
4048 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
4049 contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta;
4052 // Create operation and add to global queue
4053 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4054 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(contextualTx, inputs, destaddress, nFee, contextInfo) );
4055 q->addOperation(operation);
4056 AsyncRPCOperationId operationId = operation->getId();
4058 // Return continuation information
4059 UniValue o(UniValue::VOBJ);
4060 o.push_back(Pair("remainingUTXOs", utxoCounter - numUtxos));
4061 o.push_back(Pair("remainingValue", ValueFromAmount(remainingValue)));
4062 o.push_back(Pair("shieldingUTXOs", numUtxos));
4063 o.push_back(Pair("shieldingValue", ValueFromAmount(shieldedValue)));
4064 o.push_back(Pair("opid", operationId));
4069 #define MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT 50
4070 #define MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT 10
4072 #define JOINSPLIT_SIZE JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)
4074 UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
4076 if (!EnsureWalletIsAvailable(fHelp))
4077 return NullUniValue;
4079 auto fEnableMergeToAddress = true; //fExperimentalMode && GetBoolArg("-zmergetoaddress", false);
4080 std::string strDisabledMsg = "";
4081 if (!fEnableMergeToAddress) {
4082 strDisabledMsg = "\nWARNING: z_mergetoaddress is DISABLED but can be enabled as an experimental feature.\n";
4085 if (fHelp || params.size() < 2 || params.size() > 6)
4086 throw runtime_error(
4087 "z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n"
4089 "\nMerge multiple UTXOs and notes into a single UTXO or note. Coinbase UTXOs are ignored; use `z_shieldcoinbase`"
4090 "\nto combine those into a single note."
4091 "\n\nThis is an asynchronous operation, and UTXOs selected for merging will be locked. If there is an error, they"
4092 "\nare unlocked. The RPC call `listlockunspent` can be used to return a list of locked UTXOs."
4093 "\n\nThe number of UTXOs and notes selected for merging can be limited by the caller. If the transparent limit"
4094 "\nparameter is set to zero, the -mempooltxinputlimit option will determine the number of UTXOs. Any limit is"
4095 "\nconstrained by the consensus rule defining a maximum transaction size of "
4096 + strprintf("%d bytes.", MAX_TX_SIZE)
4097 + HelpRequiringPassphrase() + "\n"
4099 "1. fromaddresses (string, required) A JSON array with addresses.\n"
4100 " The following special strings are accepted inside the array:\n"
4101 " - \"*\": Merge both UTXOs and notes from all addresses belonging to the wallet.\n"
4102 " - \"ANY_TADDR\": Merge UTXOs from all t-addrs belonging to the wallet.\n"
4103 " - \"ANY_ZADDR\": Merge notes from all z-addrs belonging to the wallet.\n"
4104 " If a special string is given, any given addresses of that type will be ignored.\n"
4106 " \"address\" (string) Can be a t-addr or a z-addr\n"
4109 "2. \"toaddress\" (string, required) The t-addr or z-addr to send the funds to.\n"
4110 "3. fee (numeric, optional, default="
4111 + strprintf("%s", FormatMoney(MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
4112 "4. transparent_limit (numeric, optional, default="
4113 + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT) + ") Limit on the maximum number of UTXOs to merge. Set to 0 to use node option -mempooltxinputlimit.\n"
4114 "4. shielded_limit (numeric, optional, default="
4115 + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT) + ") Limit on the maximum number of notes to merge. Set to 0 to merge as many as will fit in the transaction.\n"
4116 "5. \"memo\" (string, optional) Encoded as hex. When toaddress is a z-addr, this will be stored in the memo field of the new note.\n"
4119 " \"remainingUTXOs\": xxx (numeric) Number of UTXOs still available for merging.\n"
4120 " \"remainingTransparentValue\": xxx (numeric) Value of UTXOs still available for merging.\n"
4121 " \"remainingNotes\": xxx (numeric) Number of notes still available for merging.\n"
4122 " \"remainingShieldedValue\": xxx (numeric) Value of notes still available for merging.\n"
4123 " \"mergingUTXOs\": xxx (numeric) Number of UTXOs being merged.\n"
4124 " \"mergingTransparentValue\": xxx (numeric) Value of UTXOs being merged.\n"
4125 " \"mergingNotes\": xxx (numeric) Number of notes being merged.\n"
4126 " \"mergingShieldedValue\": xxx (numeric) Value of notes being merged.\n"
4127 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
4130 + HelpExampleCli("z_mergetoaddress", "'[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"]' ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf")
4131 + HelpExampleRpc("z_mergetoaddress", "[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"], \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
4134 if (!fEnableMergeToAddress) {
4135 throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_mergetoaddress is disabled.");
4138 LOCK2(cs_main, pwalletMain->cs_wallet);
4140 bool useAny = false;
4141 bool useAnyUTXO = false;
4142 bool useAnyNote = false;
4143 std::set<CBitcoinAddress> taddrs = {};
4144 std::set<libzcash::PaymentAddress> zaddrs = {};
4146 UniValue addresses = params[0].get_array();
4147 if (addresses.size()==0)
4148 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, fromaddresses array is empty.");
4150 // Keep track of addresses to spot duplicates
4151 std::set<std::string> setAddress;
4154 for (const UniValue& o : addresses.getValues()) {
4156 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
4158 std::string address = o.get_str();
4159 if (address == "*") {
4161 } else if (address == "ANY_TADDR") {
4163 } else if (address == "ANY_ZADDR") {
4166 CBitcoinAddress taddr(address);
4167 if (taddr.IsValid()) {
4168 // Ignore any listed t-addrs if we are using all of them
4169 if (!(useAny || useAnyUTXO)) {
4170 taddrs.insert(taddr);
4174 CZCPaymentAddress zaddr(address);
4175 // Ignore listed z-addrs if we are using all of them
4176 if (!(useAny || useAnyNote)) {
4177 zaddrs.insert(zaddr.Get());
4179 } catch (const std::runtime_error&) {
4181 RPC_INVALID_PARAMETER,
4182 string("Invalid parameter, unknown address format: ") + address);
4187 if (setAddress.count(address))
4188 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + address);
4189 setAddress.insert(address);
4192 // Validate the destination address
4193 auto destaddress = params[1].get_str();
4194 bool isToZaddr = false;
4195 CBitcoinAddress taddr(destaddress);
4196 if (!taddr.IsValid()) {
4198 CZCPaymentAddress zaddr(destaddress);
4201 } catch (const std::runtime_error&) {
4202 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
4206 // Convert fee from currency format to zatoshis
4207 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
4208 if (params.size() > 2) {
4209 if (params[2].get_real() == 0.0) {
4212 nFee = AmountFromValue( params[2] );
4216 int nUTXOLimit = MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT;
4217 if (params.size() > 3) {
4218 nUTXOLimit = params[3].get_int();
4219 if (nUTXOLimit < 0) {
4220 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of UTXOs cannot be negative");
4224 int nNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT;
4225 if (params.size() > 4) {
4226 nNoteLimit = params[4].get_int();
4227 if (nNoteLimit < 0) {
4228 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of notes cannot be negative");
4233 if (params.size() > 5) {
4234 memo = params[5].get_str();
4236 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
4237 } else if (!IsHex(memo)) {
4238 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
4240 if (memo.length() > ZC_MEMO_SIZE*2) {
4241 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
4245 MergeToAddressRecipient recipient(destaddress, memo);
4247 // Prepare to get UTXOs and notes
4248 std::vector<MergeToAddressInputUTXO> utxoInputs;
4249 std::vector<MergeToAddressInputNote> noteInputs;
4250 CAmount mergedUTXOValue = 0;
4251 CAmount mergedNoteValue = 0;
4252 CAmount remainingUTXOValue = 0;
4253 CAmount remainingNoteValue = 0;
4255 uint64_t utxoCounter = 0;
4256 uint64_t noteCounter = 0;
4258 size_t utxoCounter = 0;
4259 size_t noteCounter = 0;
4261 bool maxedOutUTXOsFlag = false;
4262 bool maxedOutNotesFlag = false;
4263 size_t mempoolLimit = (nUTXOLimit != 0) ? nUTXOLimit : (size_t)GetArg("-mempooltxinputlimit", 0);
4265 size_t estimatedTxSize = 200; // tx overhead + wiggle room
4267 estimatedTxSize += JOINSPLIT_SIZE;
4270 if (useAny || useAnyUTXO || taddrs.size() > 0) {
4271 // Get available utxos
4272 vector<COutput> vecOutputs;
4273 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, false);
4275 // Find unspent utxos and update estimated size
4276 for (const COutput& out : vecOutputs) {
4277 if (!out.fSpendable) {
4281 CTxDestination address;
4282 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
4285 // If taddr is not wildcard "*", filter utxos
4286 if (taddrs.size() > 0 && !taddrs.count(address)) {
4291 CAmount nValue = out.tx->vout[out.i].nValue;
4293 if (!maxedOutUTXOsFlag) {
4294 CBitcoinAddress ba(address);
4295 size_t increase = (ba.IsScript()) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
4296 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
4297 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
4299 maxedOutUTXOsFlag = true;
4301 estimatedTxSize += increase;
4302 COutPoint utxo(out.tx->GetHash(), out.i);
4303 utxoInputs.emplace_back(utxo, nValue);
4304 mergedUTXOValue += nValue;
4308 if (maxedOutUTXOsFlag) {
4309 remainingUTXOValue += nValue;
4314 if (useAny || useAnyNote || zaddrs.size() > 0) {
4315 // Get available notes
4316 std::vector<CNotePlaintextEntry> entries;
4317 pwalletMain->GetFilteredNotes(entries, zaddrs);
4319 // Find unspent notes and update estimated size
4320 for (CNotePlaintextEntry& entry : entries) {
4322 CAmount nValue = entry.plaintext.value;
4324 if (!maxedOutNotesFlag) {
4325 // If we haven't added any notes yet and the merge is to a
4326 // z-address, we have already accounted for the first JoinSplit.
4327 size_t increase = (noteInputs.empty() && !isToZaddr) || (noteInputs.size() % 2 == 0) ? JOINSPLIT_SIZE : 0;
4328 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
4329 (nNoteLimit > 0 && noteCounter > nNoteLimit))
4331 maxedOutNotesFlag = true;
4333 estimatedTxSize += increase;
4335 pwalletMain->GetSpendingKey(entry.address, zkey);
4336 noteInputs.emplace_back(entry.jsop, entry.plaintext.note(entry.address), nValue, zkey);
4337 mergedNoteValue += nValue;
4341 if (maxedOutNotesFlag) {
4342 remainingNoteValue += nValue;
4348 uint64_t numUtxos = utxoInputs.size(); //ca333
4349 uint64_t numNotes = noteInputs.size();
4351 size_t numUtxos = utxoInputs.size();
4352 size_t numNotes = noteInputs.size();
4356 if (numUtxos == 0 && numNotes == 0) {
4357 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any funds to merge.");
4360 // Sanity check: Don't do anything if:
4361 // - We only have one from address
4362 // - It's equal to toaddress
4363 // - The address only contains a single UTXO or note
4364 if (setAddress.size() == 1 && setAddress.count(destaddress) && (numUtxos + numNotes) == 1) {
4365 throw JSONRPCError(RPC_INVALID_PARAMETER, "Destination address is also the only source address, and all its funds are already merged.");
4368 CAmount mergedValue = mergedUTXOValue + mergedNoteValue;
4369 if (mergedValue < nFee) {
4370 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
4371 strprintf("Insufficient funds, have %s, which is less than miners fee %s",
4372 FormatMoney(mergedValue), FormatMoney(nFee)));
4375 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
4376 CAmount netAmount = mergedValue - nFee;
4377 if (nFee > netAmount) {
4378 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
4381 // Keep record of parameters in context object
4382 UniValue contextInfo(UniValue::VOBJ);
4383 contextInfo.push_back(Pair("fromaddresses", params[0]));
4384 contextInfo.push_back(Pair("toaddress", params[1]));
4385 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
4387 // Contextual transaction we will build on
4388 int nextBlockHeight = chainActive.Height() + 1;
4389 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
4390 Params().GetConsensus(),
4392 bool isShielded = numNotes > 0 || isToZaddr;
4393 if (contextualTx.nVersion == 1 && isShielded) {
4394 contextualTx.nVersion = 2; // Tx format should support vjoinsplit
4396 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
4397 contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta;
4400 // Create operation and add to global queue
4401 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4402 std::shared_ptr<AsyncRPCOperation> operation(
4403 new AsyncRPCOperation_mergetoaddress(contextualTx, utxoInputs, noteInputs, recipient, nFee, contextInfo) );
4404 q->addOperation(operation);
4405 AsyncRPCOperationId operationId = operation->getId();
4407 // Return continuation information
4408 UniValue o(UniValue::VOBJ);
4409 o.push_back(Pair("remainingUTXOs", utxoCounter - numUtxos));
4410 o.push_back(Pair("remainingTransparentValue", ValueFromAmount(remainingUTXOValue)));
4411 o.push_back(Pair("remainingNotes", noteCounter - numNotes));
4412 o.push_back(Pair("remainingShieldedValue", ValueFromAmount(remainingNoteValue)));
4413 o.push_back(Pair("mergingUTXOs", numUtxos));
4414 o.push_back(Pair("mergingTransparentValue", ValueFromAmount(mergedUTXOValue)));
4415 o.push_back(Pair("mergingNotes", numNotes));
4416 o.push_back(Pair("mergingShieldedValue", ValueFromAmount(mergedNoteValue)));
4417 o.push_back(Pair("opid", operationId));
4422 UniValue z_listoperationids(const UniValue& params, bool fHelp)
4424 if (!EnsureWalletIsAvailable(fHelp))
4425 return NullUniValue;
4427 if (fHelp || params.size() > 1)
4428 throw runtime_error(
4429 "z_listoperationids\n"
4430 "\nReturns the list of operation ids currently known to the wallet.\n"
4432 "1. \"status\" (string, optional) Filter result by the operation's state e.g. \"success\".\n"
4434 "[ (json array of string)\n"
4435 " \"operationid\" (string) an operation id belonging to the wallet\n"
4439 + HelpExampleCli("z_listoperationids", "")
4440 + HelpExampleRpc("z_listoperationids", "")
4443 LOCK2(cs_main, pwalletMain->cs_wallet);
4446 bool useFilter = false;
4447 if (params.size()==1) {
4448 filter = params[0].get_str();
4452 UniValue ret(UniValue::VARR);
4453 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4454 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
4455 for (auto id : ids) {
4456 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
4460 std::string state = operation->getStateAsString();
4461 if (useFilter && filter.compare(state)!=0)
4470 #include "script/sign.h"
4471 int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
4472 extern std::string NOTARY_PUBKEY;
4473 uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime,char *destaddr);
4475 int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33)
4477 set<CBitcoinAddress> setAddress; uint8_t *script,utxosig[128]; uint256 utxotxid; uint64_t utxovalue; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector<COutput> vecOutputs; uint32_t utxovout,eligible,earliest = 0; CScript best_scriptPubKey; bool fNegative,fOverflow;
4478 bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr;
4479 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
4480 const CKeyStore& keystore = *pwalletMain;
4481 assert(pwalletMain != NULL);
4482 LOCK2(cs_main, pwalletMain->cs_wallet);
4484 memset(&utxotxid,0,sizeof(utxotxid));
4485 memset(&utxovout,0,sizeof(utxovout));
4486 memset(utxosig,0,sizeof(utxosig));
4487 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
4488 BOOST_FOREACH(const COutput& out, vecOutputs)
4490 if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth )
4492 if ( setAddress.size() )
4494 CTxDestination address;
4495 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
4497 if (!setAddress.count(address))
4500 CAmount nValue = out.tx->vout[out.i].nValue;
4501 if ( nValue != 10000 )
4503 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
4504 CTxDestination address;
4505 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
4507 //entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
4508 //if (pwalletMain->mapAddressBook.count(address))
4509 // entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
4511 script = (uint8_t *)out.tx->vout[out.i].scriptPubKey.data();
4512 if ( out.tx->vout[out.i].scriptPubKey.size() != 35 || script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(notarypub33,script+1,33) != 0 )
4514 //fprintf(stderr,"scriptsize.%d [0] %02x\n",(int32_t)out.tx->vout[out.i].scriptPubKey.size(),script[0]);
4517 utxovalue = (uint64_t)nValue;
4518 //decode_hex((uint8_t *)&utxotxid,32,(char *)out.tx->GetHash().GetHex().c_str());
4519 utxotxid = out.tx->GetHash();
4521 best_scriptPubKey = out.tx->vout[out.i].scriptPubKey;
4522 //fprintf(stderr,"check %s/v%d %llu\n",(char *)utxotxid.GetHex().c_str(),utxovout,(long long)utxovalue);
4524 txNew.vin.resize(1);
4525 txNew.vout.resize(1);
4526 txfee = utxovalue / 2;
4527 //for (i=0; i<32; i++)
4528 // ((uint8_t *)&revtxid)[i] = ((uint8_t *)&utxotxid)[31 - i];
4529 txNew.vin[0].prevout.hash = utxotxid; //revtxid;
4530 txNew.vin[0].prevout.n = utxovout;
4531 txNew.vout[0].scriptPubKey = CScript() << ParseHex(CRYPTO777_PUBSECPSTR) << OP_CHECKSIG;
4532 txNew.vout[0].nValue = utxovalue - txfee;
4533 CTransaction txNewConst(txNew);
4534 signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, utxovalue, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId);
4536 fprintf(stderr,"notaryvin failed to create signature\n");
4539 UpdateTransaction(txNew,0,sigdata);
4540 ptr = (uint8_t *)sigdata.scriptSig.data();
4541 siglen = sigdata.scriptSig.size();
4542 for (i=0; i<siglen; i++)
4543 utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]);
4544 //fprintf(stderr," siglen.%d notaryvin %s/v%d\n",siglen,utxotxid.GetHex().c_str(),utxovout);
4551 int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig)
4553 set<CBitcoinAddress> setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector<COutput> vecOutputs; uint32_t eligible,earliest = 0; CScript best_scriptPubKey; arith_uint256 bnTarget; bool fNegative,fOverflow;
4554 bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
4555 assert(pwalletMain != NULL);
4556 LOCK2(cs_main, pwalletMain->cs_wallet);
4558 memset(utxotxidp,0,sizeof(*utxotxidp));
4559 memset(utxovoutp,0,sizeof(*utxovoutp));
4560 memset(utxosig,0,72);
4561 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
4562 BOOST_FOREACH(const COutput& out, vecOutputs)
4564 if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth )
4566 if ( setAddress.size() )
4568 CTxDestination address;
4569 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
4571 if (!setAddress.count(address))
4574 CAmount nValue = out.tx->vout[out.i].nValue;
4575 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
4576 //entry.push_back(Pair("generated", out.tx->IsCoinBase()));
4577 CTxDestination address;
4578 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
4580 //entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
4581 //if (pwalletMain->mapAddressBook.count(address))
4582 // entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
4584 //BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
4585 CBlockIndex *tipindex;
4586 if ( (tipindex= chainActive.Tip()) != 0 )
4588 eligible = komodo_stake(0,bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,0,(uint32_t)tipindex->nTime,(char *)CBitcoinAddress(address).ToString().c_str());
4591 if ( eligible != komodo_stake(1,bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,eligible,(uint32_t)tipindex->nTime,(char *)CBitcoinAddress(address).ToString().c_str()) )
4593 fprintf(stderr,"tip.%d validation of winning blocktime failed %u -> eligible.%u\n",(uint32_t)tipindex->nHeight,*blocktimep,eligible);
4595 else if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || nValue < *utxovaluep)) )
4597 earliest = eligible;
4598 best_scriptPubKey = out.tx->vout[out.i].scriptPubKey;
4599 *utxovaluep = (uint64_t)nValue;
4600 decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str());
4602 *txtimep = (uint32_t)out.tx->nLockTime;
4603 fprintf(stderr,"earliest.%u [%d] (%s) nValue %.8f locktime.%u\n",earliest,(int32_t)(earliest- *blocktimep),CBitcoinAddress(address).ToString().c_str(),(double)nValue/COIN,*txtimep);
4608 if ( earliest != 0 )
4610 bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid;
4611 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
4612 const CKeyStore& keystore = *pwalletMain;
4613 txNew.vin.resize(1);
4614 txNew.vout.resize(1);
4616 for (i=0; i<32; i++)
4617 ((uint8_t *)&revtxid)[i] = ((uint8_t *)utxotxidp)[31 - i];
4618 txNew.vin[0].prevout.hash = revtxid;
4619 txNew.vin[0].prevout.n = *utxovoutp;
4620 txNew.vout[0].scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG;
4621 txNew.vout[0].nValue = *utxovaluep - txfee;
4622 txNew.nLockTime = earliest;
4623 CTransaction txNewConst(txNew);
4624 signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, *utxovaluep, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId);
4626 fprintf(stderr,"failed to create signature\n");
4629 UpdateTransaction(txNew,0,sigdata);
4630 ptr = (uint8_t *)sigdata.scriptSig.data();
4631 siglen = sigdata.scriptSig.size();
4632 for (i=0; i<siglen; i++)
4633 utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]);
4634 //fprintf(stderr," siglen.%d\n",siglen);
4635 fprintf(stderr,"best %u from %u, gap %d lag.%d\n",earliest,*blocktimep,(int32_t)(earliest - *blocktimep),(int32_t)(time(NULL) - *blocktimep));
4636 *blocktimep = earliest;
4638 } else fprintf(stderr,"no earliest utxo for staking\n");