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 UniValue TxJoinSplitToJSON(const CTransaction& tx);
47 int64_t nWalletUnlockTime;
48 static CCriticalSection cs_nWalletUnlockTime;
51 UniValue z_getoperationstatus_IMPL(const UniValue&, bool);
53 std::string HelpRequiringPassphrase()
55 return pwalletMain && pwalletMain->IsCrypted()
56 ? "\nRequires wallet passphrase to be set with walletpassphrase call."
60 bool EnsureWalletIsAvailable(bool avoidException)
65 throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
72 void EnsureWalletIsUnlocked()
74 if (pwalletMain->IsLocked())
75 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
78 uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight);
79 uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
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 UniValue getnewaddress(const UniValue& params, bool fHelp)
119 if (!EnsureWalletIsAvailable(fHelp))
122 if (fHelp || params.size() > 1)
124 "getnewaddress ( \"account\" )\n"
125 "\nReturns a new Komodo address for receiving payments.\n"
127 "1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
129 "\"zcashaddress\" (string) The new Zcash address\n"
131 + HelpExampleCli("getnewaddress", "")
132 + HelpExampleRpc("getnewaddress", "")
135 LOCK2(cs_main, pwalletMain->cs_wallet);
137 // Parse the account first so we don't generate a key if there's an error
139 if (params.size() > 0)
140 strAccount = AccountFromValue(params[0]);
142 if (!pwalletMain->IsLocked())
143 pwalletMain->TopUpKeyPool();
145 // Generate a new key that is added to wallet
147 if (!pwalletMain->GetKeyFromPool(newKey))
148 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
149 CKeyID keyID = newKey.GetID();
151 pwalletMain->SetAddressBook(keyID, strAccount, "receive");
153 return CBitcoinAddress(keyID).ToString();
157 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
159 CWalletDB walletdb(pwalletMain->strWalletFile);
162 walletdb.ReadAccount(strAccount, account);
164 bool bKeyUsed = false;
166 // Check if the current key has been used
167 if (account.vchPubKey.IsValid())
169 CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
170 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
171 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
174 const CWalletTx& wtx = (*it).second;
175 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
176 if (txout.scriptPubKey == scriptPubKey)
181 // Generate a new key
182 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
184 if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
185 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
187 pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
188 walletdb.WriteAccount(strAccount, account);
191 return CBitcoinAddress(account.vchPubKey.GetID());
194 UniValue getaccountaddress(const UniValue& params, bool fHelp)
196 if (!EnsureWalletIsAvailable(fHelp))
199 if (fHelp || params.size() != 1)
201 "getaccountaddress \"account\"\n"
202 "\nDEPRECATED. Returns the current Komodo address for receiving payments to this account.\n"
204 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
206 "\"zcashaddress\" (string) The account Zcash address\n"
208 + HelpExampleCli("getaccountaddress", "")
209 + HelpExampleCli("getaccountaddress", "\"\"")
210 + HelpExampleCli("getaccountaddress", "\"myaccount\"")
211 + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
214 LOCK2(cs_main, pwalletMain->cs_wallet);
216 // Parse the account first so we don't generate a key if there's an error
217 string strAccount = AccountFromValue(params[0]);
219 UniValue ret(UniValue::VSTR);
221 ret = GetAccountAddress(strAccount).ToString();
226 UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
228 if (!EnsureWalletIsAvailable(fHelp))
231 if (fHelp || params.size() > 1)
233 "getrawchangeaddress\n"
234 "\nReturns a new Komodo address, for receiving change.\n"
235 "This is for use with raw transactions, NOT normal use.\n"
237 "\"address\" (string) The address\n"
239 + HelpExampleCli("getrawchangeaddress", "")
240 + HelpExampleRpc("getrawchangeaddress", "")
243 LOCK2(cs_main, pwalletMain->cs_wallet);
245 if (!pwalletMain->IsLocked())
246 pwalletMain->TopUpKeyPool();
248 CReserveKey reservekey(pwalletMain);
250 if (!reservekey.GetReservedKey(vchPubKey))
251 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
253 reservekey.KeepKey();
255 CKeyID keyID = vchPubKey.GetID();
257 return CBitcoinAddress(keyID).ToString();
261 UniValue setaccount(const UniValue& params, bool fHelp)
263 if (!EnsureWalletIsAvailable(fHelp))
266 if (fHelp || params.size() < 1 || params.size() > 2)
268 "setaccount \"zcashaddress\" \"account\"\n"
269 "\nDEPRECATED. Sets the account associated with the given address.\n"
271 "1. \"zcashaddress\" (string, required) The Zcash address to be associated with an account.\n"
272 "2. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
274 + HelpExampleCli("setaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"tabby\"")
275 + HelpExampleRpc("setaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", \"tabby\"")
278 LOCK2(cs_main, pwalletMain->cs_wallet);
280 CBitcoinAddress address(params[0].get_str());
281 if (!address.IsValid())
282 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address");
285 if (params.size() > 1)
286 strAccount = AccountFromValue(params[1]);
288 // Only add the account if the address is yours.
289 if (IsMine(*pwalletMain, address.Get()))
291 // Detect when changing the account of an address that is the 'unused current key' of another account:
292 if (pwalletMain->mapAddressBook.count(address.Get()))
294 string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name;
295 if (address == GetAccountAddress(strOldAccount))
296 GetAccountAddress(strOldAccount, true);
298 pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
301 throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
307 UniValue getaccount(const UniValue& params, bool fHelp)
309 if (!EnsureWalletIsAvailable(fHelp))
312 if (fHelp || params.size() != 1)
314 "getaccount \"zcashaddress\"\n"
315 "\nDEPRECATED. Returns the account associated with the given address.\n"
317 "1. \"zcashaddress\" (string, required) The Zcash address for account lookup.\n"
319 "\"accountname\" (string) the account address\n"
321 + HelpExampleCli("getaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"")
322 + HelpExampleRpc("getaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"")
325 LOCK2(cs_main, pwalletMain->cs_wallet);
327 CBitcoinAddress address(params[0].get_str());
328 if (!address.IsValid())
329 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address");
332 map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
333 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty())
334 strAccount = (*mi).second.name;
339 UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
341 if (!EnsureWalletIsAvailable(fHelp))
344 if (fHelp || params.size() != 1)
346 "getaddressesbyaccount \"account\"\n"
347 "\nDEPRECATED. Returns the list of addresses for the given account.\n"
349 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
351 "[ (json array of string)\n"
352 " \"zcashaddress\" (string) a Zcash address associated with the given account\n"
356 + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
357 + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
360 LOCK2(cs_main, pwalletMain->cs_wallet);
362 string strAccount = AccountFromValue(params[0]);
364 // Find all addresses that have the given account
365 UniValue ret(UniValue::VARR);
366 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
368 const CBitcoinAddress& address = item.first;
369 const string& strName = item.second.name;
370 if (strName == strAccount)
371 ret.push_back(address.ToString());
376 static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew,uint8_t *opretbuf,int32_t opretlen,long int opretValue)
378 CAmount curBalance = pwalletMain->GetBalance();
382 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
384 if (nValue > curBalance)
385 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
387 // Parse Zcash address
388 CScript scriptPubKey = GetScriptForDestination(address);
390 // Create and send the transaction
391 CReserveKey reservekey(pwalletMain);
392 CAmount nFeeRequired;
393 std::string strError;
394 vector<CRecipient> vecSend;
395 int nChangePosRet = -1;
396 CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
397 vecSend.push_back(recipient);
398 if ( opretlen > 0 && opretbuf != 0 )
400 CScript opretpubkey; int32_t i; uint8_t *ptr;
401 opretpubkey.resize(opretlen);
402 ptr = (uint8_t *)opretpubkey.data();
403 for (i=0; i<opretlen; i++)
405 ptr[i] = opretbuf[i];
406 //printf("%02x",ptr[i]);
408 //printf(" opretbuf[%d]\n",opretlen);
409 CRecipient opret = { opretpubkey, opretValue, false };
410 vecSend.push_back(opret);
412 if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
413 if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
414 strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired));
415 throw JSONRPCError(RPC_WALLET_ERROR, strError);
417 if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
418 throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
421 UniValue sendtoaddress(const UniValue& params, bool fHelp)
423 if (!EnsureWalletIsAvailable(fHelp))
426 if (fHelp || params.size() < 2 || params.size() > 5)
428 "sendtoaddress \"zcashaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
429 "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
430 + HelpRequiringPassphrase() +
432 "1. \"zcashaddress\" (string, required) The Zcash address to send to.\n"
433 "2. \"amount\" (numeric, required) The amount in " + CURRENCY_UNIT + " to send. eg 0.1\n"
434 "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
435 " This is not part of the transaction, just kept in your wallet.\n"
436 "4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
437 " to which you're sending the transaction. This is not part of the \n"
438 " transaction, just kept in your wallet.\n"
439 "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
440 " The recipient will receive less Zcash than you enter in the amount field.\n"
442 "\"transactionid\" (string) The transaction id.\n"
444 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
445 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"donation\" \"seans outpost\"")
446 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"\" \"\" true")
447 + HelpExampleRpc("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
450 LOCK2(cs_main, pwalletMain->cs_wallet);
452 CBitcoinAddress address(params[0].get_str());
453 if (!address.IsValid())
454 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address");
457 CAmount nAmount = AmountFromValue(params[1]);
459 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
463 if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty())
464 wtx.mapValue["comment"] = params[2].get_str();
465 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
466 wtx.mapValue["to"] = params[3].get_str();
468 bool fSubtractFeeFromAmount = false;
469 if (params.size() > 4)
470 fSubtractFeeFromAmount = params[4].get_bool();
472 EnsureWalletIsUnlocked();
474 SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, wtx,0,0,0);
476 return wtx.GetHash().GetHex();
478 #include "komodo_defs.h"
480 #define KOMODO_KVPROTECTED 1
481 #define KOMODO_KVBINARY 2
482 #define KOMODO_KVDURATION 1440
483 #define IGUANA_MAXSCRIPTSIZE 10001
484 uint64_t PAX_fiatdest(uint64_t *seedp,int32_t tokomodo,char *destaddr,uint8_t pubkey37[37],char *coinaddr,int32_t height,char *base,int64_t fiatoshis);
485 int32_t komodo_opreturnscript(uint8_t *script,uint8_t type,uint8_t *opret,int32_t opretlen);
486 #define CRYPTO777_KMDADDR "RXL3YXG2ceaB6C5hfJcN4fvmLH2C34knhA"
487 extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
488 extern int32_t KOMODO_PAX;
489 int32_t komodo_is_issuer();
490 int32_t iguana_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp);
491 int32_t komodo_isrealtime(int32_t *kmdheightp);
492 int32_t pax_fiatstatus(uint64_t *available,uint64_t *deposited,uint64_t *issued,uint64_t *withdrawn,uint64_t *approved,uint64_t *redeemed,char *base);
493 int32_t komodo_kvsearch(uint256 *refpubkeyp,int32_t current_height,uint32_t *flagsp,int32_t *heightp,uint8_t value[IGUANA_MAXSCRIPTSIZE],uint8_t *key,int32_t keylen);
494 int32_t komodo_kvcmp(uint8_t *refvalue,uint16_t refvaluesize,uint8_t *value,uint16_t valuesize);
495 uint64_t komodo_kvfee(uint32_t flags,int32_t opretlen,int32_t keylen);
496 uint256 komodo_kvsig(uint8_t *buf,int32_t len,uint256 privkey);
497 int32_t komodo_kvduration(uint32_t flags);
498 uint256 komodo_kvprivkey(uint256 *pubkeyp,char *passphrase);
499 int32_t komodo_kvsigverify(uint8_t *buf,int32_t len,uint256 _pubkey,uint256 sig);
501 UniValue kvupdate(const UniValue& params, bool fHelp)
503 static uint256 zeroes;
504 CWalletTx wtx; UniValue ret(UniValue::VOBJ);
505 uint8_t keyvalue[IGUANA_MAXSCRIPTSIZE],opretbuf[IGUANA_MAXSCRIPTSIZE]; int32_t i,coresize,haveprivkey,duration,opretlen,height; uint16_t keylen=0,valuesize=0,refvaluesize=0; uint8_t *key,*value=0; uint32_t flags,tmpflags,n; struct komodo_kv *ptr; uint64_t fee; uint256 privkey,pubkey,refpubkey,sig;
506 if (fHelp || params.size() < 3 )
507 throw runtime_error("kvupdate key value flags/passphrase");
508 if (!EnsureWalletIsAvailable(fHelp))
510 if ( ASSETCHAINS_SYMBOL[0] == 0 )
513 memset(&sig,0,sizeof(sig));
514 memset(&privkey,0,sizeof(privkey));
515 memset(&refpubkey,0,sizeof(refpubkey));
516 memset(&pubkey,0,sizeof(pubkey));
517 if ( (n= (int32_t)params.size()) >= 3 )
519 flags = atoi(params[2].get_str().c_str());
520 //printf("flags.%d (%s) n.%d\n",flags,params[2].get_str().c_str(),n);
523 privkey = komodo_kvprivkey(&pubkey,(char *)(n >= 4 ? params[3].get_str().c_str() : "password"));
526 /*for (i=0; i<32; i++)
527 printf("%02x",((uint8_t *)&privkey)[i]);
530 printf("%02x",((uint8_t *)&pubkey)[i]);
531 printf(" pubkey, privkey derived from (%s)\n",(char *)params[3].get_str().c_str());
533 LOCK2(cs_main, pwalletMain->cs_wallet);
534 if ( (keylen= (int32_t)strlen(params[0].get_str().c_str())) > 0 )
536 key = (uint8_t *)params[0].get_str().c_str();
537 if ( n >= 2 && params[1].get_str().c_str() != 0 )
539 value = (uint8_t *)params[1].get_str().c_str();
540 valuesize = (int32_t)strlen(params[1].get_str().c_str());
542 memcpy(keyvalue,key,keylen);
543 if ( (refvaluesize= komodo_kvsearch(&refpubkey,chainActive.Tip()->nHeight,&tmpflags,&height,&keyvalue[keylen],key,keylen)) >= 0 )
545 if ( (tmpflags & KOMODO_KVPROTECTED) != 0 )
547 if ( memcmp(&refpubkey,&pubkey,sizeof(refpubkey)) != 0 )
549 ret.push_back(Pair("error",(char *)"cant modify write once key without passphrase"));
553 if ( keylen+refvaluesize <= sizeof(keyvalue) )
555 sig = komodo_kvsig(keyvalue,keylen+refvaluesize,privkey);
556 if ( komodo_kvsigverify(keyvalue,keylen+refvaluesize,refpubkey,sig) < 0 )
558 ret.push_back(Pair("error",(char *)"error verifying sig, passphrase is probably wrong"));
559 printf("VERIFY ERROR\n");
561 } // else printf("verified immediately\n");
564 //for (i=0; i<32; i++)
565 // printf("%02x",((uint8_t *)&sig)[i]);
566 //printf(" sig for keylen.%d + valuesize.%d\n",keylen,refvaluesize);
567 ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)));
568 height = chainActive.Tip()->nHeight;
569 if ( memcmp(&zeroes,&refpubkey,sizeof(refpubkey)) != 0 )
570 ret.push_back(Pair("owner",refpubkey.GetHex()));
571 ret.push_back(Pair("height", (int64_t)height));
572 duration = komodo_kvduration(flags); //((flags >> 2) + 1) * KOMODO_KVDURATION;
573 ret.push_back(Pair("expiration", (int64_t)(height+duration)));
574 ret.push_back(Pair("flags",(int64_t)flags));
575 ret.push_back(Pair("key",params[0].get_str()));
576 ret.push_back(Pair("keylen",(int64_t)keylen));
577 if ( n >= 2 && params[1].get_str().c_str() != 0 )
579 ret.push_back(Pair("value",params[1].get_str()));
580 ret.push_back(Pair("valuesize",valuesize));
582 iguana_rwnum(1,&keyvalue[0],sizeof(keylen),&keylen);
583 iguana_rwnum(1,&keyvalue[2],sizeof(valuesize),&valuesize);
584 iguana_rwnum(1,&keyvalue[4],sizeof(height),&height);
585 iguana_rwnum(1,&keyvalue[8],sizeof(flags),&flags);
586 memcpy(&keyvalue[12],key,keylen);
588 memcpy(&keyvalue[12 + keylen],value,valuesize);
589 coresize = (int32_t)(sizeof(flags)+sizeof(height)+sizeof(uint16_t)*2+keylen+valuesize);
590 if ( haveprivkey != 0 )
593 keyvalue[12 + keylen + valuesize + i] = ((uint8_t *)&pubkey)[i];
595 if ( refvaluesize >=0 )
598 keyvalue[12 + keylen + valuesize + 32 + i] = ((uint8_t *)&sig)[i];
602 if ( (opretlen= komodo_opreturnscript(opretbuf,'K',keyvalue,coresize)) == 40 )
604 //for (i=0; i<opretlen; i++)
605 // printf("%02x",opretbuf[i]);
606 //printf(" opretbuf keylen.%d valuesize.%d height.%d (%02x %02x %02x)\n",*(uint16_t *)&keyvalue[0],*(uint16_t *)&keyvalue[2],*(uint32_t *)&keyvalue[4],keyvalue[8],keyvalue[9],keyvalue[10]);
607 EnsureWalletIsUnlocked();
608 fee = komodo_kvfee(flags,opretlen,keylen);
609 ret.push_back(Pair("fee",(double)fee/COIN));
610 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
611 if (!destaddress.IsValid())
612 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
613 SendMoney(destaddress.Get(),10000,false,wtx,opretbuf,opretlen,fee);
614 ret.push_back(Pair("txid",wtx.GetHash().GetHex()));
615 } else ret.push_back(Pair("error",(char *)"null key"));
619 UniValue paxdeposit(const UniValue& params, bool fHelp)
621 uint64_t available,deposited,issued,withdrawn,approved,redeemed,seed,komodoshis = 0; int32_t height; char destaddr[64]; uint8_t i,pubkey37[33];
622 bool fSubtractFeeFromAmount = false;
623 if ( KOMODO_PAX == 0 )
625 throw runtime_error("paxdeposit disabled without -pax");
627 if ( komodo_is_issuer() != 0 )
628 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "paxdeposit only from KMD");
629 if (!EnsureWalletIsAvailable(fHelp))
630 throw runtime_error("paxdeposit needs wallet"); //return Value::null;
631 if (fHelp || params.size() != 3)
632 throw runtime_error("paxdeposit address fiatoshis base");
633 LOCK2(cs_main, pwalletMain->cs_wallet);
634 CBitcoinAddress address(params[0].get_str());
635 if (!address.IsValid())
636 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
637 int64_t fiatoshis = atof(params[1].get_str().c_str()) * COIN;
638 std::string base = params[2].get_str();
640 height = chainActive.Tip()->nHeight;
641 if ( pax_fiatstatus(&available,&deposited,&issued,&withdrawn,&approved,&redeemed,(char *)base.c_str()) != 0 || available < fiatoshis )
643 fprintf(stderr,"available %llu vs fiatoshis %llu\n",(long long)available,(long long)fiatoshis);
644 throw runtime_error("paxdeposit not enough available inventory");
646 komodoshis = PAX_fiatdest(&seed,0,destaddr,pubkey37,(char *)params[0].get_str().c_str(),height,(char *)base.c_str(),fiatoshis);
647 dest.append(destaddr);
648 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
649 if (!destaddress.IsValid())
650 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
652 fprintf(stderr,"%02x",pubkey37[i]);
653 fprintf(stderr," ht.%d srcaddr.(%s) %s fiatoshis.%lld -> dest.(%s) komodoshis.%llu seed.%llx\n",height,(char *)params[0].get_str().c_str(),(char *)base.c_str(),(long long)fiatoshis,destaddr,(long long)komodoshis,(long long)seed);
654 EnsureWalletIsUnlocked();
656 uint8_t opretbuf[64]; int32_t opretlen; uint64_t fee = komodoshis / 1000;
659 iguana_rwnum(1,&pubkey37[33],sizeof(height),&height);
660 opretlen = komodo_opreturnscript(opretbuf,'D',pubkey37,37);
661 SendMoney(address.Get(),fee,fSubtractFeeFromAmount,wtx,opretbuf,opretlen,komodoshis);
662 return wtx.GetHash().GetHex();
665 UniValue paxwithdraw(const UniValue& params, bool fHelp)
667 CWalletTx wtx; std::string dest; int32_t kmdheight; uint64_t seed,komodoshis = 0; char destaddr[64]; uint8_t i,pubkey37[37]; bool fSubtractFeeFromAmount = false;
668 if ( ASSETCHAINS_SYMBOL[0] == 0 )
670 if (!EnsureWalletIsAvailable(fHelp))
672 throw runtime_error("paxwithdraw deprecated");
673 if (fHelp || params.size() != 2)
674 throw runtime_error("paxwithdraw address fiatamount");
675 if ( komodo_isrealtime(&kmdheight) == 0 )
677 LOCK2(cs_main, pwalletMain->cs_wallet);
678 CBitcoinAddress address(params[0].get_str());
679 if (!address.IsValid())
680 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
681 int64_t fiatoshis = atof(params[1].get_str().c_str()) * COIN;
682 komodoshis = PAX_fiatdest(&seed,1,destaddr,pubkey37,(char *)params[0].get_str().c_str(),kmdheight,ASSETCHAINS_SYMBOL,fiatoshis);
683 dest.append(destaddr);
684 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
685 if (!destaddress.IsValid())
686 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
688 printf("%02x",pubkey37[i]);
689 printf(" kmdheight.%d srcaddr.(%s) %s fiatoshis.%lld -> dest.(%s) komodoshis.%llu seed.%llx\n",kmdheight,(char *)params[0].get_str().c_str(),ASSETCHAINS_SYMBOL,(long long)fiatoshis,destaddr,(long long)komodoshis,(long long)seed);
690 EnsureWalletIsUnlocked();
691 uint8_t opretbuf[64]; int32_t opretlen; uint64_t fee = fiatoshis / 1000;
694 iguana_rwnum(1,&pubkey37[33],sizeof(kmdheight),&kmdheight);
695 opretlen = komodo_opreturnscript(opretbuf,'W',pubkey37,37);
696 SendMoney(destaddress.Get(),fee,fSubtractFeeFromAmount,wtx,opretbuf,opretlen,fiatoshis);
697 return wtx.GetHash().GetHex();
700 UniValue listaddressgroupings(const UniValue& params, bool fHelp)
702 if (!EnsureWalletIsAvailable(fHelp))
707 "listaddressgroupings\n"
708 "\nLists groups of addresses which have had their common ownership\n"
709 "made public by common use as inputs or as the resulting change\n"
710 "in past transactions\n"
715 " \"zcashaddress\", (string) The zcash address\n"
716 " amount, (numeric) The amount in " + CURRENCY_UNIT + "\n"
717 " \"account\" (string, optional) The account (DEPRECATED)\n"
724 + HelpExampleCli("listaddressgroupings", "")
725 + HelpExampleRpc("listaddressgroupings", "")
728 LOCK2(cs_main, pwalletMain->cs_wallet);
730 UniValue jsonGroupings(UniValue::VARR);
731 map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
732 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
734 UniValue jsonGrouping(UniValue::VARR);
735 BOOST_FOREACH(CTxDestination address, grouping)
737 UniValue addressInfo(UniValue::VARR);
738 addressInfo.push_back(CBitcoinAddress(address).ToString());
739 addressInfo.push_back(ValueFromAmount(balances[address]));
741 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
742 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
744 jsonGrouping.push_back(addressInfo);
746 jsonGroupings.push_back(jsonGrouping);
748 return jsonGroupings;
751 UniValue signmessage(const UniValue& params, bool fHelp)
753 if (!EnsureWalletIsAvailable(fHelp))
756 if (fHelp || params.size() != 2)
758 "signmessage \"zcashaddress\" \"message\"\n"
759 "\nSign a message with the private key of an address"
760 + HelpRequiringPassphrase() + "\n"
762 "1. \"zcashaddress\" (string, required) The Zcash address to use for the private key.\n"
763 "2. \"message\" (string, required) The message to create a signature of.\n"
765 "\"signature\" (string) The signature of the message encoded in base 64\n"
767 "\nUnlock the wallet for 30 seconds\n"
768 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
769 "\nCreate the signature\n"
770 + HelpExampleCli("signmessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"my message\"") +
771 "\nVerify the signature\n"
772 + HelpExampleCli("verifymessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"signature\" \"my message\"") +
774 + HelpExampleRpc("signmessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", \"my message\"")
777 LOCK2(cs_main, pwalletMain->cs_wallet);
779 EnsureWalletIsUnlocked();
781 string strAddress = params[0].get_str();
782 string strMessage = params[1].get_str();
784 CBitcoinAddress addr(strAddress);
786 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
789 if (!addr.GetKeyID(keyID))
790 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
793 if (!pwalletMain->GetKey(keyID, key))
794 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
796 CHashWriter ss(SER_GETHASH, 0);
797 ss << strMessageMagic;
800 vector<unsigned char> vchSig;
801 if (!key.SignCompact(ss.GetHash(), vchSig))
802 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
804 return EncodeBase64(&vchSig[0], vchSig.size());
807 UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
809 if (!EnsureWalletIsAvailable(fHelp))
812 if (fHelp || params.size() < 1 || params.size() > 2)
814 "getreceivedbyaddress \"zcashaddress\" ( minconf )\n"
815 "\nReturns the total amount received by the given Zcash address in transactions with at least minconf confirmations.\n"
817 "1. \"zcashaddress\" (string, required) The Zcash address for transactions.\n"
818 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
820 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received at this address.\n"
822 "\nThe amount from transactions with at least 1 confirmation\n"
823 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"") +
824 "\nThe amount including unconfirmed transactions, zero confirmations\n"
825 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" 0") +
826 "\nThe amount with at least 6 confirmations, very safe\n"
827 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" 6") +
828 "\nAs a json rpc call\n"
829 + HelpExampleRpc("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", 6")
832 LOCK2(cs_main, pwalletMain->cs_wallet);
835 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
836 if (!address.IsValid())
837 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address");
838 CScript scriptPubKey = GetScriptForDestination(address.Get());
839 if (!IsMine(*pwalletMain,scriptPubKey))
842 // Minimum confirmations
844 if (params.size() > 1)
845 nMinDepth = params[1].get_int();
849 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
851 const CWalletTx& wtx = (*it).second;
852 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
855 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
856 if (txout.scriptPubKey == scriptPubKey)
857 if (wtx.GetDepthInMainChain() >= nMinDepth)
858 nAmount += txout.nValue; // komodo_interest?
861 return ValueFromAmount(nAmount);
865 UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
867 if (!EnsureWalletIsAvailable(fHelp))
870 if (fHelp || params.size() < 1 || params.size() > 2)
872 "getreceivedbyaccount \"account\" ( minconf )\n"
873 "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
875 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
876 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
878 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
880 "\nAmount received by the default account with at least 1 confirmation\n"
881 + HelpExampleCli("getreceivedbyaccount", "\"\"") +
882 "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
883 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
884 "\nThe amount with at least 6 confirmation, very safe\n"
885 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
886 "\nAs a json rpc call\n"
887 + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
890 LOCK2(cs_main, pwalletMain->cs_wallet);
892 // Minimum confirmations
894 if (params.size() > 1)
895 nMinDepth = params[1].get_int();
897 // Get the set of pub keys assigned to account
898 string strAccount = AccountFromValue(params[0]);
899 set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
903 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
905 const CWalletTx& wtx = (*it).second;
906 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
909 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
911 CTxDestination address;
912 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
913 if (wtx.GetDepthInMainChain() >= nMinDepth)
914 nAmount += txout.nValue; // komodo_interest?
918 return (double)nAmount / (double)COIN;
922 CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
924 CAmount nBalance = 0;
926 // Tally wallet transactions
927 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
929 const CWalletTx& wtx = (*it).second;
930 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
933 CAmount nReceived, nSent, nFee;
934 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
936 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
937 nBalance += nReceived;
938 nBalance -= nSent + nFee;
941 // Tally internal accounting entries
942 nBalance += walletdb.GetAccountCreditDebit(strAccount);
947 CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
949 CWalletDB walletdb(pwalletMain->strWalletFile);
950 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
954 UniValue getbalance(const UniValue& params, bool fHelp)
956 if (!EnsureWalletIsAvailable(fHelp))
959 if (fHelp || params.size() > 3)
961 "getbalance ( \"account\" minconf includeWatchonly )\n"
962 "\nReturns the server's total available balance.\n"
964 "1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" or to the string \"*\", either of which will give the total available balance. Passing any other string will result in an error.\n"
965 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
966 "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
968 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
970 "\nThe total amount in the wallet\n"
971 + HelpExampleCli("getbalance", "") +
972 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
973 + HelpExampleCli("getbalance", "\"*\" 6") +
974 "\nAs a json rpc call\n"
975 + HelpExampleRpc("getbalance", "\"*\", 6")
978 LOCK2(cs_main, pwalletMain->cs_wallet);
980 if (params.size() == 0)
981 return ValueFromAmount(pwalletMain->GetBalance());
984 if (params.size() > 1)
985 nMinDepth = params[1].get_int();
986 isminefilter filter = ISMINE_SPENDABLE;
987 if(params.size() > 2)
988 if(params[2].get_bool())
989 filter = filter | ISMINE_WATCH_ONLY;
991 if (params[0].get_str() == "*") {
992 // Calculate total balance a different way from GetBalance()
993 // (GetBalance() sums up all unspent TxOuts)
994 // getbalance and "getbalance * 1 true" should return the same number
995 CAmount nBalance = 0;
996 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
998 const CWalletTx& wtx = (*it).second;
999 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
1003 string strSentAccount;
1004 list<COutputEntry> listReceived;
1005 list<COutputEntry> listSent;
1006 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
1007 if (wtx.GetDepthInMainChain() >= nMinDepth)
1009 BOOST_FOREACH(const COutputEntry& r, listReceived)
1010 nBalance += r.amount;
1012 BOOST_FOREACH(const COutputEntry& s, listSent)
1013 nBalance -= s.amount;
1016 return ValueFromAmount(nBalance);
1019 string strAccount = AccountFromValue(params[0]);
1021 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
1023 return ValueFromAmount(nBalance);
1026 UniValue getunconfirmedbalance(const UniValue ¶ms, bool fHelp)
1028 if (!EnsureWalletIsAvailable(fHelp))
1029 return NullUniValue;
1031 if (fHelp || params.size() > 0)
1032 throw runtime_error(
1033 "getunconfirmedbalance\n"
1034 "Returns the server's total unconfirmed balance\n");
1036 LOCK2(cs_main, pwalletMain->cs_wallet);
1038 return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
1042 UniValue movecmd(const UniValue& params, bool fHelp)
1044 if (!EnsureWalletIsAvailable(fHelp))
1045 return NullUniValue;
1047 if (fHelp || params.size() < 3 || params.size() > 5)
1048 throw runtime_error(
1049 "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
1050 "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
1052 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1053 "2. \"toaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1054 "3. amount (numeric) Quantity of " + CURRENCY_UNIT + " to move between accounts.\n"
1055 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
1056 "5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
1058 "true|false (boolean) true if successful.\n"
1060 "\nMove 0.01 " + CURRENCY_UNIT + " from the default account to the account named tabby\n"
1061 + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
1062 "\nMove 0.01 " + CURRENCY_UNIT + " timotei to akiko with a comment and funds have 6 confirmations\n"
1063 + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
1064 "\nAs a json rpc call\n"
1065 + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
1068 LOCK2(cs_main, pwalletMain->cs_wallet);
1070 string strFrom = AccountFromValue(params[0]);
1071 string strTo = AccountFromValue(params[1]);
1072 CAmount nAmount = AmountFromValue(params[2]);
1074 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1075 if (params.size() > 3)
1076 // unused parameter, used to be nMinDepth, keep type-checking it though
1077 (void)params[3].get_int();
1079 if (params.size() > 4)
1080 strComment = params[4].get_str();
1082 CWalletDB walletdb(pwalletMain->strWalletFile);
1083 if (!walletdb.TxnBegin())
1084 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
1086 int64_t nNow = GetAdjustedTime();
1089 CAccountingEntry debit;
1090 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
1091 debit.strAccount = strFrom;
1092 debit.nCreditDebit = -nAmount;
1094 debit.strOtherAccount = strTo;
1095 debit.strComment = strComment;
1096 walletdb.WriteAccountingEntry(debit);
1099 CAccountingEntry credit;
1100 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
1101 credit.strAccount = strTo;
1102 credit.nCreditDebit = nAmount;
1103 credit.nTime = nNow;
1104 credit.strOtherAccount = strFrom;
1105 credit.strComment = strComment;
1106 walletdb.WriteAccountingEntry(credit);
1108 if (!walletdb.TxnCommit())
1109 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
1115 UniValue sendfrom(const UniValue& params, bool fHelp)
1117 if (!EnsureWalletIsAvailable(fHelp))
1118 return NullUniValue;
1120 if (fHelp || params.size() < 3 || params.size() > 6)
1121 throw runtime_error(
1122 "sendfrom \"fromaccount\" \"tozcashaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
1123 "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a Zcash address.\n"
1124 "The amount is a real and is rounded to the nearest 0.00000001."
1125 + HelpRequiringPassphrase() + "\n"
1127 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1128 "2. \"tozcashaddress\" (string, required) The Zcash address to send funds to.\n"
1129 "3. amount (numeric, required) The amount in " + CURRENCY_UNIT + " (transaction fee is added on top).\n"
1130 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
1131 "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
1132 " This is not part of the transaction, just kept in your wallet.\n"
1133 "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n"
1134 " to which you're sending the transaction. This is not part of the transaction, \n"
1135 " it is just kept in your wallet.\n"
1137 "\"transactionid\" (string) The transaction id.\n"
1139 "\nSend 0.01 " + CURRENCY_UNIT + " from the default account to the address, must have at least 1 confirmation\n"
1140 + HelpExampleCli("sendfrom", "\"\" \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
1141 "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
1142 + HelpExampleCli("sendfrom", "\"tabby\" \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01 6 \"donation\" \"seans outpost\"") +
1143 "\nAs a json rpc call\n"
1144 + HelpExampleRpc("sendfrom", "\"tabby\", \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
1147 LOCK2(cs_main, pwalletMain->cs_wallet);
1149 string strAccount = AccountFromValue(params[0]);
1150 CBitcoinAddress address(params[1].get_str());
1151 if (!address.IsValid())
1152 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Komodo address");
1153 CAmount nAmount = AmountFromValue(params[2]);
1155 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1157 if (params.size() > 3)
1158 nMinDepth = params[3].get_int();
1161 wtx.strFromAccount = strAccount;
1162 if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty())
1163 wtx.mapValue["comment"] = params[4].get_str();
1164 if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty())
1165 wtx.mapValue["to"] = params[5].get_str();
1167 EnsureWalletIsUnlocked();
1170 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
1171 if (nAmount > nBalance)
1172 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
1174 SendMoney(address.Get(), nAmount, false, wtx,0,0,0);
1176 return wtx.GetHash().GetHex();
1180 UniValue sendmany(const UniValue& params, bool fHelp)
1182 if (!EnsureWalletIsAvailable(fHelp))
1183 return NullUniValue;
1185 if (fHelp || params.size() < 2 || params.size() > 5)
1186 throw runtime_error(
1187 "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
1188 "\nSend multiple times. Amounts are double-precision floating point numbers."
1189 + HelpRequiringPassphrase() + "\n"
1191 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1192 "2. \"amounts\" (string, required) A json object with addresses and amounts\n"
1194 " \"address\":amount (numeric) The Zcash address is the key, the numeric amount in " + CURRENCY_UNIT + " is the value\n"
1197 "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
1198 "4. \"comment\" (string, optional) A comment\n"
1199 "5. subtractfeefromamount (string, optional) A json array with addresses.\n"
1200 " The fee will be equally deducted from the amount of each selected address.\n"
1201 " Those recipients will receive less Zcash than you enter in their corresponding amount field.\n"
1202 " If no addresses are specified here, the sender pays the fee.\n"
1204 " \"address\" (string) Subtract fee from this address\n"
1208 "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
1209 " the number of addresses.\n"
1211 "\nSend two amounts to two different addresses:\n"
1212 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
1213 "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
1214 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
1215 "\nSend two amounts to two different addresses, subtract fee from amount:\n"
1216 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\",\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
1217 "\nAs a json rpc call\n"
1218 + HelpExampleRpc("sendmany", "\"\", \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
1221 LOCK2(cs_main, pwalletMain->cs_wallet);
1223 string strAccount = AccountFromValue(params[0]);
1224 UniValue sendTo = params[1].get_obj();
1226 if (params.size() > 2)
1227 nMinDepth = params[2].get_int();
1230 wtx.strFromAccount = strAccount;
1231 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
1232 wtx.mapValue["comment"] = params[3].get_str();
1234 UniValue subtractFeeFromAmount(UniValue::VARR);
1235 if (params.size() > 4)
1236 subtractFeeFromAmount = params[4].get_array();
1238 set<CBitcoinAddress> setAddress;
1239 vector<CRecipient> vecSend;
1241 CAmount totalAmount = 0;
1242 vector<string> keys = sendTo.getKeys();
1243 BOOST_FOREACH(const string& name_, keys)
1245 CBitcoinAddress address(name_);
1246 if (!address.IsValid())
1247 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Komodo address: ")+name_);
1249 //if (setAddress.count(address))
1250 // throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
1251 setAddress.insert(address);
1253 CScript scriptPubKey = GetScriptForDestination(address.Get());
1254 CAmount nAmount = AmountFromValue(sendTo[name_]);
1256 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1257 totalAmount += nAmount;
1259 bool fSubtractFeeFromAmount = false;
1260 for (size_t idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
1261 const UniValue& addr = subtractFeeFromAmount[idx];
1262 if (addr.get_str() == name_)
1263 fSubtractFeeFromAmount = true;
1266 CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
1267 vecSend.push_back(recipient);
1270 EnsureWalletIsUnlocked();
1273 CAmount nBalance = pwalletMain->GetBalance();
1274 //CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
1275 if (totalAmount > nBalance)
1276 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
1279 CReserveKey keyChange(pwalletMain);
1280 CAmount nFeeRequired = 0;
1281 int nChangePosRet = -1;
1282 string strFailReason;
1283 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
1285 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
1286 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1287 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
1289 return wtx.GetHash().GetHex();
1292 // Defined in rpcmisc.cpp
1293 extern CScript _createmultisig_redeemScript(const UniValue& params);
1295 UniValue addmultisigaddress(const UniValue& params, bool fHelp)
1297 if (!EnsureWalletIsAvailable(fHelp))
1298 return NullUniValue;
1300 if (fHelp || params.size() < 2 || params.size() > 3)
1302 string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
1303 "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
1304 "Each key is a Komodo address or hex-encoded public key.\n"
1305 "If 'account' is specified (DEPRECATED), assign address to that account.\n"
1308 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
1309 "2. \"keysobject\" (string, required) A json array of Zcash addresses or hex-encoded public keys\n"
1311 " \"address\" (string) Zcash address or hex-encoded public key\n"
1314 "3. \"account\" (string, optional) DEPRECATED. If provided, MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1317 "\"zcashaddress\" (string) A Zcash address associated with the keys.\n"
1320 "\nAdd a multisig address from 2 addresses\n"
1321 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
1322 "\nAs json rpc call\n"
1323 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
1325 throw runtime_error(msg);
1328 LOCK2(cs_main, pwalletMain->cs_wallet);
1331 if (params.size() > 2)
1332 strAccount = AccountFromValue(params[2]);
1334 // Construct using pay-to-script-hash:
1335 CScript inner = _createmultisig_redeemScript(params);
1336 CScriptID innerID(inner);
1337 pwalletMain->AddCScript(inner);
1339 pwalletMain->SetAddressBook(innerID, strAccount, "send");
1340 return CBitcoinAddress(innerID).ToString();
1348 vector<uint256> txids;
1353 nConf = std::numeric_limits<int>::max();
1354 fIsWatchonly = false;
1358 UniValue ListReceived(const UniValue& params, bool fByAccounts)
1360 // Minimum confirmations
1362 if (params.size() > 0)
1363 nMinDepth = params[0].get_int();
1365 // Whether to include empty accounts
1366 bool fIncludeEmpty = false;
1367 if (params.size() > 1)
1368 fIncludeEmpty = params[1].get_bool();
1370 isminefilter filter = ISMINE_SPENDABLE;
1371 if(params.size() > 2)
1372 if(params[2].get_bool())
1373 filter = filter | ISMINE_WATCH_ONLY;
1376 map<CBitcoinAddress, tallyitem> mapTally;
1377 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1379 const CWalletTx& wtx = (*it).second;
1381 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
1384 int nDepth = wtx.GetDepthInMainChain();
1385 if (nDepth < nMinDepth)
1388 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1390 CTxDestination address;
1391 if (!ExtractDestination(txout.scriptPubKey, address))
1394 isminefilter mine = IsMine(*pwalletMain, address);
1395 if(!(mine & filter))
1398 tallyitem& item = mapTally[address];
1399 item.nAmount += txout.nValue; // komodo_interest?
1400 item.nConf = min(item.nConf, nDepth);
1401 item.txids.push_back(wtx.GetHash());
1402 if (mine & ISMINE_WATCH_ONLY)
1403 item.fIsWatchonly = true;
1408 UniValue ret(UniValue::VARR);
1409 map<string, tallyitem> mapAccountTally;
1410 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
1412 const CBitcoinAddress& address = item.first;
1413 const string& strAccount = item.second.name;
1414 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1415 if (it == mapTally.end() && !fIncludeEmpty)
1418 CAmount nAmount = 0;
1419 int nConf = std::numeric_limits<int>::max();
1420 bool fIsWatchonly = false;
1421 if (it != mapTally.end())
1423 nAmount = (*it).second.nAmount;
1424 nConf = (*it).second.nConf;
1425 fIsWatchonly = (*it).second.fIsWatchonly;
1430 tallyitem& item = mapAccountTally[strAccount];
1431 item.nAmount += nAmount;
1432 item.nConf = min(item.nConf, nConf);
1433 item.fIsWatchonly = fIsWatchonly;
1437 UniValue obj(UniValue::VOBJ);
1439 obj.push_back(Pair("involvesWatchonly", true));
1440 obj.push_back(Pair("address", address.ToString()));
1441 obj.push_back(Pair("account", strAccount));
1442 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1443 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1444 UniValue transactions(UniValue::VARR);
1445 if (it != mapTally.end())
1447 BOOST_FOREACH(const uint256& item, (*it).second.txids)
1449 transactions.push_back(item.GetHex());
1452 obj.push_back(Pair("txids", transactions));
1459 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1461 CAmount nAmount = (*it).second.nAmount;
1462 int nConf = (*it).second.nConf;
1463 UniValue obj(UniValue::VOBJ);
1464 if((*it).second.fIsWatchonly)
1465 obj.push_back(Pair("involvesWatchonly", true));
1466 obj.push_back(Pair("account", (*it).first));
1467 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1468 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1476 UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
1478 if (!EnsureWalletIsAvailable(fHelp))
1479 return NullUniValue;
1481 if (fHelp || params.size() > 3)
1482 throw runtime_error(
1483 "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
1484 "\nList balances by receiving address.\n"
1486 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1487 "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n"
1488 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1493 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
1494 " \"address\" : \"receivingaddress\", (string) The receiving address\n"
1495 " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
1496 " \"amount\" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " received by the address\n"
1497 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1503 + HelpExampleCli("listreceivedbyaddress", "")
1504 + HelpExampleCli("listreceivedbyaddress", "6 true")
1505 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
1508 LOCK2(cs_main, pwalletMain->cs_wallet);
1510 return ListReceived(params, false);
1513 UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
1515 if (!EnsureWalletIsAvailable(fHelp))
1516 return NullUniValue;
1518 if (fHelp || params.size() > 3)
1519 throw runtime_error(
1520 "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
1521 "\nDEPRECATED. List balances by account.\n"
1523 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1524 "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
1525 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1530 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
1531 " \"account\" : \"accountname\", (string) The account name of the receiving account\n"
1532 " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
1533 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1539 + HelpExampleCli("listreceivedbyaccount", "")
1540 + HelpExampleCli("listreceivedbyaccount", "6 true")
1541 + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
1544 LOCK2(cs_main, pwalletMain->cs_wallet);
1546 return ListReceived(params, true);
1549 static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
1551 CBitcoinAddress addr;
1553 entry.push_back(Pair("address", addr.ToString()));
1556 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
1559 string strSentAccount;
1560 list<COutputEntry> listReceived;
1561 list<COutputEntry> listSent;
1563 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
1565 bool fAllAccounts = (strAccount == string("*"));
1566 bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
1569 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1571 BOOST_FOREACH(const COutputEntry& s, listSent)
1573 UniValue entry(UniValue::VOBJ);
1574 if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
1575 entry.push_back(Pair("involvesWatchonly", true));
1576 entry.push_back(Pair("account", strSentAccount));
1577 MaybePushAddress(entry, s.destination);
1578 entry.push_back(Pair("category", "send"));
1579 entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
1580 entry.push_back(Pair("vout", s.vout));
1581 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1583 WalletTxToJSON(wtx, entry);
1585 entry.push_back(Pair("size", (uint64_t)static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1587 entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1589 ret.push_back(entry);
1594 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1596 BOOST_FOREACH(const COutputEntry& r, listReceived)
1599 if (pwalletMain->mapAddressBook.count(r.destination))
1600 account = pwalletMain->mapAddressBook[r.destination].name;
1601 if (fAllAccounts || (account == strAccount))
1603 UniValue entry(UniValue::VOBJ);
1604 if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
1605 entry.push_back(Pair("involvesWatchonly", true));
1606 entry.push_back(Pair("account", account));
1607 MaybePushAddress(entry, r.destination);
1608 if (wtx.IsCoinBase())
1610 if (wtx.GetDepthInMainChain() < 1)
1611 entry.push_back(Pair("category", "orphan"));
1612 else if (wtx.GetBlocksToMaturity() > 0)
1613 entry.push_back(Pair("category", "immature"));
1615 entry.push_back(Pair("category", "generate"));
1619 entry.push_back(Pair("category", "receive"));
1621 entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
1622 entry.push_back(Pair("vout", r.vout));
1624 WalletTxToJSON(wtx, entry);
1626 entry.push_back(Pair("size", (uint64_t)static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1628 entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1630 ret.push_back(entry);
1636 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret)
1638 bool fAllAccounts = (strAccount == string("*"));
1640 if (fAllAccounts || acentry.strAccount == strAccount)
1642 UniValue entry(UniValue::VOBJ);
1643 entry.push_back(Pair("account", acentry.strAccount));
1644 entry.push_back(Pair("category", "move"));
1645 entry.push_back(Pair("time", acentry.nTime));
1646 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1647 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1648 entry.push_back(Pair("comment", acentry.strComment));
1649 ret.push_back(entry);
1653 UniValue listtransactions(const UniValue& params, bool fHelp)
1655 if (!EnsureWalletIsAvailable(fHelp))
1656 return NullUniValue;
1658 if (fHelp || params.size() > 4)
1659 throw runtime_error(
1660 "listtransactions ( \"account\" count from includeWatchonly)\n"
1661 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
1663 "1. \"account\" (string, optional) DEPRECATED. The account name. Should be \"*\".\n"
1664 "2. count (numeric, optional, default=10) The number of transactions to return\n"
1665 "3. from (numeric, optional, default=0) The number of transactions to skip\n"
1666 "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
1670 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n"
1671 " It will be \"\" for the default account.\n"
1672 " \"address\":\"zcashaddress\", (string) The Zcash address of the transaction. Not present for \n"
1673 " move transactions (category = move).\n"
1674 " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
1675 " transaction between accounts, and not associated with an address,\n"
1676 " transaction id or block. 'send' and 'receive' transactions are \n"
1677 " associated with an address, transaction id and block details\n"
1678 " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the\n"
1679 " 'move' category for moves outbound. It is positive for the 'receive' category,\n"
1680 " and for the 'move' category for inbound funds.\n"
1681 " \"vout\" : n, (numeric) the vout value\n"
1682 " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
1683 " 'send' category of transactions.\n"
1684 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
1685 " 'receive' category of transactions.\n"
1686 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
1687 " category of transactions.\n"
1688 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
1689 " category of transactions.\n"
1690 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1691 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1692 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
1693 " for 'send' and 'receive' category of transactions.\n"
1694 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1695 " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
1696 " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
1697 " negative amounts).\n"
1698 " \"size\": n, (numeric) Transaction size in bytes\n"
1703 "\nList the most recent 10 transactions in the systems\n"
1704 + HelpExampleCli("listtransactions", "") +
1705 "\nList transactions 100 to 120\n"
1706 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
1707 "\nAs a json rpc call\n"
1708 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
1711 LOCK2(cs_main, pwalletMain->cs_wallet);
1713 string strAccount = "*";
1714 if (params.size() > 0)
1715 strAccount = params[0].get_str();
1717 if (params.size() > 1)
1718 nCount = params[1].get_int();
1720 if (params.size() > 2)
1721 nFrom = params[2].get_int();
1722 isminefilter filter = ISMINE_SPENDABLE;
1723 if(params.size() > 3)
1724 if(params[3].get_bool())
1725 filter = filter | ISMINE_WATCH_ONLY;
1728 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1730 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1732 UniValue ret(UniValue::VARR);
1734 std::list<CAccountingEntry> acentries;
1735 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1737 // iterate backwards until we have nCount items to return:
1738 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1740 CWalletTx *const pwtx = (*it).second.first;
1742 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1743 CAccountingEntry *const pacentry = (*it).second.second;
1745 AcentryToJSON(*pacentry, strAccount, ret);
1747 if ((int)ret.size() >= (nCount+nFrom)) break;
1749 // ret is newest to oldest
1751 if (nFrom > (int)ret.size())
1753 if ((nFrom + nCount) > (int)ret.size())
1754 nCount = ret.size() - nFrom;
1756 vector<UniValue> arrTmp = ret.getValues();
1758 vector<UniValue>::iterator first = arrTmp.begin();
1759 std::advance(first, nFrom);
1760 vector<UniValue>::iterator last = arrTmp.begin();
1761 std::advance(last, nFrom+nCount);
1763 if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
1764 if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
1766 std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
1770 ret.push_backV(arrTmp);
1775 UniValue listaccounts(const UniValue& params, bool fHelp)
1777 if (!EnsureWalletIsAvailable(fHelp))
1778 return NullUniValue;
1780 if (fHelp || params.size() > 2)
1781 throw runtime_error(
1782 "listaccounts ( minconf includeWatchonly)\n"
1783 "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
1785 "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
1786 "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
1788 "{ (json object where keys are account names, and values are numeric balances\n"
1789 " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
1793 "\nList account balances where there at least 1 confirmation\n"
1794 + HelpExampleCli("listaccounts", "") +
1795 "\nList account balances including zero confirmation transactions\n"
1796 + HelpExampleCli("listaccounts", "0") +
1797 "\nList account balances for 6 or more confirmations\n"
1798 + HelpExampleCli("listaccounts", "6") +
1799 "\nAs json rpc call\n"
1800 + HelpExampleRpc("listaccounts", "6")
1803 LOCK2(cs_main, pwalletMain->cs_wallet);
1806 if (params.size() > 0)
1807 nMinDepth = params[0].get_int();
1808 isminefilter includeWatchonly = ISMINE_SPENDABLE;
1809 if(params.size() > 1)
1810 if(params[1].get_bool())
1811 includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
1813 map<string, CAmount> mapAccountBalances;
1814 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
1815 if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
1816 mapAccountBalances[entry.second.name] = 0;
1819 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1821 const CWalletTx& wtx = (*it).second;
1823 string strSentAccount;
1824 list<COutputEntry> listReceived;
1825 list<COutputEntry> listSent;
1826 int nDepth = wtx.GetDepthInMainChain();
1827 if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
1829 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1830 mapAccountBalances[strSentAccount] -= nFee;
1831 BOOST_FOREACH(const COutputEntry& s, listSent)
1832 mapAccountBalances[strSentAccount] -= s.amount;
1833 if (nDepth >= nMinDepth)
1835 BOOST_FOREACH(const COutputEntry& r, listReceived)
1836 if (pwalletMain->mapAddressBook.count(r.destination))
1837 mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
1839 mapAccountBalances[""] += r.amount;
1843 list<CAccountingEntry> acentries;
1844 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1845 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1846 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1848 UniValue ret(UniValue::VOBJ);
1849 BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
1850 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1855 UniValue listsinceblock(const UniValue& params, bool fHelp)
1857 if (!EnsureWalletIsAvailable(fHelp))
1858 return NullUniValue;
1861 throw runtime_error(
1862 "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
1863 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
1865 "1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
1866 "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
1867 "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
1870 " \"transactions\": [\n"
1871 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
1872 " \"address\":\"zcashaddress\", (string) The Zcash address of the transaction. Not present for move transactions (category = move).\n"
1873 " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
1874 " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the 'move' category for moves \n"
1875 " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
1876 " \"vout\" : n, (numeric) the vout value\n"
1877 " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the 'send' category of transactions.\n"
1878 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
1879 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1880 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1881 " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
1882 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1883 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
1884 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
1885 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1886 " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
1888 " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
1891 + HelpExampleCli("listsinceblock", "")
1892 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1893 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1896 LOCK2(cs_main, pwalletMain->cs_wallet);
1898 CBlockIndex *pindex = NULL;
1899 int target_confirms = 1;
1900 isminefilter filter = ISMINE_SPENDABLE;
1902 if (params.size() > 0)
1906 blockId.SetHex(params[0].get_str());
1907 BlockMap::iterator it = mapBlockIndex.find(blockId);
1908 if (it != mapBlockIndex.end())
1909 pindex = it->second;
1912 if (params.size() > 1)
1914 target_confirms = params[1].get_int();
1916 if (target_confirms < 1)
1917 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1920 if(params.size() > 2)
1921 if(params[2].get_bool())
1922 filter = filter | ISMINE_WATCH_ONLY;
1924 int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
1926 UniValue transactions(UniValue::VARR);
1928 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1930 CWalletTx tx = (*it).second;
1932 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1933 ListTransactions(tx, "*", 0, true, transactions, filter);
1936 CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
1937 uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
1939 UniValue ret(UniValue::VOBJ);
1940 ret.push_back(Pair("transactions", transactions));
1941 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1946 UniValue gettransaction(const UniValue& params, bool fHelp)
1948 if (!EnsureWalletIsAvailable(fHelp))
1949 return NullUniValue;
1951 if (fHelp || params.size() < 1 || params.size() > 2)
1952 throw runtime_error(
1953 "gettransaction \"txid\" ( includeWatchonly )\n"
1954 "\nGet detailed information about in-wallet transaction <txid>\n"
1956 "1. \"txid\" (string, required) The transaction id\n"
1957 "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
1960 " \"amount\" : x.xxx, (numeric) The transaction amount in " + CURRENCY_UNIT + "\n"
1961 " \"confirmations\" : n, (numeric) The number of confirmations\n"
1962 " \"blockhash\" : \"hash\", (string) The block hash\n"
1963 " \"blockindex\" : xx, (numeric) The block index\n"
1964 " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
1965 " \"txid\" : \"transactionid\", (string) The transaction id.\n"
1966 " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
1967 " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
1968 " \"details\" : [\n"
1970 " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
1971 " \"address\" : \"zcashaddress\", (string) The Zcash address involved in the transaction\n"
1972 " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
1973 " \"amount\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n"
1974 " \"vout\" : n, (numeric) the vout value\n"
1978 " \"vjoinsplit\" : [\n"
1980 " \"anchor\" : \"treestateref\", (string) Merkle root of note commitment tree\n"
1981 " \"nullifiers\" : [ string, ... ] (string) Nullifiers of input notes\n"
1982 " \"commitments\" : [ string, ... ] (string) Note commitments for note outputs\n"
1983 " \"macs\" : [ string, ... ] (string) Message authentication tags\n"
1984 " \"vpub_old\" : x.xxx (numeric) The amount removed from the transparent value pool\n"
1985 " \"vpub_new\" : x.xxx, (numeric) The amount added to the transparent value pool\n"
1989 " \"hex\" : \"data\" (string) Raw data for transaction\n"
1993 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1994 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
1995 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1998 LOCK2(cs_main, pwalletMain->cs_wallet);
2001 hash.SetHex(params[0].get_str());
2003 isminefilter filter = ISMINE_SPENDABLE;
2004 if(params.size() > 1)
2005 if(params[1].get_bool())
2006 filter = filter | ISMINE_WATCH_ONLY;
2008 UniValue entry(UniValue::VOBJ);
2009 if (!pwalletMain->mapWallet.count(hash))
2010 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
2011 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
2013 CAmount nCredit = wtx.GetCredit(filter);
2014 CAmount nDebit = wtx.GetDebit(filter);
2015 CAmount nNet = nCredit - nDebit;
2016 CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
2018 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
2019 if (wtx.IsFromMe(filter))
2020 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
2022 WalletTxToJSON(wtx, entry);
2024 UniValue details(UniValue::VARR);
2025 ListTransactions(wtx, "*", 0, false, details, filter);
2026 entry.push_back(Pair("details", details));
2028 string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
2029 entry.push_back(Pair("hex", strHex));
2035 UniValue backupwallet(const UniValue& params, bool fHelp)
2037 if (!EnsureWalletIsAvailable(fHelp))
2038 return NullUniValue;
2040 if (fHelp || params.size() != 1)
2041 throw runtime_error(
2042 "backupwallet \"destination\"\n"
2043 "\nSafely copies wallet.dat to destination filename\n"
2045 "1. \"destination\" (string, required) The destination filename, saved in the directory set by -exportdir option.\n"
2047 "\"path\" (string) The full path of the destination file\n"
2049 + HelpExampleCli("backupwallet", "\"backupdata\"")
2050 + HelpExampleRpc("backupwallet", "\"backupdata\"")
2053 LOCK2(cs_main, pwalletMain->cs_wallet);
2055 boost::filesystem::path exportdir;
2057 exportdir = GetExportDir();
2058 } catch (const std::runtime_error& e) {
2059 throw JSONRPCError(RPC_INTERNAL_ERROR, e.what());
2061 if (exportdir.empty()) {
2062 throw JSONRPCError(RPC_WALLET_ERROR, "Cannot backup wallet until the -exportdir option has been set");
2064 std::string unclean = params[0].get_str();
2065 std::string clean = SanitizeFilename(unclean);
2066 if (clean.compare(unclean) != 0) {
2067 throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Filename is invalid as only alphanumeric characters are allowed. Try '%s' instead.", clean));
2069 boost::filesystem::path exportfilepath = exportdir / clean;
2071 if (!BackupWallet(*pwalletMain, exportfilepath.string()))
2072 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
2074 return exportfilepath.string();
2078 UniValue keypoolrefill(const UniValue& params, bool fHelp)
2080 if (!EnsureWalletIsAvailable(fHelp))
2081 return NullUniValue;
2083 if (fHelp || params.size() > 1)
2084 throw runtime_error(
2085 "keypoolrefill ( newsize )\n"
2086 "\nFills the keypool."
2087 + HelpRequiringPassphrase() + "\n"
2089 "1. newsize (numeric, optional, default=100) The new keypool size\n"
2091 + HelpExampleCli("keypoolrefill", "")
2092 + HelpExampleRpc("keypoolrefill", "")
2095 LOCK2(cs_main, pwalletMain->cs_wallet);
2097 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
2098 unsigned int kpSize = 0;
2099 if (params.size() > 0) {
2100 if (params[0].get_int() < 0)
2101 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
2102 kpSize = (unsigned int)params[0].get_int();
2105 EnsureWalletIsUnlocked();
2106 pwalletMain->TopUpKeyPool(kpSize);
2108 if (pwalletMain->GetKeyPoolSize() < kpSize)
2109 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
2111 return NullUniValue;
2115 static void LockWallet(CWallet* pWallet)
2117 LOCK(cs_nWalletUnlockTime);
2118 nWalletUnlockTime = 0;
2122 UniValue walletpassphrase(const UniValue& params, bool fHelp)
2124 if (!EnsureWalletIsAvailable(fHelp))
2125 return NullUniValue;
2127 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
2128 throw runtime_error(
2129 "walletpassphrase \"passphrase\" timeout\n"
2130 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
2131 "This is needed prior to performing transactions related to private keys such as sending Zcash\n"
2133 "1. \"passphrase\" (string, required) The wallet passphrase\n"
2134 "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
2136 "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
2137 "time that overrides the old one.\n"
2139 "\nunlock the wallet for 60 seconds\n"
2140 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
2141 "\nLock the wallet again (before 60 seconds)\n"
2142 + HelpExampleCli("walletlock", "") +
2143 "\nAs json rpc call\n"
2144 + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
2147 LOCK2(cs_main, pwalletMain->cs_wallet);
2151 if (!pwalletMain->IsCrypted())
2152 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
2154 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
2155 SecureString strWalletPass;
2156 strWalletPass.reserve(100);
2157 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2158 // Alternately, find a way to make params[0] mlock()'d to begin with.
2159 strWalletPass = params[0].get_str().c_str();
2161 if (strWalletPass.length() > 0)
2163 if (!pwalletMain->Unlock(strWalletPass))
2164 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
2167 throw runtime_error(
2168 "walletpassphrase <passphrase> <timeout>\n"
2169 "Stores the wallet decryption key in memory for <timeout> seconds.");
2171 // No need to check return values, because the wallet was unlocked above
2172 pwalletMain->UpdateNullifierNoteMap();
2173 pwalletMain->TopUpKeyPool();
2175 int64_t nSleepTime = params[1].get_int64();
2176 LOCK(cs_nWalletUnlockTime);
2177 nWalletUnlockTime = GetTime() + nSleepTime;
2178 RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
2180 return NullUniValue;
2184 UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
2186 if (!EnsureWalletIsAvailable(fHelp))
2187 return NullUniValue;
2189 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
2190 throw runtime_error(
2191 "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
2192 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
2194 "1. \"oldpassphrase\" (string) The current passphrase\n"
2195 "2. \"newpassphrase\" (string) The new passphrase\n"
2197 + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
2198 + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
2201 LOCK2(cs_main, pwalletMain->cs_wallet);
2205 if (!pwalletMain->IsCrypted())
2206 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
2208 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
2209 // Alternately, find a way to make params[0] mlock()'d to begin with.
2210 SecureString strOldWalletPass;
2211 strOldWalletPass.reserve(100);
2212 strOldWalletPass = params[0].get_str().c_str();
2214 SecureString strNewWalletPass;
2215 strNewWalletPass.reserve(100);
2216 strNewWalletPass = params[1].get_str().c_str();
2218 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
2219 throw runtime_error(
2220 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
2221 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
2223 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
2224 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
2226 return NullUniValue;
2230 UniValue walletlock(const UniValue& params, bool fHelp)
2232 if (!EnsureWalletIsAvailable(fHelp))
2233 return NullUniValue;
2235 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
2236 throw runtime_error(
2238 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
2239 "After calling this method, you will need to call walletpassphrase again\n"
2240 "before being able to call any methods which require the wallet to be unlocked.\n"
2242 "\nSet the passphrase for 2 minutes to perform a transaction\n"
2243 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
2244 "\nPerform a send (requires passphrase set)\n"
2245 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 1.0") +
2246 "\nClear the passphrase since we are done before 2 minutes is up\n"
2247 + HelpExampleCli("walletlock", "") +
2248 "\nAs json rpc call\n"
2249 + HelpExampleRpc("walletlock", "")
2252 LOCK2(cs_main, pwalletMain->cs_wallet);
2256 if (!pwalletMain->IsCrypted())
2257 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
2260 LOCK(cs_nWalletUnlockTime);
2261 pwalletMain->Lock();
2262 nWalletUnlockTime = 0;
2265 return NullUniValue;
2269 UniValue encryptwallet(const UniValue& params, bool fHelp)
2271 if (!EnsureWalletIsAvailable(fHelp))
2272 return NullUniValue;
2274 auto fEnableWalletEncryption = fExperimentalMode && GetBoolArg("-developerencryptwallet", false);
2276 std::string strWalletEncryptionDisabledMsg = "";
2277 if (!fEnableWalletEncryption) {
2278 strWalletEncryptionDisabledMsg = "\nWARNING: Wallet encryption is DISABLED. This call always fails.\n";
2281 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
2282 throw runtime_error(
2283 "encryptwallet \"passphrase\"\n"
2284 + strWalletEncryptionDisabledMsg +
2285 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
2286 "After this, any calls that interact with private keys such as sending or signing \n"
2287 "will require the passphrase to be set prior the making these calls.\n"
2288 "Use the walletpassphrase call for this, and then walletlock call.\n"
2289 "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
2290 "Note that this will shutdown the server.\n"
2292 "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
2294 "\nEncrypt you wallet\n"
2295 + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
2296 "\nNow set the passphrase to use the wallet, such as for signing or sending Zcash\n"
2297 + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
2298 "\nNow we can so something like sign\n"
2299 + HelpExampleCli("signmessage", "\"zcashaddress\" \"test message\"") +
2300 "\nNow lock the wallet again by removing the passphrase\n"
2301 + HelpExampleCli("walletlock", "") +
2302 "\nAs a json rpc call\n"
2303 + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
2306 LOCK2(cs_main, pwalletMain->cs_wallet);
2310 if (!fEnableWalletEncryption) {
2311 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet encryption is disabled.");
2313 if (pwalletMain->IsCrypted())
2314 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
2316 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2317 // Alternately, find a way to make params[0] mlock()'d to begin with.
2318 SecureString strWalletPass;
2319 strWalletPass.reserve(100);
2320 strWalletPass = params[0].get_str().c_str();
2322 if (strWalletPass.length() < 1)
2323 throw runtime_error(
2324 "encryptwallet <passphrase>\n"
2325 "Encrypts the wallet with <passphrase>.");
2327 if (!pwalletMain->EncryptWallet(strWalletPass))
2328 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
2330 // BDB seems to have a bad habit of writing old data into
2331 // slack space in .dat files; that is bad if the old data is
2332 // unencrypted private keys. So:
2334 return "wallet encrypted; Komodo server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
2337 UniValue lockunspent(const UniValue& params, bool fHelp)
2339 if (!EnsureWalletIsAvailable(fHelp))
2340 return NullUniValue;
2342 if (fHelp || params.size() < 1 || params.size() > 2)
2343 throw runtime_error(
2344 "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
2345 "\nUpdates list of temporarily unspendable outputs.\n"
2346 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
2347 "A locked transaction output will not be chosen by automatic coin selection, when spending Zcash.\n"
2348 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2349 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
2350 "Also see the listunspent call\n"
2352 "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
2353 "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
2354 " [ (json array of json objects)\n"
2356 " \"txid\":\"id\", (string) The transaction id\n"
2357 " \"vout\": n (numeric) The output number\n"
2363 "true|false (boolean) Whether the command was successful or not\n"
2366 "\nList the unspent transactions\n"
2367 + HelpExampleCli("listunspent", "") +
2368 "\nLock an unspent transaction\n"
2369 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2370 "\nList the locked transactions\n"
2371 + HelpExampleCli("listlockunspent", "") +
2372 "\nUnlock the transaction again\n"
2373 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2374 "\nAs a json rpc call\n"
2375 + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
2378 LOCK2(cs_main, pwalletMain->cs_wallet);
2380 if (params.size() == 1)
2381 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL));
2383 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
2385 bool fUnlock = params[0].get_bool();
2387 if (params.size() == 1) {
2389 pwalletMain->UnlockAllCoins();
2393 UniValue outputs = params[1].get_array();
2394 for (size_t idx = 0; idx < outputs.size(); idx++) {
2395 const UniValue& output = outputs[idx];
2396 if (!output.isObject())
2397 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
2398 const UniValue& o = output.get_obj();
2400 RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM));
2402 string txid = find_value(o, "txid").get_str();
2404 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
2406 int nOutput = find_value(o, "vout").get_int();
2408 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
2410 COutPoint outpt(uint256S(txid), nOutput);
2413 pwalletMain->UnlockCoin(outpt);
2415 pwalletMain->LockCoin(outpt);
2421 UniValue listlockunspent(const UniValue& params, bool fHelp)
2423 if (!EnsureWalletIsAvailable(fHelp))
2424 return NullUniValue;
2426 if (fHelp || params.size() > 0)
2427 throw runtime_error(
2429 "\nReturns list of temporarily unspendable outputs.\n"
2430 "See the lockunspent call to lock and unlock transactions for spending.\n"
2434 " \"txid\" : \"transactionid\", (string) The transaction id locked\n"
2435 " \"vout\" : n (numeric) The vout value\n"
2440 "\nList the unspent transactions\n"
2441 + HelpExampleCli("listunspent", "") +
2442 "\nLock an unspent transaction\n"
2443 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2444 "\nList the locked transactions\n"
2445 + HelpExampleCli("listlockunspent", "") +
2446 "\nUnlock the transaction again\n"
2447 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2448 "\nAs a json rpc call\n"
2449 + HelpExampleRpc("listlockunspent", "")
2452 LOCK2(cs_main, pwalletMain->cs_wallet);
2454 vector<COutPoint> vOutpts;
2455 pwalletMain->ListLockedCoins(vOutpts);
2457 UniValue ret(UniValue::VARR);
2459 BOOST_FOREACH(COutPoint &outpt, vOutpts) {
2460 UniValue o(UniValue::VOBJ);
2462 o.push_back(Pair("txid", outpt.hash.GetHex()));
2463 o.push_back(Pair("vout", (int)outpt.n));
2470 UniValue settxfee(const UniValue& params, bool fHelp)
2472 if (!EnsureWalletIsAvailable(fHelp))
2473 return NullUniValue;
2475 if (fHelp || params.size() < 1 || params.size() > 1)
2476 throw runtime_error(
2478 "\nSet the transaction fee per kB.\n"
2480 "1. amount (numeric, required) The transaction fee in " + CURRENCY_UNIT + "/kB rounded to the nearest 0.00000001\n"
2482 "true|false (boolean) Returns true if successful\n"
2484 + HelpExampleCli("settxfee", "0.00001")
2485 + HelpExampleRpc("settxfee", "0.00001")
2488 LOCK2(cs_main, pwalletMain->cs_wallet);
2491 CAmount nAmount = AmountFromValue(params[0]);
2493 payTxFee = CFeeRate(nAmount, 1000);
2497 UniValue getwalletinfo(const UniValue& params, bool fHelp)
2499 if (!EnsureWalletIsAvailable(fHelp))
2500 return NullUniValue;
2502 if (fHelp || params.size() != 0)
2503 throw runtime_error(
2505 "Returns an object containing various wallet state info.\n"
2508 " \"walletversion\": xxxxx, (numeric) the wallet version\n"
2509 " \"balance\": xxxxxxx, (numeric) the total confirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
2510 " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
2511 " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + CURRENCY_UNIT + "\n"
2512 " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
2513 " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
2514 " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
2515 " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
2516 " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in KMD/KB\n"
2519 + HelpExampleCli("getwalletinfo", "")
2520 + HelpExampleRpc("getwalletinfo", "")
2523 LOCK2(cs_main, pwalletMain->cs_wallet);
2525 UniValue obj(UniValue::VOBJ);
2526 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
2527 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
2528 obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
2529 obj.push_back(Pair("immature_balance", ValueFromAmount(pwalletMain->GetImmatureBalance())));
2530 obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size()));
2531 obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
2532 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
2533 if (pwalletMain->IsCrypted())
2534 obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
2535 obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
2539 UniValue resendwallettransactions(const UniValue& params, bool fHelp)
2541 if (!EnsureWalletIsAvailable(fHelp))
2542 return NullUniValue;
2544 if (fHelp || params.size() != 0)
2545 throw runtime_error(
2546 "resendwallettransactions\n"
2547 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
2548 "Intended only for testing; the wallet code periodically re-broadcasts\n"
2550 "Returns array of transaction ids that were re-broadcast.\n"
2553 LOCK2(cs_main, pwalletMain->cs_wallet);
2555 std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
2556 UniValue result(UniValue::VARR);
2557 BOOST_FOREACH(const uint256& txid, txids)
2559 result.push_back(txid.ToString());
2564 uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
2566 UniValue listunspent(const UniValue& params, bool fHelp)
2568 if (!EnsureWalletIsAvailable(fHelp))
2569 return NullUniValue;
2571 if (fHelp || params.size() > 3)
2572 throw runtime_error(
2573 "listunspent ( minconf maxconf [\"address\",...] )\n"
2574 "\nReturns array of unspent transaction outputs\n"
2575 "with between minconf and maxconf (inclusive) confirmations.\n"
2576 "Optionally filter to only include txouts paid to specified addresses.\n"
2577 "Results are an array of Objects, each of which has:\n"
2578 "{txid, vout, scriptPubKey, amount, confirmations}\n"
2580 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
2581 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
2582 "3. \"addresses\" (string) A json array of Zcash addresses to filter\n"
2584 " \"address\" (string) Zcash address\n"
2588 "[ (array of json object)\n"
2590 " \"txid\" : \"txid\", (string) the transaction id \n"
2591 " \"vout\" : n, (numeric) the vout value\n"
2592 " \"generated\" : true|false (boolean) true if txout is a coinbase transaction output\n"
2593 " \"address\" : \"address\", (string) the Zcash address\n"
2594 " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
2595 " \"scriptPubKey\" : \"key\", (string) the script key\n"
2596 " \"amount\" : x.xxx, (numeric) the transaction amount in " + CURRENCY_UNIT + "\n"
2597 " \"confirmations\" : n (numeric) The number of confirmations\n"
2603 + HelpExampleCli("listunspent", "")
2604 + HelpExampleCli("listunspent", "6 9999999 \"[\\\"t1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"t1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2605 + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"t1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"t1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2608 RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
2611 if (params.size() > 0)
2612 nMinDepth = params[0].get_int();
2614 int nMaxDepth = 9999999;
2615 if (params.size() > 1)
2616 nMaxDepth = params[1].get_int();
2618 set<CBitcoinAddress> setAddress;
2619 if (params.size() > 2) {
2620 UniValue inputs = params[2].get_array();
2621 for (size_t idx = 0; idx < inputs.size(); idx++) {
2622 const UniValue& input = inputs[idx];
2623 CBitcoinAddress address(input.get_str());
2624 if (!address.IsValid())
2625 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Komodo address: ")+input.get_str());
2626 if (setAddress.count(address))
2627 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
2628 setAddress.insert(address);
2632 UniValue results(UniValue::VARR);
2633 vector<COutput> vecOutputs;
2634 assert(pwalletMain != NULL);
2635 LOCK2(cs_main, pwalletMain->cs_wallet);
2636 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2637 BOOST_FOREACH(const COutput& out, vecOutputs) {
2638 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
2641 if (setAddress.size()) {
2642 CTxDestination address;
2643 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
2646 if (!setAddress.count(address))
2650 CAmount nValue = out.tx->vout[out.i].nValue;
2651 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
2652 UniValue entry(UniValue::VOBJ);
2653 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
2654 entry.push_back(Pair("vout", out.i));
2655 entry.push_back(Pair("generated", out.tx->IsCoinBase()));
2656 CTxDestination address;
2657 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
2658 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
2659 if (pwalletMain->mapAddressBook.count(address))
2660 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
2662 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
2663 if (pk.IsPayToScriptHash()) {
2664 CTxDestination address;
2665 if (ExtractDestination(pk, address)) {
2666 const CScriptID& hash = boost::get<CScriptID>(address);
2667 CScript redeemScript;
2668 if (pwalletMain->GetCScript(hash, redeemScript))
2669 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
2672 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
2673 if ( out.tx->nLockTime != 0 )
2675 BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
2676 CBlockIndex *tipindex,*pindex = it->second;
2677 uint64_t interest; uint32_t locktime; int32_t txheight;
2678 if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 )
2680 komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight);
2681 interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime);
2682 entry.push_back(Pair("interest",ValueFromAmount(interest)));
2684 //fprintf(stderr,"nValue %.8f pindex.%p tipindex.%p locktime.%u txheight.%d pindexht.%d\n",(double)nValue/COIN,pindex,chainActive.Tip(),locktime,txheight,pindex->nHeight);
2686 entry.push_back(Pair("confirmations",out.nDepth));
2687 entry.push_back(Pair("spendable", out.fSpendable));
2688 results.push_back(entry);
2694 uint64_t komodo_interestsum()
2696 uint64_t interest,sum = 0;
2697 vector<COutput> vecOutputs;
2698 assert(pwalletMain != NULL);
2699 LOCK2(cs_main, pwalletMain->cs_wallet);
2700 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2701 BOOST_FOREACH(const COutput& out,vecOutputs)
2703 CAmount nValue = out.tx->vout[out.i].nValue;
2704 if ( out.tx->nLockTime != 0 && out.fSpendable != 0 )
2706 BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
2707 CBlockIndex *tipindex,*pindex = it->second;
2708 if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 )
2710 interest = komodo_interest(pindex->nHeight,nValue,out.tx->nLockTime,tipindex->nTime);
2718 UniValue fundrawtransaction(const UniValue& params, bool fHelp)
2720 if (!EnsureWalletIsAvailable(fHelp))
2721 return NullUniValue;
2723 if (fHelp || params.size() != 1)
2724 throw runtime_error(
2725 "fundrawtransaction \"hexstring\"\n"
2726 "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
2727 "This will not modify existing inputs, and will add one change output to the outputs.\n"
2728 "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
2729 "The inputs added will not be signed, use signrawtransaction for that.\n"
2731 "1. \"hexstring\" (string, required) The hex string of the raw transaction\n"
2734 " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
2735 " \"fee\": n, (numeric) The fee added to the transaction\n"
2736 " \"changepos\": n (numeric) The position of the added change output, or -1\n"
2740 "\nCreate a transaction with no inputs\n"
2741 + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
2742 "\nAdd sufficient unsigned inputs to meet the output value\n"
2743 + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
2744 "\nSign the transaction\n"
2745 + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
2746 "\nSend the transaction\n"
2747 + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
2750 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
2752 // parse hex string from parameter
2753 CTransaction origTx;
2754 if (!DecodeHexTx(origTx, params[0].get_str()))
2755 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2757 CMutableTransaction tx(origTx);
2759 string strFailReason;
2760 int nChangePos = -1;
2761 if(!pwalletMain->FundTransaction(tx, nFee, nChangePos, strFailReason))
2762 throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
2764 UniValue result(UniValue::VOBJ);
2765 result.push_back(Pair("hex", EncodeHexTx(tx)));
2766 result.push_back(Pair("changepos", nChangePos));
2767 result.push_back(Pair("fee", ValueFromAmount(nFee)));
2772 UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp)
2775 throw runtime_error(
2776 "zcsamplejoinsplit\n"
2778 "Perform a joinsplit and return the JSDescription.\n"
2785 uint256 anchor = ZCIncrementalMerkleTree().root();
2786 JSDescription samplejoinsplit(*pzcashParams,
2789 {JSInput(), JSInput()},
2790 {JSOutput(), JSOutput()},
2794 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2795 ss << samplejoinsplit;
2797 return HexStr(ss.begin(), ss.end());
2800 UniValue zc_benchmark(const UniValue& params, bool fHelp)
2802 if (!EnsureWalletIsAvailable(fHelp)) {
2803 return NullUniValue;
2806 if (fHelp || params.size() < 2) {
2807 throw runtime_error(
2808 "zcbenchmark benchmarktype samplecount\n"
2810 "Runs a benchmark of the selected type samplecount times,\n"
2811 "returning the running times of each sample.\n"
2815 " \"runningtime\": runningtime\n"
2818 " \"runningtime\": runningtime\n"
2827 std::string benchmarktype = params[0].get_str();
2828 int samplecount = params[1].get_int();
2830 if (samplecount <= 0) {
2831 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount");
2834 std::vector<double> sample_times;
2836 JSDescription samplejoinsplit;
2838 if (benchmarktype == "verifyjoinsplit") {
2839 CDataStream ss(ParseHexV(params[2].get_str(), "js"), SER_NETWORK, PROTOCOL_VERSION);
2840 ss >> samplejoinsplit;
2843 for (int i = 0; i < samplecount; i++) {
2844 if (benchmarktype == "sleep") {
2845 sample_times.push_back(benchmark_sleep());
2846 } else if (benchmarktype == "parameterloading") {
2847 sample_times.push_back(benchmark_parameter_loading());
2848 } else if (benchmarktype == "createjoinsplit") {
2849 if (params.size() < 3) {
2850 sample_times.push_back(benchmark_create_joinsplit());
2852 int nThreads = params[2].get_int();
2853 std::vector<double> vals = benchmark_create_joinsplit_threaded(nThreads);
2854 // Divide by nThreads^2 to get average seconds per JoinSplit because
2855 // we are running one JoinSplit per thread.
2856 sample_times.push_back(std::accumulate(vals.begin(), vals.end(), 0.0) / (nThreads*nThreads));
2858 } else if (benchmarktype == "verifyjoinsplit") {
2859 sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
2860 #ifdef ENABLE_MINING
2861 } else if (benchmarktype == "solveequihash") {
2862 if (params.size() < 3) {
2863 sample_times.push_back(benchmark_solve_equihash());
2865 int nThreads = params[2].get_int();
2866 std::vector<double> vals = benchmark_solve_equihash_threaded(nThreads);
2867 sample_times.insert(sample_times.end(), vals.begin(), vals.end());
2870 } else if (benchmarktype == "verifyequihash") {
2871 sample_times.push_back(benchmark_verify_equihash());
2872 } else if (benchmarktype == "validatelargetx") {
2873 // Number of inputs in the spending transaction that we will simulate
2875 if (params.size() >= 3) {
2876 nInputs = params[2].get_int();
2878 sample_times.push_back(benchmark_large_tx(nInputs));
2879 } else if (benchmarktype == "trydecryptnotes") {
2880 int nAddrs = params[2].get_int();
2881 sample_times.push_back(benchmark_try_decrypt_notes(nAddrs));
2882 } else if (benchmarktype == "incnotewitnesses") {
2883 int nTxs = params[2].get_int();
2884 sample_times.push_back(benchmark_increment_note_witnesses(nTxs));
2885 } else if (benchmarktype == "connectblockslow") {
2886 if (Params().NetworkIDString() != "regtest") {
2887 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2889 sample_times.push_back(benchmark_connectblock_slow());
2890 } else if (benchmarktype == "sendtoaddress") {
2891 if (Params().NetworkIDString() != "regtest") {
2892 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2894 auto amount = AmountFromValue(params[2]);
2895 sample_times.push_back(benchmark_sendtoaddress(amount));
2896 } else if (benchmarktype == "loadwallet") {
2897 if (Params().NetworkIDString() != "regtest") {
2898 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2900 sample_times.push_back(benchmark_loadwallet());
2901 } else if (benchmarktype == "listunspent") {
2902 sample_times.push_back(benchmark_listunspent());
2904 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
2908 UniValue results(UniValue::VARR);
2909 for (auto time : sample_times) {
2910 UniValue result(UniValue::VOBJ);
2911 result.push_back(Pair("runningtime", time));
2912 results.push_back(result);
2918 UniValue zc_raw_receive(const UniValue& params, bool fHelp)
2920 if (!EnsureWalletIsAvailable(fHelp)) {
2921 return NullUniValue;
2924 if (fHelp || params.size() != 2) {
2925 throw runtime_error(
2926 "zcrawreceive zcsecretkey encryptednote\n"
2928 "DEPRECATED. Decrypts encryptednote and checks if the coin commitments\n"
2929 "are in the blockchain as indicated by the \"exists\" result.\n"
2932 " \"amount\": value,\n"
2933 " \"note\": noteplaintext,\n"
2934 " \"exists\": exists\n"
2939 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR));
2943 CZCSpendingKey spendingkey(params[0].get_str());
2944 SpendingKey k = spendingkey.Get();
2947 unsigned char nonce;
2948 ZCNoteEncryption::Ciphertext ct;
2952 CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
2958 } catch(const std::exception &) {
2959 throw runtime_error(
2960 "encrypted_note could not be decoded"
2965 ZCNoteDecryption decryptor(k.receiving_key());
2967 NotePlaintext npt = NotePlaintext::decrypt(
2974 PaymentAddress payment_addr = k.address();
2975 Note decrypted_note = npt.note(payment_addr);
2977 assert(pwalletMain != NULL);
2978 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
2980 uint256 commitment = decrypted_note.cm();
2981 pwalletMain->WitnessNoteCommitment(
2987 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2990 UniValue result(UniValue::VOBJ);
2991 result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value)));
2992 result.push_back(Pair("note", HexStr(ss.begin(), ss.end())));
2993 result.push_back(Pair("exists", (bool) witnesses[0]));
2999 UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
3001 if (!EnsureWalletIsAvailable(fHelp)) {
3002 return NullUniValue;
3005 if (fHelp || params.size() != 5) {
3006 throw runtime_error(
3007 "zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
3008 " inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
3009 " outputs: a JSON object mapping {zcaddr: value, ...}\n"
3011 "DEPRECATED. Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
3012 "Outputs are confidential between sender/receiver. The vpub_old and\n"
3013 "vpub_new values are globally public and move transparent value into\n"
3014 "or out of the confidential value store, respectively.\n"
3016 "Note: The caller is responsible for delivering the output enc1 and\n"
3017 "enc2 to the appropriate recipients, as well as signing rawtxout and\n"
3018 "ensuring it is mined. (A future RPC call will deliver the confidential\n"
3019 "payments in-band on the blockchain.)\n"
3022 " \"encryptednote1\": enc1,\n"
3023 " \"encryptednote2\": enc2,\n"
3024 " \"rawtxn\": rawtxout\n"
3032 if (!DecodeHexTx(tx, params[0].get_str()))
3033 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
3035 UniValue inputs = params[1].get_obj();
3036 UniValue outputs = params[2].get_obj();
3038 CAmount vpub_old(0);
3039 CAmount vpub_new(0);
3041 if (params[3].get_real() != 0.0)
3042 vpub_old = AmountFromValue(params[3]);
3044 if (params[4].get_real() != 0.0)
3045 vpub_new = AmountFromValue(params[4]);
3047 std::vector<JSInput> vjsin;
3048 std::vector<JSOutput> vjsout;
3049 std::vector<Note> notes;
3050 std::vector<SpendingKey> keys;
3051 std::vector<uint256> commitments;
3053 for (const string& name_ : inputs.getKeys()) {
3054 CZCSpendingKey spendingkey(inputs[name_].get_str());
3055 SpendingKey k = spendingkey.Get();
3062 CDataStream ssData(ParseHexV(name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
3066 PaymentAddress addr = k.address();
3067 Note note = npt.note(addr);
3068 notes.push_back(note);
3069 commitments.push_back(note.cm());
3073 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
3074 pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
3076 assert(witnesses.size() == notes.size());
3077 assert(notes.size() == keys.size());
3080 for (size_t i = 0; i < witnesses.size(); i++) {
3081 if (!witnesses[i]) {
3082 throw runtime_error(
3083 "joinsplit input could not be found in tree"
3087 vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
3091 while (vjsin.size() < ZC_NUM_JS_INPUTS) {
3092 vjsin.push_back(JSInput());
3095 for (const string& name_ : outputs.getKeys()) {
3096 CZCPaymentAddress pubaddr(name_);
3097 PaymentAddress addrTo = pubaddr.Get();
3098 CAmount nAmount = AmountFromValue(outputs[name_]);
3100 vjsout.push_back(JSOutput(addrTo, nAmount));
3103 while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
3104 vjsout.push_back(JSOutput());
3108 if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
3109 throw runtime_error("unsupported joinsplit input/output counts");
3112 uint256 joinSplitPubKey;
3113 unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
3114 crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
3116 CMutableTransaction mtx(tx);
3118 mtx.joinSplitPubKey = joinSplitPubKey;
3120 JSDescription jsdesc(*pzcashParams,
3123 {vjsin[0], vjsin[1]},
3124 {vjsout[0], vjsout[1]},
3129 auto verifier = libzcash::ProofVerifier::Strict();
3130 assert(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey));
3133 mtx.vjoinsplit.push_back(jsdesc);
3135 // Empty output script.
3137 CTransaction signTx(mtx);
3138 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
3139 uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
3141 // Add the signature
3142 assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
3143 dataToBeSigned.begin(), 32,
3148 assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
3149 dataToBeSigned.begin(), 32,
3150 mtx.joinSplitPubKey.begin()
3153 CTransaction rawTx(mtx);
3155 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
3158 std::string encryptedNote1;
3159 std::string encryptedNote2;
3161 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
3162 ss2 << ((unsigned char) 0x00);
3163 ss2 << jsdesc.ephemeralKey;
3164 ss2 << jsdesc.ciphertexts[0];
3165 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
3167 encryptedNote1 = HexStr(ss2.begin(), ss2.end());
3170 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
3171 ss2 << ((unsigned char) 0x01);
3172 ss2 << jsdesc.ephemeralKey;
3173 ss2 << jsdesc.ciphertexts[1];
3174 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
3176 encryptedNote2 = HexStr(ss2.begin(), ss2.end());
3179 UniValue result(UniValue::VOBJ);
3180 result.push_back(Pair("encryptednote1", encryptedNote1));
3181 result.push_back(Pair("encryptednote2", encryptedNote2));
3182 result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
3186 UniValue zc_raw_keygen(const UniValue& params, bool fHelp)
3188 if (!EnsureWalletIsAvailable(fHelp)) {
3189 return NullUniValue;
3192 if (fHelp || params.size() != 0) {
3193 throw runtime_error(
3196 "DEPRECATED. Generate a zcaddr which can send and receive confidential values.\n"
3199 " \"zcaddress\": zcaddr,\n"
3200 " \"zcsecretkey\": zcsecretkey,\n"
3201 " \"zcviewingkey\": zcviewingkey,\n"
3206 auto k = SpendingKey::random();
3207 auto addr = k.address();
3208 auto viewing_key = k.viewing_key();
3210 CZCPaymentAddress pubaddr(addr);
3211 CZCSpendingKey spendingkey(k);
3212 CZCViewingKey viewingkey(viewing_key);
3214 UniValue result(UniValue::VOBJ);
3215 result.push_back(Pair("zcaddress", pubaddr.ToString()));
3216 result.push_back(Pair("zcsecretkey", spendingkey.ToString()));
3217 result.push_back(Pair("zcviewingkey", viewingkey.ToString()));
3222 UniValue z_getnewaddress(const UniValue& params, bool fHelp)
3224 if (!EnsureWalletIsAvailable(fHelp))
3225 return NullUniValue;
3227 if (fHelp || params.size() > 0)
3228 throw runtime_error(
3230 "\nReturns a new zaddr for receiving payments.\n"
3233 "\"zcashaddress\" (string) The new zaddr\n"
3235 + HelpExampleCli("z_getnewaddress", "")
3236 + HelpExampleRpc("z_getnewaddress", "")
3239 LOCK2(cs_main, pwalletMain->cs_wallet);
3241 EnsureWalletIsUnlocked();
3243 CZCPaymentAddress pubaddr = pwalletMain->GenerateNewZKey();
3244 std::string result = pubaddr.ToString();
3249 UniValue z_listaddresses(const UniValue& params, bool fHelp)
3251 if (!EnsureWalletIsAvailable(fHelp))
3252 return NullUniValue;
3254 if (fHelp || params.size() > 1)
3255 throw runtime_error(
3256 "z_listaddresses ( includeWatchonly )\n"
3257 "\nReturns the list of zaddr belonging to the wallet.\n"
3259 "1. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n"
3261 "[ (json array of string)\n"
3262 " \"zaddr\" (string) a zaddr belonging to the wallet\n"
3266 + HelpExampleCli("z_listaddresses", "")
3267 + HelpExampleRpc("z_listaddresses", "")
3270 LOCK2(cs_main, pwalletMain->cs_wallet);
3272 bool fIncludeWatchonly = false;
3273 if (params.size() > 0) {
3274 fIncludeWatchonly = params[0].get_bool();
3277 UniValue ret(UniValue::VARR);
3278 std::set<libzcash::PaymentAddress> addresses;
3279 pwalletMain->GetPaymentAddresses(addresses);
3280 for (auto addr : addresses ) {
3281 if (fIncludeWatchonly || pwalletMain->HaveSpendingKey(addr)) {
3282 ret.push_back(CZCPaymentAddress(addr).ToString());
3288 CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ignoreUnspendable=true) {
3289 set<CBitcoinAddress> setAddress;
3290 vector<COutput> vecOutputs;
3291 CAmount balance = 0;
3293 if (transparentAddress.length() > 0) {
3294 CBitcoinAddress taddr = CBitcoinAddress(transparentAddress);
3295 if (!taddr.IsValid()) {
3296 throw std::runtime_error("invalid transparent address");
3298 setAddress.insert(taddr);
3301 LOCK2(cs_main, pwalletMain->cs_wallet);
3303 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
3305 BOOST_FOREACH(const COutput& out, vecOutputs) {
3306 if (out.nDepth < minDepth) {
3310 if (ignoreUnspendable && !out.fSpendable) {
3314 if (setAddress.size()) {
3315 CTxDestination address;
3316 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3320 if (!setAddress.count(address)) {
3325 CAmount nValue = out.tx->vout[out.i].nValue; // komodo_interest
3331 CAmount getBalanceZaddr(std::string address, int minDepth = 1, bool ignoreUnspendable=true) {
3332 CAmount balance = 0;
3333 std::vector<CNotePlaintextEntry> entries;
3334 LOCK2(cs_main, pwalletMain->cs_wallet);
3335 pwalletMain->GetFilteredNotes(entries, address, minDepth, true, ignoreUnspendable);
3336 for (auto & entry : entries) {
3337 balance += CAmount(entry.plaintext.value);
3343 UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
3345 if (!EnsureWalletIsAvailable(fHelp))
3346 return NullUniValue;
3348 if (fHelp || params.size()==0 || params.size() >2)
3349 throw runtime_error(
3350 "z_listreceivedbyaddress \"address\" ( minconf )\n"
3351 "\nReturn a list of amounts received by a zaddr belonging to the node’s wallet.\n"
3353 "1. \"address\" (string) The private address.\n"
3354 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3357 " \"txid\": xxxxx, (string) the transaction id\n"
3358 " \"amount\": xxxxx, (numeric) the amount of value in the note\n"
3359 " \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
3362 + HelpExampleCli("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3363 + HelpExampleRpc("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3366 LOCK2(cs_main, pwalletMain->cs_wallet);
3369 if (params.size() > 1) {
3370 nMinDepth = params[1].get_int();
3372 if (nMinDepth < 0) {
3373 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3376 // Check that the from address is valid.
3377 auto fromaddress = params[0].get_str();
3379 libzcash::PaymentAddress zaddr;
3380 CZCPaymentAddress address(fromaddress);
3382 zaddr = address.Get();
3383 } catch (const std::runtime_error&) {
3384 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
3387 if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) {
3388 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
3392 UniValue result(UniValue::VARR);
3393 std::vector<CNotePlaintextEntry> entries;
3394 pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false, false);
3395 for (CNotePlaintextEntry & entry : entries) {
3396 UniValue obj(UniValue::VOBJ);
3397 obj.push_back(Pair("txid",entry.jsop.hash.ToString()));
3398 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value))));
3399 std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end());
3400 obj.push_back(Pair("memo", HexStr(data)));
3401 result.push_back(obj);
3407 UniValue z_getbalance(const UniValue& params, bool fHelp)
3409 if (!EnsureWalletIsAvailable(fHelp))
3410 return NullUniValue;
3412 if (fHelp || params.size()==0 || params.size() >2)
3413 throw runtime_error(
3414 "z_getbalance \"address\" ( minconf )\n"
3415 "\nReturns the balance of a taddr or zaddr belonging to the node’s wallet.\n"
3416 "\nCAUTION: If address is a watch-only zaddr, the returned balance may be larger than the actual balance,"
3417 "\nbecause spends cannot be detected with incoming viewing keys.\n"
3419 "1. \"address\" (string) The selected address. It may be a transparent or private address.\n"
3420 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3422 "amount (numeric) The total amount in KMD received for this address.\n"
3424 "\nThe total amount received by address \"myaddress\"\n"
3425 + HelpExampleCli("z_getbalance", "\"myaddress\"") +
3426 "\nThe total amount received by address \"myaddress\" at least 5 blocks confirmed\n"
3427 + HelpExampleCli("z_getbalance", "\"myaddress\" 5") +
3428 "\nAs a json rpc call\n"
3429 + HelpExampleRpc("z_getbalance", "\"myaddress\", 5")
3432 LOCK2(cs_main, pwalletMain->cs_wallet);
3435 if (params.size() > 1) {
3436 nMinDepth = params[1].get_int();
3438 if (nMinDepth < 0) {
3439 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3442 // Check that the from address is valid.
3443 auto fromaddress = params[0].get_str();
3444 bool fromTaddr = false;
3445 CBitcoinAddress taddr(fromaddress);
3446 fromTaddr = taddr.IsValid();
3447 libzcash::PaymentAddress zaddr;
3449 CZCPaymentAddress address(fromaddress);
3451 zaddr = address.Get();
3452 } catch (const std::runtime_error&) {
3453 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3455 if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) {
3456 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
3460 CAmount nBalance = 0;
3462 nBalance = getBalanceTaddr(fromaddress, nMinDepth, false);
3464 nBalance = getBalanceZaddr(fromaddress, nMinDepth, false);
3467 return ValueFromAmount(nBalance);
3471 UniValue z_gettotalbalance(const UniValue& params, bool fHelp)
3473 if (!EnsureWalletIsAvailable(fHelp))
3474 return NullUniValue;
3476 if (fHelp || params.size() > 2)
3477 throw runtime_error(
3478 "z_gettotalbalance ( minconf includeWatchonly )\n"
3479 "\nReturn the total value of funds stored in the node’s wallet.\n"
3480 "\nCAUTION: If the wallet contains watch-only zaddrs, the returned private balance may be larger than the actual balance,"
3481 "\nbecause spends cannot be detected with incoming viewing keys.\n"
3483 "1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
3484 "2. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress' and 'z_importviewingkey')\n"
3487 " \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
3488 " \"private\": xxxxx, (numeric) the total balance of private funds\n"
3489 " \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n"
3492 "\nThe total amount in the wallet\n"
3493 + HelpExampleCli("z_gettotalbalance", "") +
3494 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3495 + HelpExampleCli("z_gettotalbalance", "5") +
3496 "\nAs a json rpc call\n"
3497 + HelpExampleRpc("z_gettotalbalance", "5")
3500 LOCK2(cs_main, pwalletMain->cs_wallet);
3503 if (params.size() > 0) {
3504 nMinDepth = params[0].get_int();
3506 if (nMinDepth < 0) {
3507 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3510 bool fIncludeWatchonly = false;
3511 if (params.size() > 1) {
3512 fIncludeWatchonly = params[1].get_bool();
3515 // getbalance and "getbalance * 1 true" should return the same number
3516 // but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
3517 // pwalletMain->GetBalance() does not accept min depth parameter
3518 // so we use our own method to get balance of utxos.
3519 CAmount nBalance = getBalanceTaddr("", nMinDepth, !fIncludeWatchonly);
3520 CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth, !fIncludeWatchonly);
3521 uint64_t interest = komodo_interestsum();
3522 CAmount nTotalBalance = nBalance + nPrivateBalance;
3523 UniValue result(UniValue::VOBJ);
3524 result.push_back(Pair("transparent", FormatMoney(nBalance)));
3525 result.push_back(Pair("interest", FormatMoney(interest)));
3526 result.push_back(Pair("private", FormatMoney(nPrivateBalance)));
3527 result.push_back(Pair("total", FormatMoney(nTotalBalance)));
3531 UniValue z_getoperationresult(const UniValue& params, bool fHelp)
3533 if (!EnsureWalletIsAvailable(fHelp))
3534 return NullUniValue;
3536 if (fHelp || params.size() > 1)
3537 throw runtime_error(
3538 "z_getoperationresult ([\"operationid\", ... ]) \n"
3539 "\nRetrieve the result and status of an operation which has finished, and then remove the operation from memory."
3540 + HelpRequiringPassphrase() + "\n"
3542 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3544 "\" [object, ...]\" (array) A list of JSON objects\n"
3546 + HelpExampleCli("z_getoperationresult", "'[\"operationid\", ... ]'")
3547 + HelpExampleRpc("z_getoperationresult", "'[\"operationid\", ... ]'")
3550 // This call will remove finished operations
3551 return z_getoperationstatus_IMPL(params, true);
3554 UniValue z_getoperationstatus(const UniValue& params, bool fHelp)
3556 if (!EnsureWalletIsAvailable(fHelp))
3557 return NullUniValue;
3559 if (fHelp || params.size() > 1)
3560 throw runtime_error(
3561 "z_getoperationstatus ([\"operationid\", ... ]) \n"
3562 "\nGet operation status and any associated result or error data. The operation will remain in memory."
3563 + HelpRequiringPassphrase() + "\n"
3565 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3567 "\" [object, ...]\" (array) A list of JSON objects\n"
3569 + HelpExampleCli("z_getoperationstatus", "'[\"operationid\", ... ]'")
3570 + HelpExampleRpc("z_getoperationstatus", "'[\"operationid\", ... ]'")
3573 // This call is idempotent so we don't want to remove finished operations
3574 return z_getoperationstatus_IMPL(params, false);
3577 UniValue z_getoperationstatus_IMPL(const UniValue& params, bool fRemoveFinishedOperations=false)
3579 LOCK2(cs_main, pwalletMain->cs_wallet);
3581 std::set<AsyncRPCOperationId> filter;
3582 if (params.size()==1) {
3583 UniValue ids = params[0].get_array();
3584 for (const UniValue & v : ids.getValues()) {
3585 filter.insert(v.get_str());
3588 bool useFilter = (filter.size()>0);
3590 UniValue ret(UniValue::VARR);
3591 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3592 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3594 for (auto id : ids) {
3595 if (useFilter && !filter.count(id))
3598 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3601 // It's possible that the operation was removed from the internal queue and map during this loop
3602 // throw JSONRPCError(RPC_INVALID_PARAMETER, "No operation exists for that id.");
3605 UniValue obj = operation->getStatus();
3606 std::string s = obj["status"].get_str();
3607 if (fRemoveFinishedOperations) {
3608 // Caller is only interested in retrieving finished results
3609 if ("success"==s || "failed"==s || "cancelled"==s) {
3611 q->popOperationForId(id);
3618 std::vector<UniValue> arrTmp = ret.getValues();
3620 // sort results chronologically by creation_time
3621 std::sort(arrTmp.begin(), arrTmp.end(), [](UniValue a, UniValue b) -> bool {
3622 const int64_t t1 = find_value(a.get_obj(), "creation_time").get_int64();
3623 const int64_t t2 = find_value(b.get_obj(), "creation_time").get_int64();
3629 ret.push_backV(arrTmp);
3635 // Here we define the maximum number of zaddr outputs that can be included in a transaction.
3636 // If input notes are small, we might actually require more than one joinsplit per zaddr output.
3637 // For now though, we assume we use one joinsplit per zaddr output (and the second output note is change).
3638 // We reduce the result by 1 to ensure there is room for non-joinsplit CTransaction data.
3639 #define Z_SENDMANY_MAX_ZADDR_OUTPUTS ((MAX_TX_SIZE / JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)) - 1)
3641 // transaction.h comment: spending taddr output requires CTxIn >= 148 bytes and typical taddr txout is 34 bytes
3642 #define CTXIN_SPEND_DUST_SIZE 148
3643 #define CTXOUT_REGULAR_SIZE 34
3645 UniValue z_sendmany(const UniValue& params, bool fHelp)
3647 if (!EnsureWalletIsAvailable(fHelp))
3648 return NullUniValue;
3650 if (fHelp || params.size() < 2 || params.size() > 4)
3651 throw runtime_error(
3652 "z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee )\n"
3653 "\nSend multiple times. Amounts are double-precision floating point numbers."
3654 "\nChange from a taddr flows to a new taddr address, while change from zaddr returns to itself."
3655 "\nWhen sending coinbase UTXOs to a zaddr, change is not allowed. The entire value of the UTXO(s) must be consumed."
3656 + strprintf("\nCurrently, the maximum number of zaddr outputs is %d due to transaction size limits.\n", Z_SENDMANY_MAX_ZADDR_OUTPUTS)
3657 + HelpRequiringPassphrase() + "\n"
3659 "1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from.\n"
3660 "2. \"amounts\" (array, required) An array of json objects representing the amounts to send.\n"
3662 " \"address\":address (string, required) The address is a taddr or zaddr\n"
3663 " \"amount\":amount (numeric, required) The numeric amount in KMD is the value\n"
3664 " \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
3666 "3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
3667 "4. fee (numeric, optional, default="
3668 + strprintf("%s", FormatMoney(ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
3670 "\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
3672 + HelpExampleCli("z_sendmany", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" '[{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]'")
3673 + HelpExampleRpc("z_sendmany", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", [{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]")
3676 LOCK2(cs_main, pwalletMain->cs_wallet);
3678 // Check that the from address is valid.
3679 auto fromaddress = params[0].get_str();
3680 bool fromTaddr = false;
3681 CBitcoinAddress taddr(fromaddress);
3682 fromTaddr = taddr.IsValid();
3683 libzcash::PaymentAddress zaddr;
3685 CZCPaymentAddress address(fromaddress);
3687 zaddr = address.Get();
3688 } catch (const std::runtime_error&) {
3690 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3694 // Check that we have the spending key
3696 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3697 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3701 UniValue outputs = params[1].get_array();
3703 if (outputs.size()==0)
3704 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
3706 // Keep track of addresses to spot duplicates
3707 set<std::string> setAddress;
3710 std::vector<SendManyRecipient> taddrRecipients;
3711 std::vector<SendManyRecipient> zaddrRecipients;
3712 CAmount nTotalOut = 0;
3714 for (const UniValue& o : outputs.getValues()) {
3716 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
3718 // sanity check, report error if unknown key-value pairs
3719 for (const string& name_ : o.getKeys()) {
3720 std::string s = name_;
3721 if (s != "address" && s != "amount" && s!="memo")
3722 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown key: ")+s);
3725 string address = find_value(o, "address").get_str();
3726 bool isZaddr = false;
3727 CBitcoinAddress taddr(address);
3728 if (!taddr.IsValid()) {
3730 CZCPaymentAddress zaddr(address);
3733 } catch (const std::runtime_error&) {
3734 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
3738 if (setAddress.count(address))
3739 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address);
3740 setAddress.insert(address);
3742 UniValue memoValue = find_value(o, "memo");
3744 if (!memoValue.isNull()) {
3745 memo = memoValue.get_str();
3747 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo cannot be used with a taddr. It can only be used with a zaddr.");
3748 } else if (!IsHex(memo)) {
3749 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
3751 if (memo.length() > ZC_MEMO_SIZE*2) {
3752 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
3756 UniValue av = find_value(o, "amount");
3757 CAmount nAmount = AmountFromValue( av );
3759 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
3762 zaddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3764 taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3767 nTotalOut += nAmount;
3770 // Check the number of zaddr outputs does not exceed the limit.
3771 if (zaddrRecipients.size() > Z_SENDMANY_MAX_ZADDR_OUTPUTS) {
3772 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, too many zaddr outputs");
3775 // As a sanity check, estimate and verify that the size of the transaction will be valid.
3776 // Depending on the input notes, the actual tx size may turn out to be larger and perhaps invalid.
3778 CMutableTransaction mtx;
3780 for (int i = 0; i < zaddrRecipients.size(); i++) {
3781 mtx.vjoinsplit.push_back(JSDescription());
3783 CTransaction tx(mtx);
3784 txsize += tx.GetSerializeSize(SER_NETWORK, tx.nVersion);
3786 txsize += CTXIN_SPEND_DUST_SIZE;
3787 txsize += CTXOUT_REGULAR_SIZE; // There will probably be taddr change
3789 txsize += CTXOUT_REGULAR_SIZE * taddrRecipients.size();
3790 if (txsize > MAX_TX_SIZE) {
3791 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Too many outputs, size of raw transaction would be larger than limit of %d bytes", MAX_TX_SIZE ));
3794 // Minimum confirmations
3796 if (params.size() > 2) {
3797 nMinDepth = params[2].get_int();
3799 if (nMinDepth < 0) {
3800 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3803 // Fee in Zatoshis, not currency format)
3804 CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE;
3805 if (params.size() > 3) {
3806 if (params[3].get_real() == 0.0) {
3809 nFee = AmountFromValue( params[3] );
3812 // Check that the user specified fee is sane.
3813 if (nFee > nTotalOut) {
3814 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the sum of outputs %s", FormatMoney(nFee), FormatMoney(nTotalOut)));
3818 // Use input parameters as the optional context info to be returned by z_getoperationstatus and z_getoperationresult.
3819 UniValue o(UniValue::VOBJ);
3820 o.push_back(Pair("fromaddress", params[0]));
3821 o.push_back(Pair("amounts", params[1]));
3822 o.push_back(Pair("minconf", nMinDepth));
3823 o.push_back(Pair("fee", std::stod(FormatMoney(nFee))));
3824 UniValue contextInfo = o;
3826 // Contextual transaction we will build on
3827 int nextBlockHeight = chainActive.Height() + 1;
3828 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextBlockHeight);
3829 bool isShielded = !fromTaddr || zaddrRecipients.size() > 0;
3830 if (contextualTx.nVersion == 1 && isShielded) {
3831 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
3833 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
3834 contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta;
3837 // Create operation and add to global queue
3838 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3839 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(contextualTx, fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee, contextInfo) );
3840 q->addOperation(operation);
3841 AsyncRPCOperationId operationId = operation->getId();
3847 When estimating the number of coinbase utxos we can shield in a single transaction:
3848 1. Joinsplit description is 1802 bytes.
3849 2. Transaction overhead ~ 100 bytes
3850 3. Spending a typical P2PKH is >=148 bytes, as defined in CTXIN_SPEND_DUST_SIZE.
3851 4. Spending a multi-sig P2SH address can vary greatly:
3852 https://github.com/bitcoin/bitcoin/blob/c3ad56f4e0b587d8d763af03d743fdfc2d180c9b/src/main.cpp#L517
3853 In real-world coinbase utxos, we consider a 3-of-3 multisig, where the size is roughly:
3854 (3*(33+1))+3 = 105 byte redeem script
3855 105 + 1 + 3*(73+1) = 328 bytes of scriptSig, rounded up to 400 based on testnet experiments.
3857 #define CTXIN_SPEND_P2SH_SIZE 400
3859 #define SHIELD_COINBASE_DEFAULT_LIMIT 50
3861 UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
3863 if (!EnsureWalletIsAvailable(fHelp))
3864 return NullUniValue;
3866 if (fHelp || params.size() < 2 || params.size() > 4)
3867 throw runtime_error(
3868 "z_shieldcoinbase \"fromaddress\" \"tozaddress\" ( fee ) ( limit )\n"
3869 "\nShield transparent coinbase funds by sending to a shielded zaddr. This is an asynchronous operation and utxos"
3870 "\nselected for shielding will be locked. If there is an error, they are unlocked. The RPC call `listlockunspent`"
3871 "\ncan be used to return a list of locked utxos. The number of coinbase utxos selected for shielding can be limited"
3872 "\nby the caller. If the limit parameter is set to zero, the -mempooltxinputlimit option will determine the number"
3873 "\nof uxtos. Any limit is constrained by the consensus rule defining a maximum transaction size of "
3874 + strprintf("%d bytes.", MAX_TX_SIZE)
3875 + HelpRequiringPassphrase() + "\n"
3877 "1. \"fromaddress\" (string, required) The address is a taddr or \"*\" for all taddrs belonging to the wallet.\n"
3878 "2. \"toaddress\" (string, required) The address is a zaddr.\n"
3879 "3. fee (numeric, optional, default="
3880 + strprintf("%s", FormatMoney(SHIELD_COINBASE_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
3881 "4. limit (numeric, optional, default="
3882 + strprintf("%d", SHIELD_COINBASE_DEFAULT_LIMIT) + ") Limit on the maximum number of utxos to shield. Set to 0 to use node option -mempooltxinputlimit.\n"
3885 " \"remainingUTXOs\": xxx (numeric) Number of coinbase utxos still available for shielding.\n"
3886 " \"remainingValue\": xxx (numeric) Value of coinbase utxos still available for shielding.\n"
3887 " \"shieldingUTXOs\": xxx (numeric) Number of coinbase utxos being shielded.\n"
3888 " \"shieldingValue\": xxx (numeric) Value of coinbase utxos being shielded.\n"
3889 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
3892 + HelpExampleCli("z_shieldcoinbase", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3893 + HelpExampleRpc("z_shieldcoinbase", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3896 LOCK2(cs_main, pwalletMain->cs_wallet);
3898 // Validate the from address
3899 auto fromaddress = params[0].get_str();
3900 bool isFromWildcard = fromaddress == "*";
3901 CBitcoinAddress taddr;
3902 if (!isFromWildcard) {
3903 taddr = CBitcoinAddress(fromaddress);
3904 if (!taddr.IsValid()) {
3905 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or \"*\".");
3909 // Validate the destination address
3910 auto destaddress = params[1].get_str();
3912 CZCPaymentAddress pa(destaddress);
3913 libzcash::PaymentAddress zaddr = pa.Get();
3914 } catch (const std::runtime_error&) {
3915 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
3918 // Convert fee from currency format to zatoshis
3919 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
3920 if (params.size() > 2) {
3921 if (params[2].get_real() == 0.0) {
3924 nFee = AmountFromValue( params[2] );
3928 int nLimit = SHIELD_COINBASE_DEFAULT_LIMIT;
3929 if (params.size() > 3) {
3930 nLimit = params[3].get_int();
3932 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of utxos cannot be negative");
3936 // Prepare to get coinbase utxos
3937 std::vector<ShieldCoinbaseUTXO> inputs;
3938 CAmount shieldedValue = 0;
3939 CAmount remainingValue = 0;
3940 size_t estimatedTxSize = 2000; // 1802 joinsplit description + tx overhead + wiggle room
3941 size_t utxoCounter = 0;
3942 bool maxedOutFlag = false;
3943 size_t mempoolLimit = (nLimit != 0) ? nLimit : (size_t)GetArg("-mempooltxinputlimit", 0);
3945 // Set of addresses to filter utxos by
3946 set<CBitcoinAddress> setAddress = {};
3947 if (!isFromWildcard) {
3948 setAddress.insert(taddr);
3951 // Get available utxos
3952 vector<COutput> vecOutputs;
3953 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true);
3955 // Find unspent coinbase utxos and update estimated size
3956 BOOST_FOREACH(const COutput& out, vecOutputs) {
3957 if (!out.fSpendable) {
3961 CTxDestination address;
3962 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3965 // If taddr is not wildcard "*", filter utxos
3966 if (setAddress.size()>0 && !setAddress.count(address)) {
3970 if (!out.tx->IsCoinBase()) {
3975 CAmount nValue = out.tx->vout[out.i].nValue;
3977 if (!maxedOutFlag) {
3978 CBitcoinAddress ba(address);
3979 size_t increase = (ba.IsScript()) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
3980 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
3981 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
3983 maxedOutFlag = true;
3985 estimatedTxSize += increase;
3986 ShieldCoinbaseUTXO utxo = {out.tx->GetHash(), out.i, nValue};
3987 inputs.push_back(utxo);
3988 shieldedValue += nValue;
3993 remainingValue += nValue;
3997 size_t numUtxos = inputs.size();
3999 if (numUtxos == 0) {
4000 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any coinbase funds to shield.");
4003 if (shieldedValue < nFee) {
4004 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
4005 strprintf("Insufficient coinbase funds, have %s, which is less than miners fee %s",
4006 FormatMoney(shieldedValue), FormatMoney(nFee)));
4009 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
4010 CAmount netAmount = shieldedValue - nFee;
4011 if (nFee > netAmount) {
4012 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
4015 // Keep record of parameters in context object
4016 UniValue contextInfo(UniValue::VOBJ);
4017 contextInfo.push_back(Pair("fromaddress", params[0]));
4018 contextInfo.push_back(Pair("toaddress", params[1]));
4019 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
4021 // Contextual transaction we will build on
4022 int nextBlockHeight = chainActive.Height() + 1;
4023 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
4024 Params().GetConsensus(), nextBlockHeight);
4025 if (contextualTx.nVersion == 1) {
4026 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
4028 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
4029 contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta;
4032 // Create operation and add to global queue
4033 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4034 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(contextualTx, inputs, destaddress, nFee, contextInfo) );
4035 q->addOperation(operation);
4036 AsyncRPCOperationId operationId = operation->getId();
4038 // Return continuation information
4039 UniValue o(UniValue::VOBJ);
4040 o.push_back(Pair("remainingUTXOs", utxoCounter - numUtxos));
4041 o.push_back(Pair("remainingValue", ValueFromAmount(remainingValue)));
4042 o.push_back(Pair("shieldingUTXOs", numUtxos));
4043 o.push_back(Pair("shieldingValue", ValueFromAmount(shieldedValue)));
4044 o.push_back(Pair("opid", operationId));
4049 #define MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT 50
4050 #define MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT 10
4052 #define JOINSPLIT_SIZE JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)
4054 UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
4056 if (!EnsureWalletIsAvailable(fHelp))
4057 return NullUniValue;
4059 auto fEnableMergeToAddress = fExperimentalMode && GetBoolArg("-zmergetoaddress", false);
4060 std::string strDisabledMsg = "";
4061 if (!fEnableMergeToAddress) {
4062 strDisabledMsg = "\nWARNING: z_mergetoaddress is DISABLED but can be enabled as an experimental feature.\n";
4065 if (fHelp || params.size() < 2 || params.size() > 6)
4066 throw runtime_error(
4067 "z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n"
4069 "\nMerge multiple UTXOs and notes into a single UTXO or note. Coinbase UTXOs are ignored; use `z_shieldcoinbase`"
4070 "\nto combine those into a single note."
4071 "\n\nThis is an asynchronous operation, and UTXOs selected for merging will be locked. If there is an error, they"
4072 "\nare unlocked. The RPC call `listlockunspent` can be used to return a list of locked UTXOs."
4073 "\n\nThe number of UTXOs and notes selected for merging can be limited by the caller. If the transparent limit"
4074 "\nparameter is set to zero, the -mempooltxinputlimit option will determine the number of UTXOs. Any limit is"
4075 "\nconstrained by the consensus rule defining a maximum transaction size of "
4076 + strprintf("%d bytes.", MAX_TX_SIZE)
4077 + HelpRequiringPassphrase() + "\n"
4079 "1. fromaddresses (string, required) A JSON array with addresses.\n"
4080 " The following special strings are accepted inside the array:\n"
4081 " - \"*\": Merge both UTXOs and notes from all addresses belonging to the wallet.\n"
4082 " - \"ANY_TADDR\": Merge UTXOs from all t-addrs belonging to the wallet.\n"
4083 " - \"ANY_ZADDR\": Merge notes from all z-addrs belonging to the wallet.\n"
4084 " If a special string is given, any given addresses of that type will be ignored.\n"
4086 " \"address\" (string) Can be a t-addr or a z-addr\n"
4089 "2. \"toaddress\" (string, required) The t-addr or z-addr to send the funds to.\n"
4090 "3. fee (numeric, optional, default="
4091 + strprintf("%s", FormatMoney(MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
4092 "4. transparent_limit (numeric, optional, default="
4093 + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT) + ") Limit on the maximum number of UTXOs to merge. Set to 0 to use node option -mempooltxinputlimit.\n"
4094 "4. shielded_limit (numeric, optional, default="
4095 + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT) + ") Limit on the maximum number of notes to merge. Set to 0 to merge as many as will fit in the transaction.\n"
4096 "5. \"memo\" (string, optional) Encoded as hex. When toaddress is a z-addr, this will be stored in the memo field of the new note.\n"
4099 " \"remainingUTXOs\": xxx (numeric) Number of UTXOs still available for merging.\n"
4100 " \"remainingTransparentValue\": xxx (numeric) Value of UTXOs still available for merging.\n"
4101 " \"remainingNotes\": xxx (numeric) Number of notes still available for merging.\n"
4102 " \"remainingShieldedValue\": xxx (numeric) Value of notes still available for merging.\n"
4103 " \"mergingUTXOs\": xxx (numeric) Number of UTXOs being merged.\n"
4104 " \"mergingTransparentValue\": xxx (numeric) Value of UTXOs being merged.\n"
4105 " \"mergingNotes\": xxx (numeric) Number of notes being merged.\n"
4106 " \"mergingShieldedValue\": xxx (numeric) Value of notes being merged.\n"
4107 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
4110 + HelpExampleCli("z_mergetoaddress", "'[\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"]' ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf")
4111 + HelpExampleRpc("z_mergetoaddress", "[\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"], \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
4114 if (!fEnableMergeToAddress) {
4115 throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_mergetoaddress is disabled.");
4118 LOCK2(cs_main, pwalletMain->cs_wallet);
4120 bool useAny = false;
4121 bool useAnyUTXO = false;
4122 bool useAnyNote = false;
4123 std::set<CBitcoinAddress> taddrs = {};
4124 std::set<libzcash::PaymentAddress> zaddrs = {};
4126 UniValue addresses = params[0].get_array();
4127 if (addresses.size()==0)
4128 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, fromaddresses array is empty.");
4130 // Keep track of addresses to spot duplicates
4131 std::set<std::string> setAddress;
4134 for (const UniValue& o : addresses.getValues()) {
4136 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
4138 std::string address = o.get_str();
4139 if (address == "*") {
4141 } else if (address == "ANY_TADDR") {
4143 } else if (address == "ANY_ZADDR") {
4146 CBitcoinAddress taddr(address);
4147 if (taddr.IsValid()) {
4148 // Ignore any listed t-addrs if we are using all of them
4149 if (!(useAny || useAnyUTXO)) {
4150 taddrs.insert(taddr);
4154 CZCPaymentAddress zaddr(address);
4155 // Ignore listed z-addrs if we are using all of them
4156 if (!(useAny || useAnyNote)) {
4157 zaddrs.insert(zaddr.Get());
4159 } catch (const std::runtime_error&) {
4161 RPC_INVALID_PARAMETER,
4162 string("Invalid parameter, unknown address format: ") + address);
4167 if (setAddress.count(address))
4168 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + address);
4169 setAddress.insert(address);
4172 // Validate the destination address
4173 auto destaddress = params[1].get_str();
4174 bool isToZaddr = false;
4175 CBitcoinAddress taddr(destaddress);
4176 if (!taddr.IsValid()) {
4178 CZCPaymentAddress zaddr(destaddress);
4181 } catch (const std::runtime_error&) {
4182 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
4186 // Convert fee from currency format to zatoshis
4187 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
4188 if (params.size() > 2) {
4189 if (params[2].get_real() == 0.0) {
4192 nFee = AmountFromValue( params[2] );
4196 int nUTXOLimit = MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT;
4197 if (params.size() > 3) {
4198 nUTXOLimit = params[3].get_int();
4199 if (nUTXOLimit < 0) {
4200 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of UTXOs cannot be negative");
4204 int nNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT;
4205 if (params.size() > 4) {
4206 nNoteLimit = params[4].get_int();
4207 if (nNoteLimit < 0) {
4208 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of notes cannot be negative");
4213 if (params.size() > 5) {
4214 memo = params[5].get_str();
4216 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
4217 } else if (!IsHex(memo)) {
4218 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
4220 if (memo.length() > ZC_MEMO_SIZE*2) {
4221 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
4225 MergeToAddressRecipient recipient(destaddress, memo);
4227 // Prepare to get UTXOs and notes
4228 std::vector<MergeToAddressInputUTXO> utxoInputs;
4229 std::vector<MergeToAddressInputNote> noteInputs;
4230 CAmount mergedUTXOValue = 0;
4231 CAmount mergedNoteValue = 0;
4232 CAmount remainingUTXOValue = 0;
4233 CAmount remainingNoteValue = 0;
4234 size_t utxoCounter = 0;
4235 size_t noteCounter = 0;
4236 bool maxedOutUTXOsFlag = false;
4237 bool maxedOutNotesFlag = false;
4238 size_t mempoolLimit = (nUTXOLimit != 0) ? nUTXOLimit : (size_t)GetArg("-mempooltxinputlimit", 0);
4240 size_t estimatedTxSize = 200; // tx overhead + wiggle room
4242 estimatedTxSize += JOINSPLIT_SIZE;
4245 if (useAny || useAnyUTXO || taddrs.size() > 0) {
4246 // Get available utxos
4247 vector<COutput> vecOutputs;
4248 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, false);
4250 // Find unspent utxos and update estimated size
4251 for (const COutput& out : vecOutputs) {
4252 if (!out.fSpendable) {
4256 CTxDestination address;
4257 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
4260 // If taddr is not wildcard "*", filter utxos
4261 if (taddrs.size() > 0 && !taddrs.count(address)) {
4266 CAmount nValue = out.tx->vout[out.i].nValue;
4268 if (!maxedOutUTXOsFlag) {
4269 CBitcoinAddress ba(address);
4270 size_t increase = (ba.IsScript()) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
4271 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
4272 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
4274 maxedOutUTXOsFlag = true;
4276 estimatedTxSize += increase;
4277 COutPoint utxo(out.tx->GetHash(), out.i);
4278 utxoInputs.emplace_back(utxo, nValue);
4279 mergedUTXOValue += nValue;
4283 if (maxedOutUTXOsFlag) {
4284 remainingUTXOValue += nValue;
4289 if (useAny || useAnyNote || zaddrs.size() > 0) {
4290 // Get available notes
4291 std::vector<CNotePlaintextEntry> entries;
4292 pwalletMain->GetFilteredNotes(entries, zaddrs);
4294 // Find unspent notes and update estimated size
4295 for (CNotePlaintextEntry& entry : entries) {
4297 CAmount nValue = entry.plaintext.value;
4299 if (!maxedOutNotesFlag) {
4300 // If we haven't added any notes yet and the merge is to a
4301 // z-address, we have already accounted for the first JoinSplit.
4302 size_t increase = (noteInputs.empty() && !isToZaddr) || (noteInputs.size() % 2 == 0) ? JOINSPLIT_SIZE : 0;
4303 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
4304 (nNoteLimit > 0 && noteCounter > nNoteLimit))
4306 maxedOutNotesFlag = true;
4308 estimatedTxSize += increase;
4310 pwalletMain->GetSpendingKey(entry.address, zkey);
4311 noteInputs.emplace_back(entry.jsop, entry.plaintext.note(entry.address), nValue, zkey);
4312 mergedNoteValue += nValue;
4316 if (maxedOutNotesFlag) {
4317 remainingNoteValue += nValue;
4322 size_t numUtxos = utxoInputs.size();
4323 size_t numNotes = noteInputs.size();
4325 if (numUtxos == 0 && numNotes == 0) {
4326 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any funds to merge.");
4329 // Sanity check: Don't do anything if:
4330 // - We only have one from address
4331 // - It's equal to toaddress
4332 // - The address only contains a single UTXO or note
4333 if (setAddress.size() == 1 && setAddress.count(destaddress) && (numUtxos + numNotes) == 1) {
4334 throw JSONRPCError(RPC_INVALID_PARAMETER, "Destination address is also the only source address, and all its funds are already merged.");
4337 CAmount mergedValue = mergedUTXOValue + mergedNoteValue;
4338 if (mergedValue < nFee) {
4339 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
4340 strprintf("Insufficient funds, have %s, which is less than miners fee %s",
4341 FormatMoney(mergedValue), FormatMoney(nFee)));
4344 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
4345 CAmount netAmount = mergedValue - nFee;
4346 if (nFee > netAmount) {
4347 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
4350 // Keep record of parameters in context object
4351 UniValue contextInfo(UniValue::VOBJ);
4352 contextInfo.push_back(Pair("fromaddresses", params[0]));
4353 contextInfo.push_back(Pair("toaddress", params[1]));
4354 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
4356 // Contextual transaction we will build on
4357 int nextBlockHeight = chainActive.Height() + 1;
4358 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
4359 Params().GetConsensus(),
4361 bool isShielded = numNotes > 0 || isToZaddr;
4362 if (contextualTx.nVersion == 1 && isShielded) {
4363 contextualTx.nVersion = 2; // Tx format should support vjoinsplit
4365 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
4366 contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta;
4369 // Create operation and add to global queue
4370 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4371 std::shared_ptr<AsyncRPCOperation> operation(
4372 new AsyncRPCOperation_mergetoaddress(contextualTx, utxoInputs, noteInputs, recipient, nFee, contextInfo) );
4373 q->addOperation(operation);
4374 AsyncRPCOperationId operationId = operation->getId();
4376 // Return continuation information
4377 UniValue o(UniValue::VOBJ);
4378 o.push_back(Pair("remainingUTXOs", utxoCounter - numUtxos));
4379 o.push_back(Pair("remainingTransparentValue", ValueFromAmount(remainingUTXOValue)));
4380 o.push_back(Pair("remainingNotes", noteCounter - numNotes));
4381 o.push_back(Pair("remainingShieldedValue", ValueFromAmount(remainingNoteValue)));
4382 o.push_back(Pair("mergingUTXOs", numUtxos));
4383 o.push_back(Pair("mergingTransparentValue", ValueFromAmount(mergedUTXOValue)));
4384 o.push_back(Pair("mergingNotes", numNotes));
4385 o.push_back(Pair("mergingShieldedValue", ValueFromAmount(mergedNoteValue)));
4386 o.push_back(Pair("opid", operationId));
4391 UniValue z_listoperationids(const UniValue& params, bool fHelp)
4393 if (!EnsureWalletIsAvailable(fHelp))
4394 return NullUniValue;
4396 if (fHelp || params.size() > 1)
4397 throw runtime_error(
4398 "z_listoperationids\n"
4399 "\nReturns the list of operation ids currently known to the wallet.\n"
4401 "1. \"status\" (string, optional) Filter result by the operation's state e.g. \"success\".\n"
4403 "[ (json array of string)\n"
4404 " \"operationid\" (string) an operation id belonging to the wallet\n"
4408 + HelpExampleCli("z_listoperationids", "")
4409 + HelpExampleRpc("z_listoperationids", "")
4412 LOCK2(cs_main, pwalletMain->cs_wallet);
4415 bool useFilter = false;
4416 if (params.size()==1) {
4417 filter = params[0].get_str();
4421 UniValue ret(UniValue::VARR);
4422 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4423 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
4424 for (auto id : ids) {
4425 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
4429 std::string state = operation->getStateAsString();
4430 if (useFilter && filter.compare(state)!=0)
4439 #include "script/sign.h"
4440 int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
4441 extern std::string NOTARY_PUBKEY;
4442 uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime);
4444 int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig)
4446 set<CBitcoinAddress> setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector<COutput> vecOutputs; uint32_t eligible,earliest = 0; CScript best_scriptPubKey; arith_uint256 bnTarget; bool fNegative,fOverflow;
4447 bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
4448 assert(pwalletMain != NULL);
4449 LOCK2(cs_main, pwalletMain->cs_wallet);
4451 memset(utxotxidp,0,sizeof(*utxotxidp));
4452 memset(utxovoutp,0,sizeof(*utxovoutp));
4453 memset(utxosig,0,72);
4454 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
4455 BOOST_FOREACH(const COutput& out, vecOutputs)
4457 if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth )
4459 if ( setAddress.size() )
4461 CTxDestination address;
4462 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
4464 if (!setAddress.count(address))
4467 CAmount nValue = out.tx->vout[out.i].nValue;
4468 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
4469 //entry.push_back(Pair("generated", out.tx->IsCoinBase()));
4470 CTxDestination address;
4471 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
4473 //entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
4474 //if (pwalletMain->mapAddressBook.count(address))
4475 // entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
4477 /*entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
4478 if (pk.IsPayToScriptHash())
4480 CTxDestination address;
4481 if (ExtractDestination(pk, address)) {
4482 const CScriptID& hash = boost::get<CScriptID>(address);
4483 CScript redeemScript;
4484 if (pwalletMain->GetCScript(hash, redeemScript))
4485 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
4488 entry.push_back(Pair("amount",ValueFromAmount(nValue)));*/
4489 BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
4490 CBlockIndex *tipindex;
4491 uint64_t interest; uint32_t locktime; int32_t txheight;
4492 if ( (tipindex= chainActive.Tip()) != 0 )
4494 eligible = komodo_stake(bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime);
4497 if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || nValue < *utxovaluep)) )
4499 earliest = eligible;
4500 best_scriptPubKey = out.tx->vout[out.i].scriptPubKey;
4501 *utxovaluep = (uint64_t)nValue;
4502 decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str());
4504 *txtimep = (uint32_t)out.tx->nLockTime;
4507 //fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight);
4510 if ( earliest != 0 )
4512 bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid;
4513 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
4514 const CKeyStore& keystore = *pwalletMain;
4515 txNew.vin.resize(1);
4516 txNew.vout.resize(1);
4518 for (i=0; i<32; i++)
4519 ((uint8_t *)&revtxid)[i] = ((uint8_t *)utxotxidp)[31 - i];
4520 txNew.vin[0].prevout.hash = revtxid;
4521 txNew.vin[0].prevout.n = *utxovoutp;
4522 txNew.vout[0].scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG;
4523 txNew.vout[0].nValue = *utxovaluep - txfee;
4524 txNew.nLockTime = *blocktimep;
4525 CTransaction txNewConst(txNew);
4526 signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, *utxovaluep, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId);
4528 fprintf(stderr,"failed to create signature\n");
4531 UpdateTransaction(txNew,0,sigdata);
4532 ptr = (uint8_t *)sigdata.scriptSig.data();
4533 siglen = sigdata.scriptSig.size();
4534 for (i=0; i<siglen; i++)
4535 utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]);
4536 //fprintf(stderr," siglen.%d\n",siglen);
4537 fprintf(stderr,"best %u from %u, gap %d\n",eligible,*blocktimep,(int32_t)(eligible - *blocktimep));
4538 *blocktimep = eligible;