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 https://www.opensource.org/licenses/mit-license.php .
7 #include "consensus/upgrades.h"
12 #include "pbaas/pbaas.h"
15 #include "rpc/server.h"
17 #include "transaction_builder.h"
19 #include "utilmoneystr.h"
22 #include "primitives/transaction.h"
23 #include "zcbenchmarks.h"
24 #include "script/interpreter.h"
25 #include "zcash/zip32.h"
28 #include "asyncrpcoperation.h"
29 #include "asyncrpcqueue.h"
30 #include "wallet/asyncrpcoperation_mergetoaddress.h"
31 #include "wallet/asyncrpcoperation_saplingmigration.h"
32 #include "wallet/asyncrpcoperation_sendmany.h"
33 #include "wallet/asyncrpcoperation_shieldcoinbase.h"
35 #include "consensus/upgrades.h"
40 #include <boost/assign/list_of.hpp>
47 using namespace libzcash;
49 extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
50 extern int32_t VERUS_MIN_STAKEAGE;
51 const std::string ADDR_TYPE_SPROUT = "sprout";
52 const std::string ADDR_TYPE_SAPLING = "sapling";
54 extern UniValue TxJoinSplitToJSON(const CTransaction& tx);
55 extern uint8_t ASSETCHAINS_PRIVATE;
56 uint32_t komodo_segid32(char *coinaddr);
58 int64_t nWalletUnlockTime;
59 static CCriticalSection cs_nWalletUnlockTime;
63 UniValue z_getoperationstatus_IMPL(const UniValue&, bool);
65 #define PLAN_NAME_MAX 8
66 #define VALID_PLAN_NAME(x) (strlen(x) <= PLAN_NAME_MAX)
68 std::string HelpRequiringPassphrase()
70 return pwalletMain && pwalletMain->IsCrypted()
71 ? "\nRequires wallet passphrase to be set with walletpassphrase call."
75 bool EnsureWalletIsAvailable(bool avoidException)
80 throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
87 void EnsureWalletIsUnlocked()
89 if (pwalletMain->IsLocked())
90 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
93 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);
95 void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
97 //int32_t i,n,txheight; uint32_t locktime; uint64_t interest = 0;
98 int confirms = wtx.GetDepthInMainChain();
99 entry.push_back(Pair("confirmations", confirms));
100 if (wtx.IsCoinBase())
101 entry.push_back(Pair("generated", true));
104 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
105 entry.push_back(Pair("blockindex", wtx.nIndex));
106 entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
107 entry.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight));
109 uint256 hash = wtx.GetHash();
110 entry.push_back(Pair("txid", hash.GetHex()));
111 UniValue conflicts(UniValue::VARR);
112 BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
113 conflicts.push_back(conflict.GetHex());
114 entry.push_back(Pair("walletconflicts", conflicts));
115 entry.push_back(Pair("time", wtx.GetTxTime()));
116 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
117 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
118 entry.push_back(Pair(item.first, item.second));
120 entry.push_back(Pair("vjoinsplit", TxJoinSplitToJSON(wtx)));
123 string AccountFromValue(const UniValue& value)
125 string strAccount = value.get_str();
126 //if (strAccount != "")
127 // throw JSONRPCError(RPC_WALLET_ACCOUNTS_UNSUPPORTED, "Accounts are unsupported");
131 char *komodo_chainname()
133 return(ASSETCHAINS_SYMBOL[0] == 0 ? (char *)"KMD" : ASSETCHAINS_SYMBOL);
136 UniValue getnewaddress(const UniValue& params, bool fHelp)
138 if (!EnsureWalletIsAvailable(fHelp))
141 if (fHelp || params.size() > 1)
143 "getnewaddress ( \"account\" )\n"
144 "\nReturns a new " + strprintf("%s",komodo_chainname()) + " address for receiving payments.\n"
146 "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"
148 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) The new " + strprintf("%s",komodo_chainname()) + " address\n"
150 + HelpExampleCli("getnewaddress", "")
151 + HelpExampleRpc("getnewaddress", "")
154 LOCK2(cs_main, pwalletMain->cs_wallet);
156 // Parse the account first so we don't generate a key if there's an error
158 if (params.size() > 0)
159 strAccount = AccountFromValue(params[0]);
161 if (!pwalletMain->IsLocked())
162 pwalletMain->TopUpKeyPool();
164 // Generate a new key that is added to wallet
166 if (!pwalletMain->GetKeyFromPool(newKey))
167 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
168 CKeyID keyID = newKey.GetID();
170 pwalletMain->SetAddressBook(keyID, strAccount, "receive");
172 return EncodeDestination(keyID);
176 CTxDestination GetAccountAddress(std::string strAccount, bool bForceNew=false)
178 CWalletDB walletdb(pwalletMain->strWalletFile);
181 walletdb.ReadAccount(strAccount, account);
183 bool bKeyUsed = false;
185 // Check if the current key has been used
186 if (account.vchPubKey.IsValid())
188 CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
189 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
190 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
193 const CWalletTx& wtx = (*it).second;
194 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
195 if (txout.scriptPubKey == scriptPubKey)
200 // Generate a new key
201 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
203 if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
204 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
206 pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
207 walletdb.WriteAccount(strAccount, account);
210 return account.vchPubKey.GetID();
213 UniValue getaccountaddress(const UniValue& params, bool fHelp)
215 if (!EnsureWalletIsAvailable(fHelp))
218 if (fHelp || params.size() != 1)
220 "getaccountaddress \"account\"\n"
221 "\nDEPRECATED. Returns the current " + strprintf("%s",komodo_chainname()) + " address for receiving payments to this account.\n"
223 "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"
225 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) The account " + strprintf("%s",komodo_chainname()) + " address\n"
227 + HelpExampleCli("getaccountaddress", "")
228 + HelpExampleCli("getaccountaddress", "\"\"")
229 + HelpExampleCli("getaccountaddress", "\"myaccount\"")
230 + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
233 LOCK2(cs_main, pwalletMain->cs_wallet);
235 // Parse the account first so we don't generate a key if there's an error
236 string strAccount = AccountFromValue(params[0]);
238 UniValue ret(UniValue::VSTR);
240 ret = EncodeDestination(GetAccountAddress(strAccount));
245 UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
247 if (!EnsureWalletIsAvailable(fHelp))
250 if (fHelp || params.size() > 1)
252 "getrawchangeaddress\n"
253 "\nReturns a new " + strprintf("%s",komodo_chainname()) + " address, for receiving change.\n"
254 "This is for use with raw transactions, NOT normal use.\n"
256 "\"address\" (string) The address\n"
258 + HelpExampleCli("getrawchangeaddress", "")
259 + HelpExampleRpc("getrawchangeaddress", "")
262 LOCK2(cs_main, pwalletMain->cs_wallet);
264 if (!pwalletMain->IsLocked())
265 pwalletMain->TopUpKeyPool();
267 CReserveKey reservekey(pwalletMain);
269 if (!reservekey.GetReservedKey(vchPubKey))
270 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
272 reservekey.KeepKey();
274 CKeyID keyID = vchPubKey.GetID();
276 return EncodeDestination(keyID);
280 UniValue setaccount(const UniValue& params, bool fHelp)
282 if (!EnsureWalletIsAvailable(fHelp))
285 if (fHelp || params.size() < 1 || params.size() > 2)
287 "setaccount \"" + strprintf("%s",komodo_chainname()) + "_address\" \"account\"\n"
288 "\nDEPRECATED. Sets the account associated with the given address.\n"
290 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to be associated with an account.\n"
291 "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"
293 + HelpExampleCli("setaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"tabby\"")
294 + HelpExampleRpc("setaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"tabby\"")
297 LOCK2(cs_main, pwalletMain->cs_wallet);
299 CTxDestination dest = DecodeDestination(params[0].get_str());
300 if (!IsValidDestination(dest)) {
301 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Verus address");
305 if (params.size() > 1)
306 strAccount = AccountFromValue(params[1]);
308 // Only add the account if the address is yours.
309 if (IsMine(*pwalletMain, dest)) {
310 // Detect when changing the account of an address that is the 'unused current key' of another account:
311 if (pwalletMain->mapAddressBook.count(dest)) {
312 std::string strOldAccount = pwalletMain->mapAddressBook[dest].name;
313 if (dest == GetAccountAddress(strOldAccount)) {
314 GetAccountAddress(strOldAccount, true);
317 pwalletMain->SetAddressBook(dest, strAccount, "receive");
320 throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
326 UniValue getaccount(const UniValue& params, bool fHelp)
328 if (!EnsureWalletIsAvailable(fHelp))
331 if (fHelp || params.size() != 1)
333 "getaccount \"" + strprintf("%s",komodo_chainname()) + "_address\"\n"
334 "\nDEPRECATED. Returns the account associated with the given address.\n"
336 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address for account lookup.\n"
338 "\"accountname\" (string) the account address\n"
340 + HelpExampleCli("getaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"")
341 + HelpExampleRpc("getaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"")
344 LOCK2(cs_main, pwalletMain->cs_wallet);
346 CTxDestination dest = DecodeDestination(params[0].get_str());
347 if (!IsValidDestination(dest)) {
348 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Verus address");
351 std::string strAccount;
352 std::map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(dest);
353 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty()) {
354 strAccount = (*mi).second.name;
360 UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
362 if (!EnsureWalletIsAvailable(fHelp))
365 if (fHelp || params.size() != 1)
367 "getaddressesbyaccount \"account\"\n"
368 "\nDEPRECATED. Returns the list of addresses for the given account.\n"
370 "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"
372 "[ (json array of string)\n"
373 " \"" + strprintf("%s",komodo_chainname()) + "_address\" (string) a " + strprintf("%s",komodo_chainname()) + " address associated with the given account\n"
377 + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
378 + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
381 LOCK2(cs_main, pwalletMain->cs_wallet);
383 string strAccount = AccountFromValue(params[0]);
385 // Find all addresses that have the given account
386 UniValue ret(UniValue::VARR);
387 for (const std::pair<CTxDestination, CAddressBookData>& item : pwalletMain->mapAddressBook) {
388 const CTxDestination& dest = item.first;
389 const std::string& strName = item.second.name;
390 if (strName == strAccount) {
391 ret.push_back(EncodeDestination(dest));
397 static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew,uint8_t *opretbuf,int32_t opretlen,long int opretValue)
399 CAmount curBalance = pwalletMain->GetBalance();
403 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
405 if (nValue > curBalance)
406 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
408 // Parse Zcash address
409 CScript scriptPubKey = GetScriptForDestination(address);
411 // Create and send the transaction
412 CReserveKey reservekey(pwalletMain);
413 CAmount nFeeRequired;
414 std::string strError;
415 vector<CRecipient> vecSend;
416 int nChangePosRet = -1;
417 CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
418 vecSend.push_back(recipient);
419 if ( opretlen > 0 && opretbuf != 0 )
421 CScript opretpubkey; int32_t i; uint8_t *ptr;
422 opretpubkey.resize(opretlen);
423 for (i=0; i<opretlen; i++)
425 opretpubkey[i] = opretbuf[i];
426 //printf("%02x",ptr[i]);
428 //printf(" opretbuf[%d]\n",opretlen);
429 CRecipient opret = { opretpubkey, opretValue, false };
430 vecSend.push_back(opret);
432 if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
433 if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
434 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));
435 throw JSONRPCError(RPC_WALLET_ERROR, strError);
437 if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
438 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.");
441 UniValue sendtoaddress(const UniValue& params, bool fHelp)
443 if (!EnsureWalletIsAvailable(fHelp))
446 if (fHelp || params.size() < 2 || params.size() > 5)
448 "sendtoaddress \"" + strprintf("%s",komodo_chainname()) + "_address\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
449 "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
450 + HelpRequiringPassphrase() +
452 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to send to.\n"
453 "2. \"amount\" (numeric, required) The amount in " + strprintf("%s",komodo_chainname()) + " to send. eg 0.1\n"
454 "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
455 " This is not part of the transaction, just kept in your wallet.\n"
456 "4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
457 " to which you're sending the transaction. This is not part of the \n"
458 " transaction, just kept in your wallet.\n"
459 "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
460 " The recipient will receive less " + strprintf("%s",komodo_chainname()) + " than you enter in the amount field.\n"
462 "\"transactionid\" (string) The transaction id.\n"
464 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.1")
465 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.1 \"donation\" \"seans outpost\"")
466 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.1 \"\" \"\" true")
467 + HelpExampleRpc("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", 0.1, \"donation\", \"seans outpost\"")
470 if ( ASSETCHAINS_PRIVATE != 0 && AmountFromValue(params[1]) > 0 )
471 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
473 LOCK2(cs_main, pwalletMain->cs_wallet);
475 CTxDestination dest = DecodeDestination(params[0].get_str());
476 if (!IsValidDestination(dest)) {
477 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Verus address");
481 CAmount nAmount = AmountFromValue(params[1]);
483 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
487 if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty())
488 wtx.mapValue["comment"] = params[2].get_str();
489 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
490 wtx.mapValue["to"] = params[3].get_str();
492 bool fSubtractFeeFromAmount = false;
493 if (params.size() > 4)
494 fSubtractFeeFromAmount = params[4].get_bool();
496 EnsureWalletIsUnlocked();
498 SendMoney(dest, nAmount, fSubtractFeeFromAmount, wtx,0,0,0);
500 return wtx.GetHash().GetHex();
503 #include "komodo_defs.h"
505 #define KOMODO_KVPROTECTED 1
506 #define KOMODO_KVBINARY 2
507 #define KOMODO_KVDURATION 1440
508 #define IGUANA_MAXSCRIPTSIZE 10001
509 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);
510 int32_t komodo_opreturnscript(uint8_t *script,uint8_t type,uint8_t *opret,int32_t opretlen);
511 #define CRYPTO777_KMDADDR "RXL3YXG2ceaB6C5hfJcN4fvmLH2C34knhA"
512 extern int32_t KOMODO_PAX;
513 extern uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE;
514 int32_t komodo_is_issuer();
515 int32_t iguana_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp);
516 int32_t komodo_isrealtime(int32_t *kmdheightp);
517 int32_t pax_fiatstatus(uint64_t *available,uint64_t *deposited,uint64_t *issued,uint64_t *withdrawn,uint64_t *approved,uint64_t *redeemed,char *base);
518 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);
519 int32_t komodo_kvcmp(uint8_t *refvalue,uint16_t refvaluesize,uint8_t *value,uint16_t valuesize);
520 uint64_t komodo_kvfee(uint32_t flags,int32_t opretlen,int32_t keylen);
521 uint256 komodo_kvsig(uint8_t *buf,int32_t len,uint256 privkey);
522 int32_t komodo_kvduration(uint32_t flags);
523 uint256 komodo_kvprivkey(uint256 *pubkeyp,char *passphrase);
524 int32_t komodo_kvsigverify(uint8_t *buf,int32_t len,uint256 _pubkey,uint256 sig);
526 UniValue kvupdate(const UniValue& params, bool fHelp)
528 static uint256 zeroes;
529 CWalletTx wtx; UniValue ret(UniValue::VOBJ);
530 uint8_t keyvalue[IGUANA_MAXSCRIPTSIZE*8],opretbuf[IGUANA_MAXSCRIPTSIZE*8]; 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;
531 if (fHelp || params.size() < 3 )
533 "kvupdate key \"value\" days passphrase\n"
534 "\nStore a key value. This feature is only available for asset chains.\n"
536 "1. key (string, required) key\n"
537 "2. \"value\" (string, required) value\n"
538 "3. days (numeric, required) amount of days(1440 blocks/day) before the key expires. Minimum 1 day\n"
539 "4. passphrase (string, optional) passphrase required to update this key\n"
542 " \"coin\": \"xxxxx\", (string) chain the key is stored on\n"
543 " \"height\": xxxxx, (numeric) height the key was stored at\n"
544 " \"expiration\": xxxxx, (numeric) height the key will expire\n"
545 " \"flags\": x, (string) amount of days the key will be stored \n"
546 " \"key\": \"xxxxx\", (numeric) stored key\n"
547 " \"keylen\": xxxxx, (numeric) length of the key\n"
548 " \"value\": \"xxxxx\" (numeric) stored value\n"
549 " \"valuesize\": xxxxx, (string) length of the stored value\n"
550 " \"fee\": xxxxx (string) transaction fee paid to store the key\n"
551 " \"txid\": \"xxxxx\" (string) transaction id\n"
554 + HelpExampleCli("kvupdate", "examplekey \"examplevalue\" 2 examplepassphrase")
555 + HelpExampleRpc("kvupdate", "examplekey \"examplevalue\" 2 examplepassphrase")
557 if (!EnsureWalletIsAvailable(fHelp))
559 if ( ASSETCHAINS_SYMBOL[0] == 0 )
562 memset(&sig,0,sizeof(sig));
563 memset(&privkey,0,sizeof(privkey));
564 memset(&refpubkey,0,sizeof(refpubkey));
565 memset(&pubkey,0,sizeof(pubkey));
566 if ( (n= (int32_t)params.size()) >= 3 )
568 flags = atoi(params[2].get_str().c_str());
569 //printf("flags.%d (%s) n.%d\n",flags,params[2].get_str().c_str(),n);
572 privkey = komodo_kvprivkey(&pubkey,(char *)(n >= 4 ? params[3].get_str().c_str() : "password"));
575 /*for (i=0; i<32; i++)
576 printf("%02x",((uint8_t *)&privkey)[i]);
579 printf("%02x",((uint8_t *)&pubkey)[i]);
580 printf(" pubkey, privkey derived from (%s)\n",(char *)params[3].get_str().c_str());
582 LOCK2(cs_main, pwalletMain->cs_wallet);
583 if ( (keylen= (int32_t)strlen(params[0].get_str().c_str())) > 0 )
585 key = (uint8_t *)params[0].get_str().c_str();
586 if ( n >= 2 && params[1].get_str().c_str() != 0 )
588 value = (uint8_t *)params[1].get_str().c_str();
589 valuesize = (int32_t)strlen(params[1].get_str().c_str());
591 memcpy(keyvalue,key,keylen);
592 if ( (refvaluesize= komodo_kvsearch(&refpubkey,chainActive.LastTip()->GetHeight(),&tmpflags,&height,&keyvalue[keylen],key,keylen)) >= 0 )
594 if ( (tmpflags & KOMODO_KVPROTECTED) != 0 )
596 if ( memcmp(&refpubkey,&pubkey,sizeof(refpubkey)) != 0 )
598 ret.push_back(Pair("error",(char *)"cant modify write once key without passphrase"));
602 if ( keylen+refvaluesize <= sizeof(keyvalue) )
604 sig = komodo_kvsig(keyvalue,keylen+refvaluesize,privkey);
605 if ( komodo_kvsigverify(keyvalue,keylen+refvaluesize,refpubkey,sig) < 0 )
607 ret.push_back(Pair("error",(char *)"error verifying sig, passphrase is probably wrong"));
608 printf("VERIFY ERROR\n");
610 } // else printf("verified immediately\n");
613 //for (i=0; i<32; i++)
614 // printf("%02x",((uint8_t *)&sig)[i]);
615 //printf(" sig for keylen.%d + valuesize.%d\n",keylen,refvaluesize);
616 ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)));
617 height = chainActive.LastTip()->GetHeight();
618 if ( memcmp(&zeroes,&refpubkey,sizeof(refpubkey)) != 0 )
619 ret.push_back(Pair("owner",refpubkey.GetHex()));
620 ret.push_back(Pair("height", (int64_t)height));
621 duration = komodo_kvduration(flags); //((flags >> 2) + 1) * KOMODO_KVDURATION;
622 ret.push_back(Pair("expiration", (int64_t)(height+duration)));
623 ret.push_back(Pair("flags",(int64_t)flags));
624 ret.push_back(Pair("key",params[0].get_str()));
625 ret.push_back(Pair("keylen",(int64_t)keylen));
626 if ( n >= 2 && params[1].get_str().c_str() != 0 )
628 ret.push_back(Pair("value",params[1].get_str()));
629 ret.push_back(Pair("valuesize",valuesize));
631 iguana_rwnum(1,&keyvalue[0],sizeof(keylen),&keylen);
632 iguana_rwnum(1,&keyvalue[2],sizeof(valuesize),&valuesize);
633 iguana_rwnum(1,&keyvalue[4],sizeof(height),&height);
634 iguana_rwnum(1,&keyvalue[8],sizeof(flags),&flags);
635 memcpy(&keyvalue[12],key,keylen);
637 memcpy(&keyvalue[12 + keylen],value,valuesize);
638 coresize = (int32_t)(sizeof(flags)+sizeof(height)+sizeof(uint16_t)*2+keylen+valuesize);
639 if ( haveprivkey != 0 )
642 keyvalue[12 + keylen + valuesize + i] = ((uint8_t *)&pubkey)[i];
644 if ( refvaluesize >=0 )
647 keyvalue[12 + keylen + valuesize + 32 + i] = ((uint8_t *)&sig)[i];
651 if ( (opretlen= komodo_opreturnscript(opretbuf,'K',keyvalue,coresize)) == 40 )
653 //for (i=0; i<opretlen; i++)
654 // printf("%02x",opretbuf[i]);
655 //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]);
656 EnsureWalletIsUnlocked();
657 fee = komodo_kvfee(flags,opretlen,keylen);
658 ret.push_back(Pair("fee",(double)fee/COIN));
659 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
660 if (!destaddress.IsValid())
661 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
662 SendMoney(destaddress.Get(),10000,false,wtx,opretbuf,opretlen,fee);
663 ret.push_back(Pair("txid",wtx.GetHash().GetHex()));
664 } else ret.push_back(Pair("error",(char *)"null key"));
668 UniValue paxdeposit(const UniValue& params, bool fHelp)
670 uint64_t available,deposited,issued,withdrawn,approved,redeemed,seed,komodoshis = 0; int32_t height; char destaddr[64]; uint8_t i,pubkey37[33];
671 bool fSubtractFeeFromAmount = false;
672 if ( KOMODO_PAX == 0 )
674 throw runtime_error("paxdeposit disabled without -pax");
676 if ( komodo_is_issuer() != 0 )
677 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "paxdeposit only from KMD");
678 if (!EnsureWalletIsAvailable(fHelp))
679 throw runtime_error("paxdeposit needs wallet"); //return Value::null;
680 if (fHelp || params.size() != 3)
681 throw runtime_error("paxdeposit address fiatoshis base");
682 LOCK2(cs_main, pwalletMain->cs_wallet);
683 CBitcoinAddress address(params[0].get_str());
684 if (!address.IsValid())
685 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
686 int64_t fiatoshis = atof(params[1].get_str().c_str()) * COIN;
687 std::string base = params[2].get_str();
689 height = chainActive.LastTip()->GetHeight();
690 if ( pax_fiatstatus(&available,&deposited,&issued,&withdrawn,&approved,&redeemed,(char *)base.c_str()) != 0 || available < fiatoshis )
692 fprintf(stderr,"available %llu vs fiatoshis %llu\n",(long long)available,(long long)fiatoshis);
693 throw runtime_error("paxdeposit not enough available inventory");
695 komodoshis = PAX_fiatdest(&seed,0,destaddr,pubkey37,(char *)params[0].get_str().c_str(),height,(char *)base.c_str(),fiatoshis);
696 dest.append(destaddr);
697 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
698 if (!destaddress.IsValid())
699 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
701 fprintf(stderr,"%02x",pubkey37[i]);
702 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);
703 EnsureWalletIsUnlocked();
705 uint8_t opretbuf[64]; int32_t opretlen; uint64_t fee = komodoshis / 1000;
708 iguana_rwnum(1,&pubkey37[33],sizeof(height),&height);
709 opretlen = komodo_opreturnscript(opretbuf,'D',pubkey37,37);
710 SendMoney(address.Get(),fee,fSubtractFeeFromAmount,wtx,opretbuf,opretlen,komodoshis);
711 return wtx.GetHash().GetHex();
714 UniValue paxwithdraw(const UniValue& params, bool fHelp)
716 CWalletTx wtx; std::string dest; int32_t kmdheight; uint64_t seed,komodoshis = 0; char destaddr[64]; uint8_t i,pubkey37[37]; bool fSubtractFeeFromAmount = false;
717 if ( ASSETCHAINS_SYMBOL[0] == 0 )
719 if (!EnsureWalletIsAvailable(fHelp))
721 throw runtime_error("paxwithdraw deprecated");
722 if (fHelp || params.size() != 2)
723 throw runtime_error("paxwithdraw address fiatamount");
724 if ( komodo_isrealtime(&kmdheight) == 0 )
726 LOCK2(cs_main, pwalletMain->cs_wallet);
727 CBitcoinAddress address(params[0].get_str());
728 if (!address.IsValid())
729 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
730 int64_t fiatoshis = atof(params[1].get_str().c_str()) * COIN;
731 komodoshis = PAX_fiatdest(&seed,1,destaddr,pubkey37,(char *)params[0].get_str().c_str(),kmdheight,ASSETCHAINS_SYMBOL,fiatoshis);
732 dest.append(destaddr);
733 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
734 if (!destaddress.IsValid())
735 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
737 printf("%02x",pubkey37[i]);
738 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);
739 EnsureWalletIsUnlocked();
740 uint8_t opretbuf[64]; int32_t opretlen; uint64_t fee = fiatoshis / 1000;
743 iguana_rwnum(1,&pubkey37[33],sizeof(kmdheight),&kmdheight);
744 opretlen = komodo_opreturnscript(opretbuf,'W',pubkey37,37);
745 SendMoney(destaddress.Get(),fee,fSubtractFeeFromAmount,wtx,opretbuf,opretlen,fiatoshis);
746 return wtx.GetHash().GetHex();
749 UniValue listaddressgroupings(const UniValue& params, bool fHelp)
751 if (!EnsureWalletIsAvailable(fHelp))
756 "listaddressgroupings\n"
757 "\nLists groups of addresses which have had their common ownership\n"
758 "made public by common use as inputs or as the resulting change\n"
759 "in past transactions\n"
764 " \"" + strprintf("%s",komodo_chainname()) + " address\", (string) The " + strprintf("%s",komodo_chainname()) + " address\n"
765 " amount, (numeric) The amount in " + strprintf("%s",komodo_chainname()) + "\n"
766 " \"account\" (string, optional) The account (DEPRECATED)\n"
773 + HelpExampleCli("listaddressgroupings", "")
774 + HelpExampleRpc("listaddressgroupings", "")
777 LOCK2(cs_main, pwalletMain->cs_wallet);
779 UniValue jsonGroupings(UniValue::VARR);
780 std::map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
781 for (const std::set<CTxDestination>& grouping : pwalletMain->GetAddressGroupings()) {
782 UniValue jsonGrouping(UniValue::VARR);
783 for (const CTxDestination& address : grouping)
785 UniValue addressInfo(UniValue::VARR);
786 addressInfo.push_back(EncodeDestination(address));
787 addressInfo.push_back(ValueFromAmount(balances[address]));
789 if (pwalletMain->mapAddressBook.find(address) != pwalletMain->mapAddressBook.end()) {
790 addressInfo.push_back(pwalletMain->mapAddressBook.find(address)->second.name);
793 jsonGrouping.push_back(addressInfo);
795 jsonGroupings.push_back(jsonGrouping);
797 return jsonGroupings;
800 std::string SignMessageHash(const CIdentity &identity, const uint256 &_msgHash, const std::string &signatureStr, uint32_t blockHeight)
804 CIdentitySignature signature;
805 bool fInvalid = false;
807 CHashWriterSHA256 ss(SER_GETHASH, PROTOCOL_VERSION);
809 ss << verusDataSignaturePrefix;
810 ss << ConnectedChains.ThisChain().GetID();
812 ss << identity.GetID();
815 uint256 msgHash = ss.GetHash();
817 // get the signature, a hex string, which is deserialized into an instance of the ID signature class
818 std::vector<unsigned char> sigVec;
821 sigVec = DecodeBase64(signatureStr.c_str(), &fInvalid);
829 signature = CIdentitySignature(sigVec);
832 catch(const std::exception& e)
834 std::cerr << e.what() << '\n';
836 signature = CIdentitySignature();
839 signature.blockHeight = blockHeight;
841 std::set<uint160> signatureKeyIDs;
842 std::map<uint160, std::vector<unsigned char>> signatureMap;
844 for (auto &oneSig : signature.signatures)
847 if (pubkey.RecoverCompact(msgHash, oneSig))
849 uint160 pkID = pubkey.GetID();
850 signatureKeyIDs.insert(pkID);
851 signatureMap[pkID] = oneSig;
855 std::set<CKeyID> keysToTry;
857 // remove all valid addresses and count
858 for (auto &oneAddr : identity.primaryAddresses)
860 if (!(oneAddr.which() == COptCCParams::ADDRTYPE_PK || oneAddr.which() == COptCCParams::ADDRTYPE_PKH))
865 uint160 addrID = GetDestinationID(oneAddr);
867 if (signatureKeyIDs.count(addrID))
870 signatureKeyIDs.erase(addrID);
871 if (!signatureKeyIDs.size())
878 keysToTry.insert(addrID);
882 // if there are obsolete signatures, remove them
883 for (auto &oneSigID : signatureKeyIDs)
885 signatureMap.erase(oneSigID);
888 int numSigsAdded = 0;
889 for (auto &oneKeyID : keysToTry)
892 if (pwalletMain->GetKey(oneKeyID, key)) {
893 vector<unsigned char> vchSig;
894 if (!key.SignCompact(msgHash, vchSig))
896 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Signing failed");
898 signatureMap[oneKeyID] = vchSig;
904 if (numSigs < identity.minSigs && !numSigsAdded)
906 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No private key available for additional signing");
909 // reset signatures from union of old and new in map
910 signature.signatures.clear();
911 for (auto &sigpair : signatureMap)
913 signature.signatures.insert(sigpair.second);
916 vector<unsigned char> vchSig = ::AsVector(signature);
918 // all signatures must be from valid keys, and if there are enough, it is valid
919 return EncodeBase64(&vchSig[0], vchSig.size());
922 UniValue signhash(const UniValue& params, bool fHelp)
924 if (!EnsureWalletIsAvailable(fHelp))
927 if (fHelp || params.size() < 2 || params.size() > 3)
929 "signhash \"address or identity\" \"hexhash\" \"curentsig\"\n"
930 "\nSign a hexadecimal hash value with the private key of a t-addr or the authorities present in this wallet for an identity"
931 + HelpRequiringPassphrase() + "\n"
932 "\nNOTE: This API will only work for signing a data hash, but cannot properly sign the hash of a transaction\n"
934 "1. \"t-addr or identity\" (string, required) The transparent address or identity to use for signing.\n"
935 "2. \"hexhash\" (string, required) The hexadecimal hash to create a signature of.\n"
936 "2. \"cursig\" (string) The current signature of the message encoded in base 64 if multisig ID\n"
938 "\"signature\" (string) The aggregate signature of the message encoded in base 64 if all or partial signing successful\n"
940 "\nUnlock the wallet for 30 seconds\n"
941 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
942 "\nCreate the signature\n"
943 + HelpExampleCli("signhash", "\"idname@\" \"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f\"") +
944 "\nVerify the signature\n"
945 + HelpExampleCli("verifyhash", "\"idname@\" \"signature\" \"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f\"") +
947 + HelpExampleRpc("signhash", "\"idname@\", \"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f\"")
950 LOCK2(cs_main, pwalletMain->cs_wallet);
952 EnsureWalletIsUnlocked();
954 string strAddress = params[0].get_str();
955 string strHash = params[1].get_str();
957 bool fInvalid = false;
960 CTxDestination destination = DecodeDestination(strAddress);
961 if (!IsValidDestination(destination)) {
962 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
967 throw JSONRPCError(RPC_INVALID_PARAMETER, "No hash to verify");
972 msgHash = uint256S(strHash.c_str());
974 catch(const std::exception& e)
976 throw JSONRPCError(RPC_INVALID_PARAMETER, "hexhash must be a valid, 32 byte hexadecimal hash value");
979 // we expect the hash passed in to be reversed for compatibility with hashing tools
981 std::reverse(msgHash.begin(), msgHash.end());
983 CTxDestination dest = DecodeDestination(strAddress);
984 if (!IsValidDestination(dest)) {
985 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address or identity");
988 if (dest.which() == COptCCParams::ADDRTYPE_ID)
990 std::string strSign = params.size() > 2 ? uni_get_str(params[2]) : "";
994 identity = CIdentity::LookupIdentity(GetDestinationID(dest));
995 if (identity.IsValidUnrevoked())
997 uint32_t blockHeight = (uint32_t)chainActive.Height();
999 UniValue ret(UniValue::VOBJ);
1000 std::string sig = SignMessageHash(identity, msgHash, strSign, blockHeight);
1001 std::reverse(msgHash.begin(), msgHash.end()); // return a reversed hash for compatibility with sha256sum
1002 ret.push_back(Pair("hash", msgHash.GetHex()));
1003 ret.push_back(Pair("signature", sig));
1006 else if (!identity.IsValid())
1008 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid identity");
1012 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Identity is revoked and cannot sign");
1017 const CKeyID *keyID = boost::get<CKeyID>(&dest);
1019 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
1023 if (!pwalletMain->GetKey(*keyID, key)) {
1024 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
1027 CHashWriterSHA256 ss(SER_GETHASH, PROTOCOL_VERSION);
1028 ss << verusDataSignaturePrefix;
1031 vector<unsigned char> vchSig;
1033 if (!key.SignCompact(ss.GetHash(), vchSig))
1034 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
1036 UniValue ret(UniValue::VOBJ);
1037 std::reverse(msgHash.begin(), msgHash.end()); // return a reversed hash for compatibility reasons
1038 ret.push_back(Pair("hash", msgHash.GetHex()));
1039 ret.push_back(Pair("signature", EncodeBase64(&vchSig[0], vchSig.size())));
1044 UniValue signmessage(const UniValue& params, bool fHelp)
1046 if (!EnsureWalletIsAvailable(fHelp))
1047 return NullUniValue;
1049 if (fHelp || params.size() < 2 || params.size() > 3)
1050 throw runtime_error(
1051 "signmessage \"address or identity\" \"message\" \"curentsig\"\n"
1052 "\nSign a message with the private key of a t-addr or the authorities present in this wallet for an identity"
1053 + HelpRequiringPassphrase() + "\n"
1055 "1. \"t-addr or identity\" (string, required) The transparent address or identity to use for signing.\n"
1056 "2. \"message\" (string, required) The message to create a signature of.\n"
1057 "2. \"cursig\" (string) The current signature of the message encoded in base 64 if multisig ID\n"
1060 " \"hash\":\"hexhash\" (string) The hash of the message (SHA256, NOT SHA256D)\n"
1061 " \"signature\":\"base64sig\" (string) The aggregate signature of the message encoded in base 64 if all or partial signing successful\n"
1064 "\nUnlock the wallet for 30 seconds\n"
1065 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
1066 "\nCreate the signature\n"
1067 + HelpExampleCli("signmessage", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"my message\"") +
1068 "\nVerify the signature\n"
1069 + HelpExampleCli("verifymessage", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"signature\" \"my message\"") +
1071 + HelpExampleRpc("signmessage", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"my message\"")
1074 LOCK2(cs_main, pwalletMain->cs_wallet);
1076 EnsureWalletIsUnlocked();
1078 string strAddress = params[0].get_str();
1079 string strMessage = params[1].get_str();
1081 CTxDestination dest = DecodeDestination(strAddress);
1082 if (!IsValidDestination(dest)) {
1083 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address or identity");
1086 if (dest.which() == COptCCParams::ADDRTYPE_ID)
1088 std::string strSign = params.size() > 2 ? uni_get_str(params[2]) : "";
1092 identity = CIdentity::LookupIdentity(GetDestinationID(dest));
1093 if (identity.IsValidUnrevoked())
1095 uint32_t blockHeight = (uint32_t)chainActive.Height();
1096 CHashWriterSHA256 ss(SER_GETHASH, PROTOCOL_VERSION);
1098 uint256 msgHash = ss.GetHash();
1099 std::string sig = SignMessageHash(identity, msgHash, strSign, blockHeight);
1101 UniValue ret(UniValue::VOBJ);
1102 std::reverse(msgHash.begin(), msgHash.end()); // return a reversed hash for compatibility with sha256sum
1103 ret.push_back(Pair("hash", msgHash.GetHex()));
1104 ret.push_back(Pair("signature", sig));
1107 else if (!identity.IsValid())
1109 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid identity");
1113 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Identity is revoked and cannot sign");
1118 const CKeyID *keyID = boost::get<CKeyID>(&dest);
1120 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
1124 if (!pwalletMain->GetKey(*keyID, key)) {
1125 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
1128 CHashWriterSHA256 ss(SER_GETHASH, PROTOCOL_VERSION);
1130 uint256 msgHash = ss.GetHash();
1133 ss << verusDataSignaturePrefix;
1136 vector<unsigned char> vchSig;
1137 if (!key.SignCompact(ss.GetHash(), vchSig))
1138 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
1140 UniValue ret(UniValue::VOBJ);
1141 std::reverse(msgHash.begin(), msgHash.end()); // return a reversed hash for compatibility reasons
1142 ret.push_back(Pair("hash", msgHash.GetHex()));
1143 ret.push_back(Pair("signature", EncodeBase64(&vchSig[0], vchSig.size())));
1148 uint256 HashFile(std::string filepath);
1150 bool printoutAPI = false;
1151 UniValue printapis(const UniValue& params, bool fHelp)
1153 if (fHelp || params.size() != 1)
1154 throw runtime_error(
1155 "printapis trueorfalse\n"
1156 "\nPrints the name of all APIs if parameter is true"
1161 + HelpExampleCli("signfile", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"filepath/filename\"") +
1162 "\nVerify the signature\n"
1163 + HelpExampleCli("verifyfile", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"signature\" \"filepath/filename\"") +
1165 + HelpExampleRpc("signfile", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"filepath/filename\"")
1167 printoutAPI = uni_get_bool(params[0]);
1168 return NullUniValue;
1171 UniValue signfile(const UniValue& params, bool fHelp)
1173 if (!EnsureWalletIsAvailable(fHelp))
1174 return NullUniValue;
1176 if (fHelp || params.size() < 2 || params.size() > 3)
1177 throw runtime_error(
1178 "signfile \"address or identity\" \"filepath/filename\" \"curentsig\"\n"
1179 "\nGenerates a SHA256D hash of the file, returns the hash, and signs the hash with the private key specified"
1180 + HelpRequiringPassphrase() + "\n"
1182 "1. \"t-addr or identity\" (string, required) The transparent address or identity to use for signing.\n"
1183 "2. \"filename\" (string, required) Local file to sign\n"
1184 "2. \"cursig\" (string) The current signature of the message encoded in base 64 if multisig ID\n"
1187 " \"hash\":\"hexhash\" (string) The hash of the message (SHA256, NOT SHA256D)\n"
1188 " \"signature\":\"base64sig\" (string) The aggregate signature of the message encoded in base 64 if all or partial signing successful\n"
1191 "\nCreate the signature\n"
1192 + HelpExampleCli("signfile", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"filepath/filename\"") +
1193 "\nVerify the signature\n"
1194 + HelpExampleCli("verifyfile", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"signature\" \"filepath/filename\"") +
1196 + HelpExampleRpc("signfile", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"filepath/filename\"")
1199 LOCK2(cs_main, pwalletMain->cs_wallet);
1201 EnsureWalletIsUnlocked();
1203 string strAddress = params[0].get_str();
1204 string strFileName = params[1].get_str();
1206 CTxDestination dest = DecodeDestination(strAddress);
1207 if (!IsValidDestination(dest)) {
1208 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address or identity");
1211 if (dest.which() == COptCCParams::ADDRTYPE_ID)
1213 string strSign = params.size() > 2 ? uni_get_str(params[2]) : "";
1217 identity = CIdentity::LookupIdentity(GetDestinationID(dest));
1218 if (identity.IsValidUnrevoked())
1220 CHashWriterSHA256 ss(SER_GETHASH, PROTOCOL_VERSION);
1221 uint256 msgHash = HashFile(strFileName);
1222 if (msgHash.IsNull())
1224 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot open file " + strFileName);
1228 std::string sig = SignMessageHash(identity, msgHash, strSign, (uint32_t)chainActive.Height());
1230 UniValue ret(UniValue::VOBJ);
1231 std::reverse(msgHash.begin(), msgHash.end()); // return a reversed hash for compatibility with sha256sum
1232 ret.push_back(Pair("hash", msgHash.GetHex()));
1233 ret.push_back(Pair("signature", sig));
1237 else if (!identity.IsValid())
1239 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid identity");
1243 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Identity is revoked and cannot sign");
1248 const CKeyID *keyID = boost::get<CKeyID>(&dest);
1250 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
1254 if (!pwalletMain->GetKey(*keyID, key)) {
1255 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
1258 CHashWriterSHA256 ss(SER_GETHASH, PROTOCOL_VERSION);
1259 uint256 msgHash = HashFile(strFileName);
1260 if (msgHash.IsNull())
1262 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot open file " + strFileName);
1266 ss << verusDataSignaturePrefix;
1270 vector<unsigned char> vchSig;
1271 if (!key.SignCompact(ss.GetHash(), vchSig))
1272 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
1274 UniValue ret(UniValue::VOBJ);
1275 std::reverse(msgHash.begin(), msgHash.end()); // return a reversed hash for compatibility with sha256sum
1276 ret.push_back(Pair("hash", msgHash.GetHex()));
1277 ret.push_back(Pair("signature", EncodeBase64(&vchSig[0], vchSig.size())));
1282 UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
1284 if (!EnsureWalletIsAvailable(fHelp))
1285 return NullUniValue;
1287 if (fHelp || params.size() < 1 || params.size() > 2)
1288 throw runtime_error(
1289 "getreceivedbyaddress \"" + strprintf("%s",komodo_chainname()) + "_address\" ( minconf )\n"
1290 "\nReturns the total amount received by the given " + strprintf("%s",komodo_chainname()) + " address in transactions with at least minconf confirmations.\n"
1292 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address for transactions.\n"
1293 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
1295 "amount (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received at this address.\n"
1297 "\nThe amount from transactions with at least 1 confirmation\n"
1298 + HelpExampleCli("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"") +
1299 "\nThe amount including unconfirmed transactions, zero confirmations\n"
1300 + HelpExampleCli("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0") +
1301 "\nThe amount with at least 6 confirmations, very safe\n"
1302 + HelpExampleCli("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 6") +
1303 "\nAs a json rpc call\n"
1304 + HelpExampleRpc("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", 6")
1307 LOCK2(cs_main, pwalletMain->cs_wallet);
1310 CTxDestination dest = DecodeDestination(params[0].get_str());
1311 if (!IsValidDestination(dest)) {
1312 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Verus address");
1314 CScript scriptPubKey = GetScriptForDestination(dest);
1315 if (!IsMine(*pwalletMain, scriptPubKey)) {
1316 return ValueFromAmount(0);
1319 // Minimum confirmations
1321 if (params.size() > 1)
1322 nMinDepth = params[1].get_int();
1325 CAmount nAmount = 0;
1326 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1328 const CWalletTx& wtx = (*it).second;
1329 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
1332 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1333 if (txout.scriptPubKey == scriptPubKey)
1334 if (wtx.GetDepthInMainChain() >= nMinDepth)
1335 nAmount += txout.nValue; // komodo_interest?
1338 return ValueFromAmount(nAmount);
1342 UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
1344 if (!EnsureWalletIsAvailable(fHelp))
1345 return NullUniValue;
1347 if (fHelp || params.size() < 1 || params.size() > 2)
1348 throw runtime_error(
1349 "getreceivedbyaccount \"account\" ( minconf )\n"
1350 "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
1352 "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"
1353 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
1355 "amount (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received for this account.\n"
1357 "\nAmount received by the default account with at least 1 confirmation\n"
1358 + HelpExampleCli("getreceivedbyaccount", "\"\"") +
1359 "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
1360 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
1361 "\nThe amount with at least 6 confirmation, very safe\n"
1362 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
1363 "\nAs a json rpc call\n"
1364 + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
1367 LOCK2(cs_main, pwalletMain->cs_wallet);
1369 // Minimum confirmations
1371 if (params.size() > 1)
1372 nMinDepth = params[1].get_int();
1374 // Get the set of pub keys assigned to account
1375 string strAccount = AccountFromValue(params[0]);
1376 set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
1379 CAmount nAmount = 0;
1380 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1382 const CWalletTx& wtx = (*it).second;
1383 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
1386 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1388 CTxDestination address;
1389 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
1390 if (wtx.GetDepthInMainChain() >= nMinDepth)
1391 nAmount += txout.nValue; // komodo_interest?
1395 return ValueFromAmount(nAmount);
1399 CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
1401 CAmount nBalance = 0;
1403 // Tally wallet transactions
1404 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1406 const CWalletTx& wtx = (*it).second;
1407 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
1410 CAmount nReceived, nSent, nFee;
1411 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
1413 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1414 nBalance += nReceived;
1415 nBalance -= nSent + nFee;
1418 // Tally internal accounting entries
1419 nBalance += walletdb.GetAccountCreditDebit(strAccount);
1424 CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
1426 CWalletDB walletdb(pwalletMain->strWalletFile);
1427 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
1431 UniValue getbalance(const UniValue& params, bool fHelp)
1433 if (!EnsureWalletIsAvailable(fHelp))
1434 return NullUniValue;
1436 if (fHelp || params.size() > 3)
1437 throw runtime_error(
1438 "getbalance ( \"account\" minconf includeWatchonly )\n"
1439 "\nReturns the server's total available balance.\n"
1441 "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"
1442 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
1443 "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
1445 "amount (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received for this account.\n"
1447 "\nThe total amount in the wallet\n"
1448 + HelpExampleCli("getbalance", "") +
1449 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
1450 + HelpExampleCli("getbalance", "\"*\" 6") +
1451 "\nAs a json rpc call\n"
1452 + HelpExampleRpc("getbalance", "\"*\", 6")
1455 LOCK2(cs_main, pwalletMain->cs_wallet);
1457 if (params.size() == 0)
1458 return ValueFromAmount(pwalletMain->GetBalance());
1461 if (params.size() > 1)
1462 nMinDepth = params[1].get_int();
1463 isminefilter filter = ISMINE_SPENDABLE;
1464 if(params.size() > 2)
1465 if(params[2].get_bool())
1466 filter = filter | ISMINE_WATCH_ONLY;
1468 if (params[0].get_str() == "*") {
1469 // Calculate total balance a different way from GetBalance()
1470 // (GetBalance() sums up all unspent TxOuts)
1471 // getbalance and "getbalance * 1 true" should return the same number
1472 CAmount nBalance = 0;
1473 //CAmount altBalance = 0;
1474 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1476 const CWalletTx& wtx = (*it).second;
1477 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
1481 string strSentAccount;
1482 list<COutputEntry> listReceived;
1483 list<COutputEntry> listSent;
1484 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
1485 if (wtx.GetDepthInMainChain() >= nMinDepth)
1487 //altBalance += wtx.GetAvailableCredit();
1488 BOOST_FOREACH(const COutputEntry& r, listReceived)
1489 nBalance += r.amount;
1491 BOOST_FOREACH(const COutputEntry& s, listSent)
1492 nBalance -= s.amount;
1495 //printf("alternate wallet balance: %s\n", ValueFromAmount(nBalance).write().c_str());
1496 return ValueFromAmount(nBalance);
1499 string strAccount = AccountFromValue(params[0]);
1501 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
1503 return ValueFromAmount(nBalance);
1506 UniValue getunconfirmedbalance(const UniValue ¶ms, bool fHelp)
1508 if (!EnsureWalletIsAvailable(fHelp))
1509 return NullUniValue;
1511 if (fHelp || params.size() > 0)
1512 throw runtime_error(
1513 "getunconfirmedbalance\n"
1514 "Returns the server's total unconfirmed balance\n");
1516 LOCK2(cs_main, pwalletMain->cs_wallet);
1518 return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
1522 UniValue movecmd(const UniValue& params, bool fHelp)
1524 if (!EnsureWalletIsAvailable(fHelp))
1525 return NullUniValue;
1527 if (fHelp || params.size() < 3 || params.size() > 5)
1528 throw runtime_error(
1529 "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
1530 "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
1532 "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"
1533 "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"
1534 "3. amount (numeric) Quantity of " + strprintf("%s",komodo_chainname()) + " to move between accounts.\n"
1535 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
1536 "5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
1538 "true|false (boolean) true if successful.\n"
1540 "\nMove 0.01 " + strprintf("%s",komodo_chainname()) + " from the default account to the account named tabby\n"
1541 + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
1542 "\nMove 0.01 " + strprintf("%s",komodo_chainname()) + " timotei to akiko with a comment and funds have 6 confirmations\n"
1543 + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
1544 "\nAs a json rpc call\n"
1545 + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
1547 if ( ASSETCHAINS_PRIVATE != 0 )
1548 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
1550 LOCK2(cs_main, pwalletMain->cs_wallet);
1552 string strFrom = AccountFromValue(params[0]);
1553 string strTo = AccountFromValue(params[1]);
1554 CAmount nAmount = AmountFromValue(params[2]);
1556 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1557 if (params.size() > 3)
1558 // unused parameter, used to be nMinDepth, keep type-checking it though
1559 (void)params[3].get_int();
1561 if (params.size() > 4)
1562 strComment = params[4].get_str();
1564 CWalletDB walletdb(pwalletMain->strWalletFile);
1565 if (!walletdb.TxnBegin())
1566 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
1568 int64_t nNow = GetAdjustedTime();
1571 CAccountingEntry debit;
1572 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
1573 debit.strAccount = strFrom;
1574 debit.nCreditDebit = -nAmount;
1576 debit.strOtherAccount = strTo;
1577 debit.strComment = strComment;
1578 walletdb.WriteAccountingEntry(debit);
1581 CAccountingEntry credit;
1582 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
1583 credit.strAccount = strTo;
1584 credit.nCreditDebit = nAmount;
1585 credit.nTime = nNow;
1586 credit.strOtherAccount = strFrom;
1587 credit.strComment = strComment;
1588 walletdb.WriteAccountingEntry(credit);
1590 if (!walletdb.TxnCommit())
1591 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
1597 UniValue sendfrom(const UniValue& params, bool fHelp)
1599 if (!EnsureWalletIsAvailable(fHelp))
1600 return NullUniValue;
1602 if (fHelp || params.size() < 3 || params.size() > 6)
1603 throw runtime_error(
1604 "sendfrom \"fromaccount\" \"to" + strprintf("%s",komodo_chainname()) + "address\" amount ( minconf \"comment\" \"comment-to\" )\n"
1605 "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a " + strprintf("%s",komodo_chainname()) + " address.\n"
1606 "The amount is a real and is rounded to the nearest 0.00000001."
1607 + HelpRequiringPassphrase() + "\n"
1609 "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"
1610 "2. \"to" + strprintf("%s",komodo_chainname()) + "address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to send funds to.\n"
1611 "3. amount (numeric, required) The amount in " + strprintf("%s",komodo_chainname()) + " (transaction fee is added on top).\n"
1612 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
1613 "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
1614 " This is not part of the transaction, just kept in your wallet.\n"
1615 "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n"
1616 " to which you're sending the transaction. This is not part of the transaction, \n"
1617 " it is just kept in your wallet.\n"
1619 "\"transactionid\" (string) The transaction id.\n"
1621 "\nSend 0.01 " + strprintf("%s",komodo_chainname()) + " from the default account to the address, must have at least 1 confirmation\n"
1622 + HelpExampleCli("sendfrom", "\"\" \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.01") +
1623 "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
1624 + HelpExampleCli("sendfrom", "\"tabby\" \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.01 6 \"donation\" \"seans outpost\"") +
1625 "\nAs a json rpc call\n"
1626 + HelpExampleRpc("sendfrom", "\"tabby\", \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", 0.01, 6, \"donation\", \"seans outpost\"")
1628 if ( ASSETCHAINS_PRIVATE != 0 )
1629 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
1631 LOCK2(cs_main, pwalletMain->cs_wallet);
1633 std::string strAccount = AccountFromValue(params[0]);
1634 CTxDestination dest = DecodeDestination(params[1].get_str());
1635 if (!IsValidDestination(dest)) {
1636 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Verus address");
1638 CAmount nAmount = AmountFromValue(params[2]);
1640 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1642 if (params.size() > 3)
1643 nMinDepth = params[3].get_int();
1646 wtx.strFromAccount = strAccount;
1647 if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty())
1648 wtx.mapValue["comment"] = params[4].get_str();
1649 if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty())
1650 wtx.mapValue["to"] = params[5].get_str();
1652 EnsureWalletIsUnlocked();
1655 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
1656 if (nAmount > nBalance)
1657 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
1659 SendMoney(dest, nAmount, false, wtx, 0, 0, 0);
1661 return wtx.GetHash().GetHex();
1665 UniValue sendmany(const UniValue& params, bool fHelp)
1667 if (!EnsureWalletIsAvailable(fHelp))
1668 return NullUniValue;
1670 if (fHelp || params.size() < 2 || params.size() > 5)
1671 throw runtime_error(
1672 "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
1673 "\nSend multiple times. Amounts are decimal numbers with at most 8 digits of precision."
1674 + HelpRequiringPassphrase() + "\n"
1676 "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"
1677 "2. \"amounts\" (string, required) A json object with addresses and amounts\n"
1679 " \"address\":amount (numeric) The " + strprintf("%s",komodo_chainname()) + " address is the key, the numeric amount in " + strprintf("%s",komodo_chainname()) + " is the value\n"
1682 "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
1683 "4. \"comment\" (string, optional) A comment\n"
1684 "5. subtractfeefromamount (string, optional) A json array with addresses.\n"
1685 " The fee will be equally deducted from the amount of each selected address.\n"
1686 " Those recipients will receive less " + strprintf("%s",komodo_chainname()) + " than you enter in their corresponding amount field.\n"
1687 " If no addresses are specified here, the sender pays the fee.\n"
1689 " \"address\" (string) Subtract fee from this address\n"
1693 "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
1694 " the number of addresses.\n"
1696 "\nSend two amounts to two different addresses:\n"
1697 + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\"") +
1698 "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
1699 + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\" 6 \"testing\"") +
1700 "\nSend two amounts to two different addresses, subtract fee from amount:\n"
1701 + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\" 1 \"\" \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"") +
1702 "\nAs a json rpc call\n"
1703 + HelpExampleRpc("sendmany", "\"\", \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\", 6, \"testing\"")
1705 if ( ASSETCHAINS_PRIVATE != 0 )
1706 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
1708 LOCK2(cs_main, pwalletMain->cs_wallet);
1710 string strAccount = AccountFromValue(params[0]);
1711 UniValue sendTo = params[1].get_obj();
1713 if (params.size() > 2)
1714 nMinDepth = params[2].get_int();
1717 wtx.strFromAccount = strAccount;
1718 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
1719 wtx.mapValue["comment"] = params[3].get_str();
1721 UniValue subtractFeeFromAmount(UniValue::VARR);
1722 if (params.size() > 4)
1723 subtractFeeFromAmount = params[4].get_array();
1725 std::set<CTxDestination> destinations;
1726 std::vector<CRecipient> vecSend;
1728 CAmount totalAmount = 0;
1729 std::vector<std::string> keys = sendTo.getKeys();
1730 for (const std::string& name_ : keys) {
1731 CTxDestination dest = DecodeDestination(name_);
1732 if (!IsValidDestination(dest)) {
1733 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Verus address: ") + name_);
1736 if (destinations.count(dest)) {
1737 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
1739 destinations.insert(dest);
1741 CScript scriptPubKey = GetScriptForDestination(dest);
1742 CAmount nAmount = AmountFromValue(sendTo[name_]);
1744 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1745 totalAmount += nAmount;
1747 bool fSubtractFeeFromAmount = false;
1748 for (size_t idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
1749 const UniValue& addr = subtractFeeFromAmount[idx];
1750 if (addr.get_str() == name_)
1751 fSubtractFeeFromAmount = true;
1754 CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
1755 vecSend.push_back(recipient);
1758 EnsureWalletIsUnlocked();
1761 CAmount nBalance = pwalletMain->GetBalance();
1762 //CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
1763 if (totalAmount > nBalance)
1764 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
1767 CReserveKey keyChange(pwalletMain);
1768 CAmount nFeeRequired = 0;
1769 int nChangePosRet = -1;
1770 string strFailReason;
1771 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
1773 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
1774 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1775 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
1777 return wtx.GetHash().GetHex();
1780 // Defined in rpc/misc.cpp
1781 extern CScript _createmultisig_redeemScript(const UniValue& params);
1783 UniValue addmultisigaddress(const UniValue& params, bool fHelp)
1785 if (!EnsureWalletIsAvailable(fHelp))
1786 return NullUniValue;
1788 if (fHelp || params.size() < 2 || params.size() > 3)
1790 string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
1791 "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
1792 "Each key is a " + strprintf("%s",komodo_chainname()) + " address or hex-encoded public key.\n"
1793 "If 'account' is specified (DEPRECATED), assign address to that account.\n"
1796 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
1797 "2. \"keysobject\" (string, required) A json array of " + strprintf("%s",komodo_chainname()) + " addresses or hex-encoded public keys\n"
1799 " \"address\" (string) " + strprintf("%s",komodo_chainname()) + " address or hex-encoded public key\n"
1802 "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"
1805 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) A " + strprintf("%s",komodo_chainname()) + " address associated with the keys.\n"
1808 "\nAdd a multisig address from 2 addresses\n"
1809 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"") +
1810 "\nAs json rpc call\n"
1811 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"")
1813 throw runtime_error(msg);
1816 LOCK2(cs_main, pwalletMain->cs_wallet);
1819 if (params.size() > 2)
1820 strAccount = AccountFromValue(params[2]);
1822 // Construct using pay-to-script-hash:
1823 CScript inner = _createmultisig_redeemScript(params);
1824 CScriptID innerID(inner);
1825 pwalletMain->AddCScript(inner);
1827 pwalletMain->SetAddressBook(innerID, strAccount, "send");
1828 return EncodeDestination(innerID);
1836 vector<uint256> txids;
1841 nConf = std::numeric_limits<int>::max();
1842 fIsWatchonly = false;
1846 UniValue ListReceived(const UniValue& params, bool fByAccounts)
1848 // Minimum confirmations
1850 if (params.size() > 0)
1851 nMinDepth = params[0].get_int();
1853 // Whether to include empty accounts
1854 bool fIncludeEmpty = false;
1855 if (params.size() > 1)
1856 fIncludeEmpty = params[1].get_bool();
1858 isminefilter filter = ISMINE_SPENDABLE;
1859 if(params.size() > 2)
1860 if(params[2].get_bool())
1861 filter = filter | ISMINE_WATCH_ONLY;
1864 std::map<CTxDestination, tallyitem> mapTally;
1865 for (const std::pair<uint256, CWalletTx>& pairWtx : pwalletMain->mapWallet) {
1866 const CWalletTx& wtx = pairWtx.second;
1868 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
1871 int nDepth = wtx.GetDepthInMainChain();
1872 if (nDepth < nMinDepth)
1875 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1877 CTxDestination address;
1878 if (!ExtractDestination(txout.scriptPubKey, address))
1881 isminefilter mine = IsMine(*pwalletMain, address);
1882 if(!(mine & filter))
1885 tallyitem& item = mapTally[address];
1886 item.nAmount += txout.nValue; // komodo_interest?
1887 item.nConf = min(item.nConf, nDepth);
1888 item.txids.push_back(wtx.GetHash());
1889 if (mine & ISMINE_WATCH_ONLY)
1890 item.fIsWatchonly = true;
1895 UniValue ret(UniValue::VARR);
1896 std::map<std::string, tallyitem> mapAccountTally;
1897 for (const std::pair<CTxDestination, CAddressBookData>& item : pwalletMain->mapAddressBook) {
1898 const CTxDestination& dest = item.first;
1899 const std::string& strAccount = item.second.name;
1900 std::map<CTxDestination, tallyitem>::iterator it = mapTally.find(dest);
1901 if (it == mapTally.end() && !fIncludeEmpty)
1904 CAmount nAmount = 0;
1905 int nConf = std::numeric_limits<int>::max();
1906 bool fIsWatchonly = false;
1907 if (it != mapTally.end())
1909 nAmount = (*it).second.nAmount;
1910 nConf = (*it).second.nConf;
1911 fIsWatchonly = (*it).second.fIsWatchonly;
1916 tallyitem& item = mapAccountTally[strAccount];
1917 item.nAmount += nAmount;
1918 item.nConf = min(item.nConf, nConf);
1919 item.fIsWatchonly = fIsWatchonly;
1923 UniValue obj(UniValue::VOBJ);
1925 obj.push_back(Pair("involvesWatchonly", true));
1926 obj.push_back(Pair("address", EncodeDestination(dest)));
1927 obj.push_back(Pair("account", strAccount));
1928 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1929 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1930 UniValue transactions(UniValue::VARR);
1931 if (it != mapTally.end())
1933 BOOST_FOREACH(const uint256& item, (*it).second.txids)
1935 transactions.push_back(item.GetHex());
1938 obj.push_back(Pair("txids", transactions));
1945 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1947 CAmount nAmount = (*it).second.nAmount;
1948 int nConf = (*it).second.nConf;
1949 UniValue obj(UniValue::VOBJ);
1950 if((*it).second.fIsWatchonly)
1951 obj.push_back(Pair("involvesWatchonly", true));
1952 obj.push_back(Pair("account", (*it).first));
1953 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1954 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1962 UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
1964 if (!EnsureWalletIsAvailable(fHelp))
1965 return NullUniValue;
1967 if (fHelp || params.size() > 3)
1968 throw runtime_error(
1969 "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
1970 "\nList balances by receiving address.\n"
1972 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1973 "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n"
1974 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1979 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
1980 " \"address\" : \"receivingaddress\", (string) The receiving address\n"
1981 " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
1982 " \"amount\" : x.xxx, (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received by the address\n"
1983 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1989 + HelpExampleCli("listreceivedbyaddress", "")
1990 + HelpExampleCli("listreceivedbyaddress", "6 true")
1991 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
1994 LOCK2(cs_main, pwalletMain->cs_wallet);
1996 return ListReceived(params, false);
1999 UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
2001 if (!EnsureWalletIsAvailable(fHelp))
2002 return NullUniValue;
2004 if (fHelp || params.size() > 3)
2005 throw runtime_error(
2006 "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
2007 "\nDEPRECATED. List balances by account.\n"
2009 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
2010 "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
2011 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
2016 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
2017 " \"account\" : \"accountname\", (string) The account name of the receiving account\n"
2018 " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
2019 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
2025 + HelpExampleCli("listreceivedbyaccount", "")
2026 + HelpExampleCli("listreceivedbyaccount", "6 true")
2027 + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
2030 LOCK2(cs_main, pwalletMain->cs_wallet);
2032 return ListReceived(params, true);
2035 static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
2037 if (IsValidDestination(dest)) {
2038 entry.push_back(Pair("address", EncodeDestination(dest)));
2042 bool ValidateStakeTransaction(const CTransaction &stakeTx, CStakeParams &stakeParams, bool validateSig = true);
2044 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
2047 string strSentAccount;
2048 list<COutputEntry> listReceived;
2049 list<COutputEntry> listSent;
2052 bool bIsStake = false;
2053 bool bIsCoinbase = false;
2054 bool bIsMint = false;
2055 bool bIsReserve = ConnectedChains.ThisChain().IsReserve();
2056 CReserveTransactionDescriptor rtxd;
2057 CCoinsViewCache view(pcoinsTip);
2058 uint32_t nHeight = chainActive.Height();
2060 if (ValidateStakeTransaction(wtx, p, false))
2066 bIsCoinbase = wtx.IsCoinBase();
2067 bIsMint = bIsCoinbase && wtx.vout.size() > 0 && wtx.vout[0].scriptPubKey.IsPayToCryptoCondition();
2070 if (bIsReserve && (rtxd = CReserveTransactionDescriptor(wtx, view, nHeight)).IsReserve())
2072 ret.push_back(Pair("isreserve", true));
2073 bool isReserveExchange = rtxd.IsReserveExchange();
2074 ret.push_back(Pair("isreserveexchange", isReserveExchange));
2075 if (isReserveExchange)
2077 if (rtxd.IsMarket())
2079 ret.push_back(Pair("exchangetype", "market"));
2081 else if (rtxd.IsLimit())
2083 ret.push_back(Pair("exchangetype", "limit"));
2086 ret.push_back(Pair("nativefees", rtxd.NativeFees()));
2087 ret.push_back(Pair("reservefees", rtxd.ReserveFees().ToUniValue()));
2088 if (rtxd.nativeConversionFees || (rtxd.ReserveConversionFeesMap() > CCurrencyValueMap()))
2090 ret.push_back(Pair("nativeconversionfees", rtxd.nativeConversionFees));
2091 ret.push_back(Pair("reserveconversionfees", rtxd.ReserveConversionFeesMap().ToUniValue()));
2096 ret.push_back(Pair("isreserve", false));
2099 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, bIsStake ? ISMINE_ALLANDCHANGE : filter);
2101 bool fAllAccounts = (strAccount == string("*"));
2102 bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
2105 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
2107 BOOST_FOREACH(const COutputEntry& s, listSent)
2109 UniValue entry(UniValue::VOBJ);
2110 if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
2111 entry.push_back(Pair("involvesWatchonly", true));
2112 entry.push_back(Pair("account", strSentAccount));
2113 MaybePushAddress(entry, s.destination);
2114 entry.push_back(Pair("category", bIsStake ? "stake" : "send"));
2115 entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
2116 entry.push_back(Pair("vout", s.vout));
2117 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
2119 WalletTxToJSON(wtx, entry);
2120 entry.push_back(Pair("size", static_cast<uint64_t>(GetSerializeSize(static_cast<CTransaction>(wtx), SER_NETWORK, PROTOCOL_VERSION))));
2121 ret.push_back(entry);
2126 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
2128 BOOST_FOREACH(const COutputEntry& r, listReceived)
2131 if (pwalletMain->mapAddressBook.count(r.destination))
2132 account = pwalletMain->mapAddressBook[r.destination].name;
2133 if (fAllAccounts || (account == strAccount))
2135 UniValue entry(UniValue::VOBJ);
2136 if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
2137 entry.push_back(Pair("involvesWatchonly", true));
2138 entry.push_back(Pair("account", account));
2140 CTxDestination dest;
2141 if (CScriptExt::ExtractVoutDestination(wtx, r.vout, dest))
2142 MaybePushAddress(entry, dest);
2144 MaybePushAddress(entry, r.destination);
2149 if (wtx.GetDepthInMainChain() < 1)
2150 entry.push_back(Pair("category", "orphan"));
2151 else if ((btm = wtx.GetBlocksToMaturity()) > 0)
2153 entry.push_back(Pair("category", "immature"));
2154 entry.push_back(Pair("blockstomaturity", btm));
2157 entry.push_back(Pair("category", bIsMint ? "mint" : "generate"));
2161 entry.push_back(Pair("category", bIsStake ? "stake" : "receive"));
2165 if (rtxd.IsValid() && wtx.vout[r.vout].scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid())
2168 ScriptPubKeyToJSON(wtx.vout[r.vout].scriptPubKey, ccUni, false, false);
2169 entry.push_back(Pair("cryptocondition", ccUni));
2172 entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
2173 if (rtxd.IsReserve())
2175 entry.push_back(Pair("reserveamount", wtx.vout[r.vout].scriptPubKey.ReserveOutValue().ToUniValue()));
2177 entry.push_back(Pair("vout", r.vout));
2179 WalletTxToJSON(wtx, entry);
2180 entry.push_back(Pair("size", static_cast<uint64_t>(GetSerializeSize(static_cast<CTransaction>(wtx), SER_NETWORK, PROTOCOL_VERSION))));
2181 ret.push_back(entry);
2187 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret)
2189 bool fAllAccounts = (strAccount == string("*"));
2191 if (fAllAccounts || acentry.strAccount == strAccount)
2193 UniValue entry(UniValue::VOBJ);
2194 entry.push_back(Pair("account", acentry.strAccount));
2195 entry.push_back(Pair("category", "move"));
2196 entry.push_back(Pair("time", acentry.nTime));
2197 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
2198 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
2199 entry.push_back(Pair("comment", acentry.strComment));
2200 ret.push_back(entry);
2204 UniValue listtransactions(const UniValue& params, bool fHelp)
2206 if (!EnsureWalletIsAvailable(fHelp))
2207 return NullUniValue;
2209 if (fHelp || params.size() > 4)
2210 throw runtime_error(
2211 "listtransactions ( \"account\" count from includeWatchonly)\n"
2212 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
2214 "1. \"account\" (string, optional) DEPRECATED. The account name. Should be \"*\".\n"
2215 "2. count (numeric, optional, default=10) The number of transactions to return\n"
2216 "3. from (numeric, optional, default=0) The number of transactions to skip\n"
2217 "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
2221 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n"
2222 " It will be \"\" for the default account.\n"
2223 " \"address\":\"" + strprintf("%s",komodo_chainname()) + "_address\", (string) The " + strprintf("%s",komodo_chainname()) + " address of the transaction. Not present for \n"
2224 " move transactions (category = move).\n"
2225 " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
2226 " transaction between accounts, and not associated with an address,\n"
2227 " transaction id or block. 'send' and 'receive' transactions are \n"
2228 " associated with an address, transaction id and block details\n"
2229 " \"amount\": x.xxx, (numeric) The amount in " + strprintf("%s",komodo_chainname()) + ". This is negative for the 'send' category, and for the\n"
2230 " 'move' category for moves outbound. It is positive for the 'receive' category,\n"
2231 " and for the 'move' category for inbound funds.\n"
2232 " \"vout\" : n, (numeric) the vout value\n"
2233 " \"fee\": x.xxx, (numeric) The amount of the fee in " + strprintf("%s",komodo_chainname()) + ". This is negative and only available for the \n"
2234 " 'send' category of transactions.\n"
2235 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
2236 " 'receive' category of transactions.\n"
2237 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
2238 " category of transactions.\n"
2239 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
2240 " category of transactions.\n"
2241 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
2242 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
2243 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
2244 " for 'send' and 'receive' category of transactions.\n"
2245 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
2246 " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
2247 " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
2248 " negative amounts).\n"
2249 " \"size\": n, (numeric) Transaction size in bytes\n"
2254 "\nList the most recent 10 transactions in the systems\n"
2255 + HelpExampleCli("listtransactions", "") +
2256 "\nList transactions 100 to 120\n"
2257 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
2258 "\nAs a json rpc call\n"
2259 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
2262 LOCK2(cs_main, pwalletMain->cs_wallet);
2264 string strAccount = "*";
2265 if (params.size() > 0)
2266 strAccount = params[0].get_str();
2268 if (params.size() > 1)
2269 nCount = params[1].get_int();
2271 if (params.size() > 2)
2272 nFrom = params[2].get_int();
2273 isminefilter filter = ISMINE_SPENDABLE;
2274 if(params.size() > 3)
2275 if(params[3].get_bool())
2276 filter = filter | ISMINE_WATCH_ONLY;
2279 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
2281 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
2283 UniValue ret(UniValue::VARR);
2285 std::list<CAccountingEntry> acentries;
2286 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
2288 // iterate backwards until we have nCount items to return:
2289 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
2291 CWalletTx *const pwtx = (*it).second.first;
2293 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
2294 CAccountingEntry *const pacentry = (*it).second.second;
2296 AcentryToJSON(*pacentry, strAccount, ret);
2298 if ((int)ret.size() >= (nCount+nFrom)) break;
2300 // ret is newest to oldest
2302 if (nFrom > (int)ret.size())
2304 if ((nFrom + nCount) > (int)ret.size())
2305 nCount = ret.size() - nFrom;
2307 vector<UniValue> arrTmp = ret.getValues();
2309 vector<UniValue>::iterator first = arrTmp.begin();
2310 std::advance(first, nFrom);
2311 vector<UniValue>::iterator last = arrTmp.begin();
2312 std::advance(last, nFrom+nCount);
2314 if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
2315 if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
2317 std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
2321 ret.push_backV(arrTmp);
2326 UniValue listaccounts(const UniValue& params, bool fHelp)
2328 if (!EnsureWalletIsAvailable(fHelp))
2329 return NullUniValue;
2331 if (fHelp || params.size() > 2)
2332 throw runtime_error(
2333 "listaccounts ( minconf includeWatchonly)\n"
2334 "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
2336 "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
2337 "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
2339 "{ (json object where keys are account names, and values are numeric balances\n"
2340 " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
2344 "\nList account balances where there at least 1 confirmation\n"
2345 + HelpExampleCli("listaccounts", "") +
2346 "\nList account balances including zero confirmation transactions\n"
2347 + HelpExampleCli("listaccounts", "0") +
2348 "\nList account balances for 6 or more confirmations\n"
2349 + HelpExampleCli("listaccounts", "6") +
2350 "\nAs json rpc call\n"
2351 + HelpExampleRpc("listaccounts", "6")
2354 LOCK2(cs_main, pwalletMain->cs_wallet);
2357 if (params.size() > 0)
2358 nMinDepth = params[0].get_int();
2359 isminefilter includeWatchonly = ISMINE_SPENDABLE;
2360 if(params.size() > 1)
2361 if(params[1].get_bool())
2362 includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
2364 map<string, CAmount> mapAccountBalances;
2365 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
2366 if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
2367 mapAccountBalances[entry.second.name] = 0;
2370 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
2372 const CWalletTx& wtx = (*it).second;
2374 string strSentAccount;
2375 list<COutputEntry> listReceived;
2376 list<COutputEntry> listSent;
2377 int nDepth = wtx.GetDepthInMainChain();
2378 if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
2380 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
2381 mapAccountBalances[strSentAccount] -= nFee;
2382 BOOST_FOREACH(const COutputEntry& s, listSent)
2383 mapAccountBalances[strSentAccount] -= s.amount;
2384 if (nDepth >= nMinDepth)
2386 BOOST_FOREACH(const COutputEntry& r, listReceived)
2387 if (pwalletMain->mapAddressBook.count(r.destination))
2388 mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
2390 mapAccountBalances[""] += r.amount;
2394 list<CAccountingEntry> acentries;
2395 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
2396 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
2397 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
2399 UniValue ret(UniValue::VOBJ);
2400 BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
2401 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
2406 UniValue listsinceblock(const UniValue& params, bool fHelp)
2408 if (!EnsureWalletIsAvailable(fHelp))
2409 return NullUniValue;
2412 throw runtime_error(
2413 "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
2414 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
2416 "1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
2417 "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
2418 "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
2421 " \"transactions\": [\n"
2422 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
2423 " \"address\":\"" + strprintf("%s",komodo_chainname()) + "_address\", (string) The " + strprintf("%s",komodo_chainname()) + " address of the transaction. Not present for move transactions (category = move).\n"
2424 " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
2425 " \"amount\": x.xxx, (numeric) The amount in " + strprintf("%s",komodo_chainname()) + ". This is negative for the 'send' category, and for the 'move' category for moves \n"
2426 " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
2427 " \"vout\" : n, (numeric) the vout value\n"
2428 " \"fee\": x.xxx, (numeric) The amount of the fee in " + strprintf("%s",komodo_chainname()) + ". This is negative and only available for the 'send' category of transactions.\n"
2429 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
2430 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
2431 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
2432 " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
2433 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
2434 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
2435 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
2436 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
2437 " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
2439 " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
2442 + HelpExampleCli("listsinceblock", "")
2443 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
2444 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
2447 LOCK2(cs_main, pwalletMain->cs_wallet);
2449 CBlockIndex *pindex = NULL;
2450 int target_confirms = 1;
2451 isminefilter filter = ISMINE_SPENDABLE;
2453 if (params.size() > 0)
2457 blockId.SetHex(params[0].get_str());
2458 BlockMap::iterator it = mapBlockIndex.find(blockId);
2459 if (it != mapBlockIndex.end())
2460 pindex = it->second;
2463 if (params.size() > 1)
2465 target_confirms = params[1].get_int();
2467 if (target_confirms < 1)
2468 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
2471 if(params.size() > 2)
2472 if(params[2].get_bool())
2473 filter = filter | ISMINE_WATCH_ONLY;
2475 int depth = pindex ? (1 + chainActive.Height() - pindex->GetHeight()) : -1;
2477 UniValue transactions(UniValue::VARR);
2479 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
2481 CWalletTx tx = (*it).second;
2483 if (depth == -1 || tx.GetDepthInMainChain() < depth)
2484 ListTransactions(tx, "*", 0, true, transactions, filter);
2487 CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
2488 uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
2490 UniValue ret(UniValue::VOBJ);
2491 ret.push_back(Pair("transactions", transactions));
2492 ret.push_back(Pair("lastblock", lastblock.GetHex()));
2497 UniValue gettransaction(const UniValue& params, bool fHelp)
2499 if (!EnsureWalletIsAvailable(fHelp))
2500 return NullUniValue;
2502 if (fHelp || params.size() < 1 || params.size() > 2)
2503 throw runtime_error(
2504 "gettransaction \"txid\" ( includeWatchonly )\n"
2505 "\nGet detailed information about in-wallet transaction <txid>\n"
2507 "1. \"txid\" (string, required) The transaction id\n"
2508 "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
2511 " \"amount\" : x.xxx, (numeric) The transaction amount in " + strprintf("%s",komodo_chainname()) + "\n"
2512 " \"confirmations\" : n, (numeric) The number of confirmations\n"
2513 " \"blockhash\" : \"hash\", (string) The block hash\n"
2514 " \"blockindex\" : xx, (numeric) The block index\n"
2515 " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
2516 " \"txid\" : \"transactionid\", (string) The transaction id.\n"
2517 " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
2518 " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
2519 " \"details\" : [\n"
2521 " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
2522 " \"address\" : \"" + strprintf("%s",komodo_chainname()) + "_address\", (string) The " + strprintf("%s",komodo_chainname()) + " address involved in the transaction\n"
2523 " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
2524 " \"amount\" : x.xxx (numeric) The amount in " + strprintf("%s",komodo_chainname()) + "\n"
2525 " \"vout\" : n, (numeric) the vout value\n"
2529 " \"vjoinsplit\" : [\n"
2531 " \"anchor\" : \"treestateref\", (string) Merkle root of note commitment tree\n"
2532 " \"nullifiers\" : [ string, ... ] (string) Nullifiers of input notes\n"
2533 " \"commitments\" : [ string, ... ] (string) Note commitments for note outputs\n"
2534 " \"macs\" : [ string, ... ] (string) Message authentication tags\n"
2535 " \"vpub_old\" : x.xxx (numeric) The amount removed from the transparent value pool\n"
2536 " \"vpub_new\" : x.xxx, (numeric) The amount added to the transparent value pool\n"
2540 " \"hex\" : \"data\" (string) Raw data for transaction\n"
2544 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
2545 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
2546 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
2549 LOCK2(cs_main, pwalletMain->cs_wallet);
2552 hash.SetHex(params[0].get_str());
2554 isminefilter filter = ISMINE_SPENDABLE;
2555 if(params.size() > 1)
2556 if(params[1].get_bool())
2557 filter = filter | ISMINE_WATCH_ONLY;
2559 UniValue entry(UniValue::VOBJ);
2560 if (!pwalletMain->mapWallet.count(hash))
2561 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
2562 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
2564 CAmount nCredit = wtx.GetCredit(filter);
2565 CAmount nDebit = wtx.GetDebit(filter);
2566 CAmount nNet = nCredit - nDebit;
2567 CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
2569 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
2570 if (wtx.IsFromMe(filter))
2571 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
2573 WalletTxToJSON(wtx, entry);
2575 UniValue details(UniValue::VARR);
2576 ListTransactions(wtx, "*", 0, false, details, filter);
2577 entry.push_back(Pair("details", details));
2579 string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
2580 entry.push_back(Pair("hex", strHex));
2586 UniValue backupwallet(const UniValue& params, bool fHelp)
2588 if (!EnsureWalletIsAvailable(fHelp))
2589 return NullUniValue;
2591 if (fHelp || params.size() != 1)
2592 throw runtime_error(
2593 "backupwallet \"destination\"\n"
2594 "\nSafely copies wallet.dat to destination filename\n"
2596 "1. \"destination\" (string, required) The destination filename, saved in the directory set by -exportdir option.\n"
2598 "\"path\" (string) The full path of the destination file\n"
2600 + HelpExampleCli("backupwallet", "\"backupdata\"")
2601 + HelpExampleRpc("backupwallet", "\"backupdata\"")
2604 LOCK2(cs_main, pwalletMain->cs_wallet);
2606 boost::filesystem::path exportdir;
2608 exportdir = GetExportDir();
2609 } catch (const std::runtime_error& e) {
2610 throw JSONRPCError(RPC_INTERNAL_ERROR, e.what());
2612 if (exportdir.empty()) {
2613 throw JSONRPCError(RPC_WALLET_ERROR, "Cannot backup wallet until the -exportdir option has been set");
2615 std::string unclean = params[0].get_str();
2616 std::string clean = SanitizeFilename(unclean);
2617 if (clean.compare(unclean) != 0) {
2618 throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Filename is invalid as only alphanumeric characters are allowed. Try '%s' instead.", clean));
2620 boost::filesystem::path exportfilepath = exportdir / clean;
2622 if (!BackupWallet(*pwalletMain, exportfilepath.string()))
2623 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
2625 return exportfilepath.string();
2629 UniValue keypoolrefill(const UniValue& params, bool fHelp)
2631 if (!EnsureWalletIsAvailable(fHelp))
2632 return NullUniValue;
2634 if (fHelp || params.size() > 1)
2635 throw runtime_error(
2636 "keypoolrefill ( newsize )\n"
2637 "\nFills the keypool."
2638 + HelpRequiringPassphrase() + "\n"
2640 "1. newsize (numeric, optional, default=100) The new keypool size\n"
2642 + HelpExampleCli("keypoolrefill", "")
2643 + HelpExampleRpc("keypoolrefill", "")
2646 LOCK2(cs_main, pwalletMain->cs_wallet);
2648 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
2649 unsigned int kpSize = 0;
2650 if (params.size() > 0) {
2651 if (params[0].get_int() < 0)
2652 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
2653 kpSize = (unsigned int)params[0].get_int();
2656 EnsureWalletIsUnlocked();
2657 pwalletMain->TopUpKeyPool(kpSize);
2659 if (pwalletMain->GetKeyPoolSize() < kpSize)
2660 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
2662 return NullUniValue;
2666 static void LockWallet(CWallet* pWallet)
2668 LOCK(cs_nWalletUnlockTime);
2669 nWalletUnlockTime = 0;
2673 UniValue walletpassphrase(const UniValue& params, bool fHelp)
2675 if (!EnsureWalletIsAvailable(fHelp))
2676 return NullUniValue;
2678 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
2679 throw runtime_error(
2680 "walletpassphrase \"passphrase\" timeout\n"
2681 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
2682 "This is needed prior to performing transactions related to private keys such as sending " + strprintf("%s",komodo_chainname()) + "\n"
2684 "1. \"passphrase\" (string, required) The wallet passphrase\n"
2685 "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
2687 "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
2688 "time that overrides the old one.\n"
2690 "\nunlock the wallet for 60 seconds\n"
2691 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
2692 "\nLock the wallet again (before 60 seconds)\n"
2693 + HelpExampleCli("walletlock", "") +
2694 "\nAs json rpc call\n"
2695 + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
2698 LOCK2(cs_main, pwalletMain->cs_wallet);
2702 if (!pwalletMain->IsCrypted())
2703 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
2705 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
2706 SecureString strWalletPass;
2707 strWalletPass.reserve(100);
2708 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2709 // Alternately, find a way to make params[0] mlock()'d to begin with.
2710 strWalletPass = params[0].get_str().c_str();
2712 if (strWalletPass.length() > 0)
2714 if (!pwalletMain->Unlock(strWalletPass))
2715 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
2718 throw runtime_error(
2719 "walletpassphrase <passphrase> <timeout>\n"
2720 "Stores the wallet decryption key in memory for <timeout> seconds.");
2722 // No need to check return values, because the wallet was unlocked above
2723 pwalletMain->UpdateNullifierNoteMap();
2724 pwalletMain->TopUpKeyPool();
2726 int64_t nSleepTime = params[1].get_int64();
2727 LOCK(cs_nWalletUnlockTime);
2728 nWalletUnlockTime = GetTime() + nSleepTime;
2729 RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
2731 return NullUniValue;
2735 UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
2737 if (!EnsureWalletIsAvailable(fHelp))
2738 return NullUniValue;
2740 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
2741 throw runtime_error(
2742 "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
2743 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
2745 "1. \"oldpassphrase\" (string) The current passphrase\n"
2746 "2. \"newpassphrase\" (string) The new passphrase\n"
2748 + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
2749 + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
2752 LOCK2(cs_main, pwalletMain->cs_wallet);
2756 if (!pwalletMain->IsCrypted())
2757 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
2759 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
2760 // Alternately, find a way to make params[0] mlock()'d to begin with.
2761 SecureString strOldWalletPass;
2762 strOldWalletPass.reserve(100);
2763 strOldWalletPass = params[0].get_str().c_str();
2765 SecureString strNewWalletPass;
2766 strNewWalletPass.reserve(100);
2767 strNewWalletPass = params[1].get_str().c_str();
2769 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
2770 throw runtime_error(
2771 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
2772 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
2774 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
2775 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
2777 return NullUniValue;
2781 UniValue walletlock(const UniValue& params, bool fHelp)
2783 if (!EnsureWalletIsAvailable(fHelp))
2784 return NullUniValue;
2786 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
2787 throw runtime_error(
2789 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
2790 "After calling this method, you will need to call walletpassphrase again\n"
2791 "before being able to call any methods which require the wallet to be unlocked.\n"
2793 "\nSet the passphrase for 2 minutes to perform a transaction\n"
2794 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
2795 "\nPerform a send (requires passphrase set)\n"
2796 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 1.0") +
2797 "\nClear the passphrase since we are done before 2 minutes is up\n"
2798 + HelpExampleCli("walletlock", "") +
2799 "\nAs json rpc call\n"
2800 + HelpExampleRpc("walletlock", "")
2803 LOCK2(cs_main, pwalletMain->cs_wallet);
2807 if (!pwalletMain->IsCrypted())
2808 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
2811 LOCK(cs_nWalletUnlockTime);
2812 pwalletMain->Lock();
2813 nWalletUnlockTime = 0;
2816 return NullUniValue;
2820 UniValue encryptwallet(const UniValue& params, bool fHelp)
2822 if (!EnsureWalletIsAvailable(fHelp))
2823 return NullUniValue;
2825 string enableArg = "developerencryptwallet";
2826 auto fEnableWalletEncryption = fExperimentalMode && GetBoolArg("-" + enableArg, false);
2828 std::string strWalletEncryptionDisabledMsg = "";
2829 if (!fEnableWalletEncryption) {
2830 strWalletEncryptionDisabledMsg = experimentalDisabledHelpMsg("encryptwallet", enableArg);
2833 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
2834 throw runtime_error(
2835 "encryptwallet \"passphrase\"\n"
2836 + strWalletEncryptionDisabledMsg +
2837 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
2838 "After this, any calls that interact with private keys such as sending or signing \n"
2839 "will require the passphrase to be set prior the making these calls.\n"
2840 "Use the walletpassphrase call for this, and then walletlock call.\n"
2841 "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
2842 "Note that this will shutdown the server.\n"
2844 "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
2846 "\nEncrypt you wallet\n"
2847 + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
2848 "\nNow set the passphrase to use the wallet, such as for signing or sending " + strprintf("%s",komodo_chainname()) + "\n"
2849 + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
2850 "\nNow we can so something like sign\n"
2851 + HelpExampleCli("signmessage", "\"" + strprintf("%s",komodo_chainname()) + "_address\" \"test message\"") +
2852 "\nNow lock the wallet again by removing the passphrase\n"
2853 + HelpExampleCli("walletlock", "") +
2854 "\nAs a json rpc call\n"
2855 + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
2858 LOCK2(cs_main, pwalletMain->cs_wallet);
2862 if (!fEnableWalletEncryption) {
2863 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet encryption is disabled.");
2865 if (pwalletMain->IsCrypted())
2866 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
2868 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2869 // Alternately, find a way to make params[0] mlock()'d to begin with.
2870 SecureString strWalletPass;
2871 strWalletPass.reserve(100);
2872 strWalletPass = params[0].get_str().c_str();
2874 if (strWalletPass.length() < 1)
2875 throw runtime_error(
2876 "encryptwallet <passphrase>\n"
2877 "Encrypts the wallet with <passphrase>.");
2879 if (!pwalletMain->EncryptWallet(strWalletPass))
2880 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
2882 // BDB seems to have a bad habit of writing old data into
2883 // slack space in .dat files; that is bad if the old data is
2884 // unencrypted private keys. So:
2886 return "wallet encrypted; Verus server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
2889 UniValue lockunspent(const UniValue& params, bool fHelp)
2891 if (!EnsureWalletIsAvailable(fHelp))
2892 return NullUniValue;
2894 if (fHelp || params.size() < 1 || params.size() > 2)
2895 throw runtime_error(
2896 "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
2897 "\nUpdates list of temporarily unspendable outputs.\n"
2898 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
2899 "A locked transaction output will not be chosen by automatic coin selection, when spending " + strprintf("%s",komodo_chainname()) + ".\n"
2900 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2901 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
2902 "Also see the listunspent call\n"
2904 "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
2905 "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
2906 " [ (json array of json objects)\n"
2908 " \"txid\":\"id\", (string) The transaction id\n"
2909 " \"vout\": n (numeric) The output number\n"
2915 "true|false (boolean) Whether the command was successful or not\n"
2918 "\nList the unspent transactions\n"
2919 + HelpExampleCli("listunspent", "") +
2920 "\nLock an unspent transaction\n"
2921 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2922 "\nList the locked transactions\n"
2923 + HelpExampleCli("listlockunspent", "") +
2924 "\nUnlock the transaction again\n"
2925 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2926 "\nAs a json rpc call\n"
2927 + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
2930 LOCK2(cs_main, pwalletMain->cs_wallet);
2932 if (params.size() == 1)
2933 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL));
2935 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
2937 bool fUnlock = params[0].get_bool();
2939 if (params.size() == 1) {
2941 pwalletMain->UnlockAllCoins();
2945 UniValue outputs = params[1].get_array();
2946 for (size_t idx = 0; idx < outputs.size(); idx++) {
2947 const UniValue& output = outputs[idx];
2948 if (!output.isObject())
2949 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
2950 const UniValue& o = output.get_obj();
2952 RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM));
2954 string txid = find_value(o, "txid").get_str();
2956 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
2958 int nOutput = find_value(o, "vout").get_int();
2960 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
2962 COutPoint outpt(uint256S(txid), nOutput);
2965 pwalletMain->UnlockCoin(outpt);
2967 pwalletMain->LockCoin(outpt);
2973 UniValue listlockunspent(const UniValue& params, bool fHelp)
2975 if (!EnsureWalletIsAvailable(fHelp))
2976 return NullUniValue;
2978 if (fHelp || params.size() > 0)
2979 throw runtime_error(
2981 "\nReturns list of temporarily unspendable outputs.\n"
2982 "See the lockunspent call to lock and unlock transactions for spending.\n"
2986 " \"txid\" : \"transactionid\", (string) The transaction id locked\n"
2987 " \"vout\" : n (numeric) The vout value\n"
2992 "\nList the unspent transactions\n"
2993 + HelpExampleCli("listunspent", "") +
2994 "\nLock an unspent transaction\n"
2995 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2996 "\nList the locked transactions\n"
2997 + HelpExampleCli("listlockunspent", "") +
2998 "\nUnlock the transaction again\n"
2999 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
3000 "\nAs a json rpc call\n"
3001 + HelpExampleRpc("listlockunspent", "")
3004 LOCK2(cs_main, pwalletMain->cs_wallet);
3006 vector<COutPoint> vOutpts;
3007 pwalletMain->ListLockedCoins(vOutpts);
3009 UniValue ret(UniValue::VARR);
3011 BOOST_FOREACH(COutPoint &outpt, vOutpts) {
3012 UniValue o(UniValue::VOBJ);
3014 o.push_back(Pair("txid", outpt.hash.GetHex()));
3015 o.push_back(Pair("vout", (int)outpt.n));
3022 UniValue settxfee(const UniValue& params, bool fHelp)
3024 if (!EnsureWalletIsAvailable(fHelp))
3025 return NullUniValue;
3027 if (fHelp || params.size() < 1 || params.size() > 1)
3028 throw runtime_error(
3030 "\nSet the transaction fee per kB.\n"
3032 "1. amount (numeric, required) The transaction fee in " + strprintf("%s",komodo_chainname()) + "/kB rounded to the nearest 0.00000001\n"
3034 "true|false (boolean) Returns true if successful\n"
3036 + HelpExampleCli("settxfee", "0.00001")
3037 + HelpExampleRpc("settxfee", "0.00001")
3040 LOCK2(cs_main, pwalletMain->cs_wallet);
3043 CAmount nAmount = AmountFromValue(params[0]);
3045 payTxFee = CFeeRate(nAmount, 1000);
3049 UniValue getwalletinfo(const UniValue& params, bool fHelp)
3051 if (!EnsureWalletIsAvailable(fHelp))
3052 return NullUniValue;
3054 if (fHelp || params.size() != 0)
3055 throw runtime_error(
3057 "Returns an object containing various wallet state info.\n"
3060 " \"walletversion\": xxxxx, (numeric) the wallet version\n"
3061 " \"balance\": xxxxxxx, (numeric) the total confirmed balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
3062 " \"reserve_balance\": xxxxxxx, (numeric) for PBaaS reserve chains, the total confirmed reserve balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
3063 " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
3064 " \"unconfirmed_reserve_balance\": xxx, (numeric) total unconfirmed reserve balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
3065 " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
3066 " \"immature_reserve_balance\": xxxxxx, (numeric) total immature reserve balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
3067 " \"eligible_staking_balance\": xxxxxx, (numeric) eligible staking balance in " + strprintf("%s",komodo_chainname()) + "\n"
3068 " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
3069 " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
3070 " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
3071 " \"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"
3072 " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n"
3073 " \"seedfp\": \"uint256\", (string) the BLAKE2b-256 hash of the HD seed\n"
3076 + HelpExampleCli("getwalletinfo", "")
3077 + HelpExampleRpc("getwalletinfo", "")
3080 LOCK2(cs_main, pwalletMain->cs_wallet);
3082 UniValue obj(UniValue::VOBJ);
3083 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
3084 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
3085 obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
3086 obj.push_back(Pair("immature_balance", ValueFromAmount(pwalletMain->GetImmatureBalance())));
3088 std::vector<COutput> vecOutputs;
3089 CAmount totalStakingAmount = 0;
3091 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true, false);
3093 for (int i = 0; i < vecOutputs.size(); i++)
3095 auto &txout = vecOutputs[i];
3098 txout.i < txout.tx->vout.size() &&
3099 txout.tx->vout[txout.i].nValue > 0 &&
3101 (txout.nDepth >= VERUS_MIN_STAKEAGE) &&
3102 !txout.tx->vout[txout.i].scriptPubKey.IsPayToCryptoCondition())
3104 totalStakingAmount += txout.tx->vout[txout.i].nValue;
3108 obj.push_back(Pair("eligible_staking_balance", ValueFromAmount(totalStakingAmount)));
3110 CCurrencyDefinition &chainDef = ConnectedChains.ThisChain();
3111 UniValue reserveBal(UniValue::VOBJ);
3112 for (auto &oneBalance : pwalletMain->GetReserveBalance().valueMap)
3114 reserveBal.push_back(make_pair(ConnectedChains.GetCachedCurrency(oneBalance.first).name, ValueFromAmount(oneBalance.second)));
3116 if (reserveBal.size())
3118 obj.push_back(Pair("reserve_balance", reserveBal));
3121 UniValue unconfirmedReserveBal(UniValue::VARR);
3122 for (auto &oneBalance : pwalletMain->GetUnconfirmedReserveBalance().valueMap)
3124 UniValue oneCurObj(UniValue::VOBJ);
3125 oneCurObj.push_back(make_pair(ConnectedChains.GetCachedCurrency(oneBalance.first).name, ValueFromAmount(oneBalance.second)));
3126 unconfirmedReserveBal.push_back(oneCurObj);
3128 if (unconfirmedReserveBal.size())
3130 obj.push_back(Pair("unconfirmed_reserve_balance", unconfirmedReserveBal));
3133 UniValue immatureReserveBal(UniValue::VARR);
3134 for (auto &oneBalance : pwalletMain->GetImmatureReserveBalance().valueMap)
3136 UniValue oneCurObj(UniValue::VOBJ);
3137 oneCurObj.push_back(make_pair(ConnectedChains.GetCachedCurrency(oneBalance.first).name, ValueFromAmount(oneBalance.second)));
3138 immatureReserveBal.push_back(oneCurObj);
3140 if (immatureReserveBal.size())
3142 obj.push_back(Pair("immature_reserve_balance", immatureReserveBal));
3145 uint32_t height = chainActive.LastTip() ? chainActive.LastTip()->GetHeight() : 0;
3147 if ((ConnectedChains.ThisChain().IsReserve() || ConnectedChains.ThisChain().startBlock < height) &&
3148 ConnectedChains.ThisChain().currencies.size())
3150 UniValue pricesInReserve(UniValue::VARR);
3151 CCoinbaseCurrencyState thisCurState(ConnectedChains.GetCurrencyState(height));
3152 std::vector<CAmount> prices(thisCurState.PricesInReserve());
3153 for (int i = 0; i < thisCurState.currencies.size(); i++)
3155 UniValue oneCurObj(UniValue::VOBJ);
3156 oneCurObj.push_back(make_pair(ConnectedChains.GetCachedCurrency(thisCurState.currencies[i]).name, ValueFromAmount(prices[i])));
3157 pricesInReserve.push_back(oneCurObj);
3159 obj.push_back(Pair("prices", pricesInReserve));
3162 obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size()));
3163 obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
3164 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
3165 if (pwalletMain->IsCrypted())
3166 obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
3167 obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
3168 uint256 seedFp = pwalletMain->GetHDChain().seedFp;
3169 if (!seedFp.IsNull())
3170 obj.push_back(Pair("seedfp", seedFp.GetHex()));
3174 UniValue resendwallettransactions(const UniValue& params, bool fHelp)
3176 if (!EnsureWalletIsAvailable(fHelp))
3177 return NullUniValue;
3179 if (fHelp || params.size() != 0)
3180 throw runtime_error(
3181 "resendwallettransactions\n"
3182 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
3183 "Intended only for testing; the wallet code periodically re-broadcasts\n"
3185 "Returns array of transaction ids that were re-broadcast.\n"
3188 LOCK2(cs_main, pwalletMain->cs_wallet);
3190 std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
3191 UniValue result(UniValue::VARR);
3192 BOOST_FOREACH(const uint256& txid, txids)
3194 result.push_back(txid.ToString());
3199 UniValue listunspent(const UniValue& params, bool fHelp)
3201 if (!EnsureWalletIsAvailable(fHelp))
3202 return NullUniValue;
3204 if (fHelp || params.size() > 3)
3205 throw runtime_error(
3206 "listunspent ( minconf maxconf [\"address\",...] )\n"
3207 "\nReturns array of unspent transaction outputs\n"
3208 "with between minconf and maxconf (inclusive) confirmations.\n"
3209 "Optionally filter to only include txouts paid to specified addresses.\n"
3210 "Results are an array of Objects, each of which has:\n"
3211 "{txid, vout, scriptPubKey, amount, confirmations}\n"
3213 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
3214 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
3215 "3. \"addresses\" (string) A json array of " + strprintf("%s",komodo_chainname()) + " addresses to filter\n"
3217 " \"address\" (string) " + strprintf("%s",komodo_chainname()) + " address\n"
3221 "[ (array of json object)\n"
3223 " \"txid\" : \"txid\", (string) the transaction id \n"
3224 " \"vout\" : n, (numeric) the vout value\n"
3225 " \"generated\" : true|false (boolean) true if txout is a coinbase transaction output\n"
3226 " \"address\" : \"address\", (string) the Zcash address\n"
3227 " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
3228 " \"scriptPubKey\" : \"key\", (string) the script key\n"
3229 " \"amount\" : x.xxx, (numeric) the transaction amount in " + CURRENCY_UNIT + "\n"
3230 " \"confirmations\" : n, (numeric) The number of confirmations\n"
3231 " \"redeemScript\" : n (string) The redeemScript if scriptPubKey is P2SH\n"
3232 " \"spendable\" : xxx (bool) Whether we have the private keys to spend this output\n"
3238 + HelpExampleCli("listunspent", "")
3239 + HelpExampleCli("listunspent", "6 9999999 \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"")
3240 + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"")
3243 RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
3246 if (params.size() > 0)
3247 nMinDepth = params[0].get_int();
3249 int nMaxDepth = 9999999;
3250 if (params.size() > 1)
3251 nMaxDepth = params[1].get_int();
3253 std::set<CTxDestination> destinations;
3254 if (params.size() > 2) {
3255 UniValue inputs = params[2].get_array();
3256 for (size_t idx = 0; idx < inputs.size(); idx++) {
3257 const UniValue& input = inputs[idx];
3258 CTxDestination dest = DecodeDestination(input.get_str());
3259 if (!IsValidDestination(dest)) {
3260 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Verus address: ") + input.get_str());
3262 if (!destinations.insert(dest).second) {
3263 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
3268 UniValue results(UniValue::VARR);
3269 vector<COutput> vecOutputs;
3270 assert(pwalletMain != NULL);
3271 LOCK2(cs_main, pwalletMain->cs_wallet);
3272 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
3273 BOOST_FOREACH(const COutput& out, vecOutputs) {
3274 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
3277 CTxDestination address;
3278 const CScript& scriptPubKey = out.tx->vout[out.i].scriptPubKey;
3279 bool fValidAddress = ExtractDestination(scriptPubKey, address);
3281 if (destinations.size() && (!fValidAddress || !destinations.count(address)))
3284 UniValue entry(UniValue::VOBJ);
3285 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
3286 entry.push_back(Pair("vout", out.i));
3287 entry.push_back(Pair("generated", out.tx->IsCoinBase()));
3289 if (fValidAddress) {
3290 entry.push_back(Pair("address", EncodeDestination(address)));
3292 if (pwalletMain->mapAddressBook.count(address))
3293 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
3295 if (scriptPubKey.IsPayToScriptHash()) {
3296 const CScriptID& hash = boost::get<CScriptID>(address);
3297 CScript redeemScript;
3298 if (pwalletMain->GetCScript(hash, redeemScript))
3299 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
3302 CAmount nValue = out.tx->vout[out.i].nValue;
3303 entry.push_back(Pair("amount", ValueFromAmount(out.tx->vout[out.i].nValue)));
3305 CCurrencyValueMap reserveOut;
3306 if (ConnectedChains.ThisChain().IsReserve() && (reserveOut = out.tx->vout[out.i].scriptPubKey.ReserveOutValue()).valueMap.size())
3308 entry.push_back(Pair("reserveAmount", reserveOut.ToUniValue()));
3310 if ( out.tx->nLockTime != 0 )
3312 BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
3313 CBlockIndex *tipindex,*pindex = it->second;
3314 uint64_t interest; uint32_t locktime; int32_t txheight;
3315 if ( pindex != 0 && (tipindex= chainActive.LastTip()) != 0 )
3317 interest = komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->GetHeight());
3318 //interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime);
3319 entry.push_back(Pair("interest",ValueFromAmount(interest)));
3321 //fprintf(stderr,"nValue %.8f pindex.%p tipindex.%p locktime.%u txheight.%d pindexht.%d\n",(double)nValue/COIN,pindex,chainActive.LastTip(),locktime,txheight,pindex->GetHeight());
3323 entry.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
3324 entry.push_back(Pair("confirmations", out.nDepth));
3325 entry.push_back(Pair("spendable", out.fSpendable));
3326 results.push_back(entry);
3332 uint64_t komodo_interestsum()
3334 #ifdef ENABLE_WALLET
3335 if ( GetBoolArg("-disablewallet", false) == 0 )
3337 uint64_t interest,sum = 0; int32_t txheight; uint32_t locktime;
3338 vector<COutput> vecOutputs;
3339 assert(pwalletMain != NULL);
3340 LOCK2(cs_main, pwalletMain->cs_wallet);
3341 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
3342 BOOST_FOREACH(const COutput& out,vecOutputs)
3344 CAmount nValue = out.tx->vout[out.i].nValue;
3345 if ( out.tx->nLockTime != 0 && out.fSpendable != 0 )
3347 BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
3348 CBlockIndex *tipindex,*pindex = it->second;
3349 if ( pindex != 0 && (tipindex= chainActive.LastTip()) != 0 )
3351 interest = komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->GetHeight());
3352 //interest = komodo_interest(pindex->GetHeight(),nValue,out.tx->nLockTime,tipindex->nTime);
3357 KOMODO_INTERESTSUM = sum;
3358 KOMODO_WALLETBALANCE = pwalletMain->GetBalance();
3366 UniValue z_listunspent(const UniValue& params, bool fHelp)
3368 if (!EnsureWalletIsAvailable(fHelp))
3369 return NullUniValue;
3371 if (fHelp || params.size() > 4)
3372 throw runtime_error(
3373 "z_listunspent ( minconf maxconf includeWatchonly [\"zaddr\",...] )\n"
3374 "\nReturns array of unspent shielded notes with between minconf and maxconf (inclusive) confirmations.\n"
3375 "Optionally filter to only include notes sent to specified addresses.\n"
3376 "When minconf is 0, unspent notes with zero confirmations are returned, even though they are not immediately spendable.\n"
3377 "Results are an array of Objects, each of which has:\n"
3378 "{txid, jsindex, jsoutindex, confirmations, address, amount, memo} (Sprout)\n"
3379 "{txid, outindex, confirmations, address, amount, memo} (Sapling)\n"
3381 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
3382 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
3383 "3. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n"
3384 "4. \"addresses\" (string) A json array of zaddrs (both Sprout and Sapling) to filter on. Duplicate addresses not allowed.\n"
3386 " \"address\" (string) zaddr\n"
3390 "[ (array of json object)\n"
3392 " \"txid\" : \"txid\", (string) the transaction id \n"
3393 " \"jsindex\" (sprout) : n, (numeric) the joinsplit index\n"
3394 " \"jsoutindex\" (sprout) : n, (numeric) the output index of the joinsplit\n"
3395 " \"outindex\" (sapling) : n, (numeric) the output index\n"
3396 " \"confirmations\" : n, (numeric) the number of confirmations\n"
3397 " \"spendable\" : true|false, (boolean) true if note can be spent by wallet, false if address is watchonly\n"
3398 " \"address\" : \"address\", (string) the shielded address\n"
3399 " \"amount\": xxxxx, (numeric) the amount of value in the note\n"
3400 " \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
3401 " \"change\": true|false, (boolean) true if the address that received the note is also one of the sending addresses\n"
3407 + HelpExampleCli("z_listunspent", "")
3408 + HelpExampleCli("z_listunspent", "6 9999999 false \"[\\\"ztbx5DLDxa5ZLFTchHhoPNkKs57QzSyib6UqXpEdy76T1aUdFxJt1w9318Z8DJ73XzbnWHKEZP9Yjg712N5kMmP4QzS9iC9\\\",\\\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\\\"]\"")
3409 + HelpExampleRpc("z_listunspent", "6 9999999 false \"[\\\"ztbx5DLDxa5ZLFTchHhoPNkKs57QzSyib6UqXpEdy76T1aUdFxJt1w9318Z8DJ73XzbnWHKEZP9Yjg712N5kMmP4QzS9iC9\\\",\\\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\\\"]\"")
3412 RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VBOOL)(UniValue::VARR));
3415 if (params.size() > 0) {
3416 nMinDepth = params[0].get_int();
3418 if (nMinDepth < 0) {
3419 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3422 int nMaxDepth = 9999999;
3423 if (params.size() > 1) {
3424 nMaxDepth = params[1].get_int();
3426 if (nMaxDepth < nMinDepth) {
3427 throw JSONRPCError(RPC_INVALID_PARAMETER, "Maximum number of confirmations must be greater or equal to the minimum number of confirmations");
3430 std::set<libzcash::PaymentAddress> zaddrs = {};
3432 bool fIncludeWatchonly = false;
3433 if (params.size() > 2) {
3434 fIncludeWatchonly = params[2].get_bool();
3437 LOCK2(cs_main, pwalletMain->cs_wallet);
3439 // User has supplied zaddrs to filter on
3440 if (params.size() > 3) {
3441 UniValue addresses = params[3].get_array();
3442 if (addresses.size()==0)
3443 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, addresses array is empty.");
3445 // Keep track of addresses to spot duplicates
3446 set<std::string> setAddress;
3449 for (const UniValue& o : addresses.getValues()) {
3451 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
3453 string address = o.get_str();
3454 auto zaddr = DecodePaymentAddress(address);
3455 if (!IsValidPaymentAddress(zaddr)) {
3456 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, address is not a valid zaddr: ") + address);
3458 auto hasSpendingKey = boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr);
3459 if (!fIncludeWatchonly && !hasSpendingKey) {
3460 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, spending key for address does not belong to wallet: ") + address);
3462 zaddrs.insert(zaddr);
3464 if (setAddress.count(address)) {
3465 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + address);
3467 setAddress.insert(address);
3471 // User did not provide zaddrs, so use default i.e. all addresses
3472 std::set<libzcash::SproutPaymentAddress> sproutzaddrs = {};
3473 pwalletMain->GetSproutPaymentAddresses(sproutzaddrs);
3476 std::set<libzcash::SaplingPaymentAddress> saplingzaddrs = {};
3477 pwalletMain->GetSaplingPaymentAddresses(saplingzaddrs);
3479 zaddrs.insert(sproutzaddrs.begin(), sproutzaddrs.end());
3480 zaddrs.insert(saplingzaddrs.begin(), saplingzaddrs.end());
3483 UniValue results(UniValue::VARR);
3485 if (zaddrs.size() > 0) {
3486 std::vector<SproutNoteEntry> sproutEntries;
3487 std::vector<SaplingNoteEntry> saplingEntries;
3488 pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs, nMinDepth, nMaxDepth, true, !fIncludeWatchonly, false);
3489 std::set<std::pair<PaymentAddress, uint256>> nullifierSet = pwalletMain->GetNullifiersForAddresses(zaddrs);
3491 for (auto & entry : sproutEntries) {
3492 UniValue obj(UniValue::VOBJ);
3493 obj.push_back(Pair("txid", entry.jsop.hash.ToString()));
3494 obj.push_back(Pair("jsindex", (int)entry.jsop.js ));
3495 obj.push_back(Pair("jsoutindex", (int)entry.jsop.n));
3496 obj.push_back(Pair("confirmations", entry.confirmations));
3497 bool hasSproutSpendingKey = pwalletMain->HaveSproutSpendingKey(boost::get<libzcash::SproutPaymentAddress>(entry.address));
3498 obj.push_back(Pair("spendable", hasSproutSpendingKey));
3499 obj.push_back(Pair("address", EncodePaymentAddress(entry.address)));
3500 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.note.value()))));
3501 std::string data(entry.memo.begin(), entry.memo.end());
3502 obj.push_back(Pair("memo", HexStr(data)));
3503 if (hasSproutSpendingKey) {
3504 obj.push_back(Pair("change", pwalletMain->IsNoteSproutChange(nullifierSet, entry.address, entry.jsop)));
3506 results.push_back(obj);
3509 for (auto & entry : saplingEntries) {
3510 UniValue obj(UniValue::VOBJ);
3511 obj.push_back(Pair("txid", entry.op.hash.ToString()));
3512 obj.push_back(Pair("outindex", (int)entry.op.n));
3513 obj.push_back(Pair("confirmations", entry.confirmations));
3514 libzcash::SaplingIncomingViewingKey ivk;
3515 libzcash::SaplingFullViewingKey fvk;
3516 pwalletMain->GetSaplingIncomingViewingKey(boost::get<libzcash::SaplingPaymentAddress>(entry.address), ivk);
3517 pwalletMain->GetSaplingFullViewingKey(ivk, fvk);
3518 bool hasSaplingSpendingKey = pwalletMain->HaveSaplingSpendingKey(fvk);
3519 obj.push_back(Pair("spendable", hasSaplingSpendingKey));
3520 obj.push_back(Pair("address", EncodePaymentAddress(entry.address)));
3521 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.note.value())))); // note.value() is equivalent to plaintext.value()
3522 obj.push_back(Pair("memo", HexStr(entry.memo)));
3523 if (hasSaplingSpendingKey) {
3524 obj.push_back(Pair("change", pwalletMain->IsNoteSaplingChange(nullifierSet, entry.address, entry.op)));
3526 results.push_back(obj);
3534 UniValue fundrawtransaction(const UniValue& params, bool fHelp)
3536 if (!EnsureWalletIsAvailable(fHelp))
3537 return NullUniValue;
3539 if (fHelp || params.size() != 1)
3540 throw runtime_error(
3541 "fundrawtransaction \"hexstring\"\n"
3542 "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
3543 "This will not modify existing inputs, and will add one change output to the outputs.\n"
3544 "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
3545 "The inputs added will not be signed, use signrawtransaction for that.\n"
3547 "1. \"hexstring\" (string, required) The hex string of the raw transaction\n"
3550 " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
3551 " \"fee\": n, (numeric) The fee added to the transaction\n"
3552 " \"changepos\": n (numeric) The position of the added change output, or -1\n"
3556 "\nCreate a transaction with no inputs\n"
3557 + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
3558 "\nAdd sufficient unsigned inputs to meet the output value\n"
3559 + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
3560 "\nSign the transaction\n"
3561 + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
3562 "\nSend the transaction\n"
3563 + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
3566 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
3568 // parse hex string from parameter
3569 CTransaction origTx;
3570 if (!DecodeHexTx(origTx, params[0].get_str()))
3571 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
3573 CMutableTransaction tx(origTx);
3575 string strFailReason;
3576 int nChangePos = -1;
3577 if(!pwalletMain->FundTransaction(tx, nFee, nChangePos, strFailReason))
3578 throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
3580 UniValue result(UniValue::VOBJ);
3581 result.push_back(Pair("hex", EncodeHexTx(tx)));
3582 result.push_back(Pair("changepos", nChangePos));
3583 result.push_back(Pair("fee", ValueFromAmount(nFee)));
3588 UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp)
3591 throw runtime_error(
3592 "zcsamplejoinsplit\n"
3594 "Perform a joinsplit and return the JSDescription.\n"
3600 uint256 joinSplitPubKey;
3601 uint256 anchor = SproutMerkleTree().root();
3602 JSDescription samplejoinsplit(true,
3606 {JSInput(), JSInput()},
3607 {JSOutput(), JSOutput()},
3611 CDataStream ss(SER_NETWORK, SAPLING_TX_VERSION | (1 << 31));
3612 ss << samplejoinsplit;
3614 return HexStr(ss.begin(), ss.end());
3617 UniValue zc_benchmark(const UniValue& params, bool fHelp)
3619 if (!EnsureWalletIsAvailable(fHelp)) {
3620 return NullUniValue;
3623 if (fHelp || params.size() < 2) {
3624 throw runtime_error(
3625 "zcbenchmark benchmarktype samplecount\n"
3627 "Runs a benchmark of the selected type samplecount times,\n"
3628 "returning the running times of each sample.\n"
3632 " \"runningtime\": runningtime\n"
3635 " \"runningtime\": runningtime\n"
3644 std::string benchmarktype = params[0].get_str();
3645 int samplecount = params[1].get_int();
3647 if (samplecount <= 0) {
3648 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount");
3651 std::vector<double> sample_times;
3653 JSDescription samplejoinsplit;
3655 if (benchmarktype == "verifyjoinsplit") {
3656 CDataStream ss(ParseHexV(params[2].get_str(), "js"), SER_NETWORK, SAPLING_TX_VERSION | (1 << 31));
3657 ss >> samplejoinsplit;
3660 for (int i = 0; i < samplecount; i++) {
3661 if (benchmarktype == "sleep") {
3662 sample_times.push_back(benchmark_sleep());
3663 } else if (benchmarktype == "parameterloading") {
3664 sample_times.push_back(benchmark_parameter_loading());
3665 } else if (benchmarktype == "createjoinsplit") {
3666 if (params.size() < 3) {
3667 sample_times.push_back(benchmark_create_joinsplit());
3669 int nThreads = params[2].get_int();
3670 std::vector<double> vals = benchmark_create_joinsplit_threaded(nThreads);
3671 // Divide by nThreads^2 to get average seconds per JoinSplit because
3672 // we are running one JoinSplit per thread.
3673 sample_times.push_back(std::accumulate(vals.begin(), vals.end(), 0.0) / (nThreads*nThreads));
3675 } else if (benchmarktype == "verifyjoinsplit") {
3676 sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
3677 #ifdef ENABLE_MINING
3678 } else if (benchmarktype == "solveequihash") {
3679 if (params.size() < 3) {
3680 sample_times.push_back(benchmark_solve_equihash());
3682 int nThreads = params[2].get_int();
3683 std::vector<double> vals = benchmark_solve_equihash_threaded(nThreads);
3684 sample_times.insert(sample_times.end(), vals.begin(), vals.end());
3687 } else if (benchmarktype == "verifyequihash") {
3688 sample_times.push_back(benchmark_verify_equihash());
3689 } else if (benchmarktype == "validatelargetx") {
3690 // Number of inputs in the spending transaction that we will simulate
3691 int nInputs = 11130;
3692 if (params.size() >= 3) {
3693 nInputs = params[2].get_int();
3695 sample_times.push_back(benchmark_large_tx(nInputs));
3696 } else if (benchmarktype == "trydecryptnotes") {
3697 int nKeys = params[2].get_int();
3698 sample_times.push_back(benchmark_try_decrypt_sprout_notes(nKeys));
3699 } else if (benchmarktype == "trydecryptsaplingnotes") {
3700 int nKeys = params[2].get_int();
3701 sample_times.push_back(benchmark_try_decrypt_sapling_notes(nKeys));
3702 } else if (benchmarktype == "incnotewitnesses") {
3703 int nTxs = params[2].get_int();
3704 sample_times.push_back(benchmark_increment_sprout_note_witnesses(nTxs));
3705 } else if (benchmarktype == "incsaplingnotewitnesses") {
3706 int nTxs = params[2].get_int();
3707 sample_times.push_back(benchmark_increment_sapling_note_witnesses(nTxs));
3708 } else if (benchmarktype == "connectblockslow") {
3709 if (Params().NetworkIDString() != "regtest") {
3710 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
3712 sample_times.push_back(benchmark_connectblock_slow());
3713 } else if (benchmarktype == "sendtoaddress") {
3714 if (Params().NetworkIDString() != "regtest") {
3715 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
3717 auto amount = AmountFromValue(params[2]);
3718 sample_times.push_back(benchmark_sendtoaddress(amount));
3719 } else if (benchmarktype == "loadwallet") {
3720 if (Params().NetworkIDString() != "regtest") {
3721 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
3723 sample_times.push_back(benchmark_loadwallet());
3724 } else if (benchmarktype == "listunspent") {
3725 sample_times.push_back(benchmark_listunspent());
3726 } else if (benchmarktype == "createsaplingspend") {
3727 sample_times.push_back(benchmark_create_sapling_spend());
3728 } else if (benchmarktype == "createsaplingoutput") {
3729 sample_times.push_back(benchmark_create_sapling_output());
3730 } else if (benchmarktype == "verifysaplingspend") {
3731 sample_times.push_back(benchmark_verify_sapling_spend());
3732 } else if (benchmarktype == "verifysaplingoutput") {
3733 sample_times.push_back(benchmark_verify_sapling_output());
3735 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
3739 UniValue results(UniValue::VARR);
3740 for (auto time : sample_times) {
3741 UniValue result(UniValue::VOBJ);
3742 result.push_back(Pair("runningtime", time));
3743 results.push_back(result);
3749 UniValue zc_raw_receive(const UniValue& params, bool fHelp)
3751 if (!EnsureWalletIsAvailable(fHelp)) {
3752 return NullUniValue;
3755 if (fHelp || params.size() != 2) {
3756 throw runtime_error(
3757 "zcrawreceive zcsecretkey encryptednote\n"
3759 "DEPRECATED. Decrypts encryptednote and checks if the coin commitments\n"
3760 "are in the blockchain as indicated by the \"exists\" result.\n"
3763 " \"amount\": value,\n"
3764 " \"note\": noteplaintext,\n"
3765 " \"exists\": exists\n"
3770 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR));
3774 auto spendingkey = DecodeSpendingKey(params[0].get_str());
3775 if (!IsValidSpendingKey(spendingkey)) {
3776 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
3778 if (boost::get<libzcash::SproutSpendingKey>(&spendingkey) == nullptr) {
3779 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout spending keys");
3781 SproutSpendingKey k = boost::get<libzcash::SproutSpendingKey>(spendingkey);
3784 unsigned char nonce;
3785 ZCNoteEncryption::Ciphertext ct;
3789 CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
3795 } catch(const std::exception &) {
3796 throw runtime_error(
3797 "encrypted_note could not be decoded"
3802 ZCNoteDecryption decryptor(k.receiving_key());
3804 SproutNotePlaintext npt = SproutNotePlaintext::decrypt(
3811 SproutPaymentAddress payment_addr = k.address();
3812 SproutNote decrypted_note = npt.note(payment_addr);
3814 assert(pwalletMain != NULL);
3815 std::vector<boost::optional<SproutWitness>> witnesses;
3817 uint256 commitment = decrypted_note.cm();
3818 pwalletMain->WitnessNoteCommitment(
3824 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
3827 UniValue result(UniValue::VOBJ);
3828 result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value())));
3829 result.push_back(Pair("note", HexStr(ss.begin(), ss.end())));
3830 result.push_back(Pair("exists", (bool) witnesses[0]));
3836 UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
3838 if (!EnsureWalletIsAvailable(fHelp)) {
3839 return NullUniValue;
3842 if (fHelp || params.size() != 5) {
3843 throw runtime_error(
3844 "zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
3845 " inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
3846 " outputs: a JSON object mapping {zcaddr: value, ...}\n"
3848 "DEPRECATED. Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
3849 "Outputs are confidential between sender/receiver. The vpub_old and\n"
3850 "vpub_new values are globally public and move transparent value into\n"
3851 "or out of the confidential value store, respectively.\n"
3853 "Note: The caller is responsible for delivering the output enc1 and\n"
3854 "enc2 to the appropriate recipients, as well as signing rawtxout and\n"
3855 "ensuring it is mined. (A future RPC call will deliver the confidential\n"
3856 "payments in-band on the blockchain.)\n"
3859 " \"encryptednote1\": enc1,\n"
3860 " \"encryptednote2\": enc2,\n"
3861 " \"rawtxn\": rawtxout\n"
3869 if (!DecodeHexTx(tx, params[0].get_str()))
3870 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
3872 UniValue inputs = params[1].get_obj();
3873 UniValue outputs = params[2].get_obj();
3875 CAmount vpub_old(0);
3876 CAmount vpub_new(0);
3878 if (params[3].get_real() != 0.0)
3879 vpub_old = AmountFromValue(params[3]);
3881 if (params[4].get_real() != 0.0)
3882 vpub_new = AmountFromValue(params[4]);
3884 std::vector<JSInput> vjsin;
3885 std::vector<JSOutput> vjsout;
3886 std::vector<SproutNote> notes;
3887 std::vector<SproutSpendingKey> keys;
3888 std::vector<uint256> commitments;
3890 for (const string& name_ : inputs.getKeys()) {
3891 auto spendingkey = DecodeSpendingKey(inputs[name_].get_str());
3892 if (!IsValidSpendingKey(spendingkey)) {
3893 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
3895 if (boost::get<libzcash::SproutSpendingKey>(&spendingkey) == nullptr) {
3896 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout spending keys");
3898 SproutSpendingKey k = boost::get<libzcash::SproutSpendingKey>(spendingkey);
3902 SproutNotePlaintext npt;
3905 CDataStream ssData(ParseHexV(name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
3909 SproutPaymentAddress addr = k.address();
3910 SproutNote note = npt.note(addr);
3911 notes.push_back(note);
3912 commitments.push_back(note.cm());
3916 std::vector<boost::optional<SproutWitness>> witnesses;
3917 pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
3919 assert(witnesses.size() == notes.size());
3920 assert(notes.size() == keys.size());
3923 for (size_t i = 0; i < witnesses.size(); i++) {
3924 if (!witnesses[i]) {
3925 throw runtime_error(
3926 "joinsplit input could not be found in tree"
3930 vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
3934 while (vjsin.size() < ZC_NUM_JS_INPUTS) {
3935 vjsin.push_back(JSInput());
3938 for (const string& name_ : outputs.getKeys()) {
3939 auto addrTo = DecodePaymentAddress(name_);
3940 if (!IsValidPaymentAddress(addrTo)) {
3941 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid recipient address.");
3943 if (boost::get<libzcash::SproutPaymentAddress>(&addrTo) == nullptr) {
3944 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout payment addresses");
3946 CAmount nAmount = AmountFromValue(outputs[name_]);
3948 vjsout.push_back(JSOutput(boost::get<libzcash::SproutPaymentAddress>(addrTo), nAmount));
3951 while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
3952 vjsout.push_back(JSOutput());
3956 if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
3957 throw runtime_error("unsupported joinsplit input/output counts");
3960 uint256 joinSplitPubKey;
3961 unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
3962 crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
3964 CMutableTransaction mtx(tx);
3966 mtx.joinSplitPubKey = joinSplitPubKey;
3968 JSDescription jsdesc(false,
3972 {vjsin[0], vjsin[1]},
3973 {vjsout[0], vjsout[1]},
3978 auto verifier = libzcash::ProofVerifier::Strict();
3979 assert(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey));
3982 mtx.vJoinSplit.push_back(jsdesc);
3984 // Empty output script.
3986 CTransaction signTx(mtx);
3987 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
3988 uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
3990 // Add the signature
3991 assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
3992 dataToBeSigned.begin(), 32,
3997 assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
3998 dataToBeSigned.begin(), 32,
3999 mtx.joinSplitPubKey.begin()
4002 CTransaction rawTx(mtx);
4004 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
4007 std::string encryptedNote1;
4008 std::string encryptedNote2;
4010 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
4011 ss2 << ((unsigned char) 0x00);
4012 ss2 << jsdesc.ephemeralKey;
4013 ss2 << jsdesc.ciphertexts[0];
4014 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
4016 encryptedNote1 = HexStr(ss2.begin(), ss2.end());
4019 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
4020 ss2 << ((unsigned char) 0x01);
4021 ss2 << jsdesc.ephemeralKey;
4022 ss2 << jsdesc.ciphertexts[1];
4023 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
4025 encryptedNote2 = HexStr(ss2.begin(), ss2.end());
4028 UniValue result(UniValue::VOBJ);
4029 result.push_back(Pair("encryptednote1", encryptedNote1));
4030 result.push_back(Pair("encryptednote2", encryptedNote2));
4031 result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
4035 UniValue zc_raw_keygen(const UniValue& params, bool fHelp)
4037 if (!EnsureWalletIsAvailable(fHelp)) {
4038 return NullUniValue;
4041 if (fHelp || params.size() != 0) {
4042 throw runtime_error(
4045 "DEPRECATED. Generate a zcaddr which can send and receive confidential values.\n"
4048 " \"zcaddress\": zcaddr,\n"
4049 " \"zcsecretkey\": zcsecretkey,\n"
4050 " \"zcviewingkey\": zcviewingkey,\n"
4055 auto k = SproutSpendingKey::random();
4056 auto addr = k.address();
4057 auto viewing_key = k.viewing_key();
4059 UniValue result(UniValue::VOBJ);
4060 result.push_back(Pair("zcaddress", EncodePaymentAddress(addr)));
4061 result.push_back(Pair("zcsecretkey", EncodeSpendingKey(k)));
4062 result.push_back(Pair("zcviewingkey", EncodeViewingKey(viewing_key)));
4067 UniValue z_getnewaddress(const UniValue& params, bool fHelp)
4069 if (!EnsureWalletIsAvailable(fHelp))
4070 return NullUniValue;
4072 std::string defaultType = ADDR_TYPE_SAPLING;
4074 if (fHelp || params.size() > 1)
4075 throw runtime_error(
4076 "z_getnewaddress ( type )\n"
4077 "\nReturns a new shielded address for receiving payments.\n"
4078 "\nWith no arguments, returns a Sapling address.\n"
4080 "1. \"type\" (string, optional, default=\"" + defaultType + "\") The type of address. One of [\""
4081 + ADDR_TYPE_SPROUT + "\", \"" + ADDR_TYPE_SAPLING + "\"].\n"
4083 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) The new shielded address.\n"
4085 + HelpExampleCli("z_getnewaddress", "")
4086 + HelpExampleCli("z_getnewaddress", ADDR_TYPE_SAPLING)
4087 + HelpExampleRpc("z_getnewaddress", "")
4090 LOCK2(cs_main, pwalletMain->cs_wallet);
4092 EnsureWalletIsUnlocked();
4094 auto addrType = defaultType;
4095 if (params.size() > 0) {
4096 addrType = params[0].get_str();
4099 if (addrType == ADDR_TYPE_SPROUT) {
4100 return EncodePaymentAddress(pwalletMain->GenerateNewSproutZKey());
4101 } else if (addrType == ADDR_TYPE_SAPLING) {
4102 return EncodePaymentAddress(pwalletMain->GenerateNewSaplingZKey());
4104 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid address type");
4109 UniValue z_listaddresses(const UniValue& params, bool fHelp)
4111 if (!EnsureWalletIsAvailable(fHelp))
4112 return NullUniValue;
4114 if (fHelp || params.size() > 1)
4115 throw runtime_error(
4116 "z_listaddresses ( includeWatchonly )\n"
4117 "\nReturns the list of Sprout and Sapling shielded addresses belonging to the wallet.\n"
4119 "1. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n"
4121 "[ (json array of string)\n"
4122 " \"zaddr\" (string) a zaddr belonging to the wallet\n"
4126 + HelpExampleCli("z_listaddresses", "")
4127 + HelpExampleRpc("z_listaddresses", "")
4130 LOCK2(cs_main, pwalletMain->cs_wallet);
4132 bool fIncludeWatchonly = false;
4133 if (params.size() > 0) {
4134 fIncludeWatchonly = params[0].get_bool();
4137 UniValue ret(UniValue::VARR);
4139 std::set<libzcash::SproutPaymentAddress> addresses;
4140 pwalletMain->GetSproutPaymentAddresses(addresses);
4141 for (auto addr : addresses) {
4142 if (fIncludeWatchonly || pwalletMain->HaveSproutSpendingKey(addr)) {
4143 ret.push_back(EncodePaymentAddress(addr));
4148 std::set<libzcash::SaplingPaymentAddress> addresses;
4149 pwalletMain->GetSaplingPaymentAddresses(addresses);
4150 libzcash::SaplingIncomingViewingKey ivk;
4151 libzcash::SaplingFullViewingKey fvk;
4152 for (auto addr : addresses) {
4153 if (fIncludeWatchonly || (
4154 pwalletMain->GetSaplingIncomingViewingKey(addr, ivk) &&
4155 pwalletMain->GetSaplingFullViewingKey(ivk, fvk) &&
4156 pwalletMain->HaveSaplingSpendingKey(fvk)
4158 ret.push_back(EncodePaymentAddress(addr));
4165 CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ignoreUnspendable=true) {
4166 std::set<CTxDestination> destinations;
4167 vector<COutput> vecOutputs;
4168 CAmount balance = 0;
4170 if (transparentAddress.length() > 0) {
4171 CTxDestination taddr = DecodeDestination(transparentAddress);
4172 if (!IsValidDestination(taddr)) {
4173 throw std::runtime_error("invalid transparent address");
4175 destinations.insert(taddr);
4178 LOCK2(cs_main, pwalletMain->cs_wallet);
4180 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
4182 BOOST_FOREACH(const COutput& out, vecOutputs) {
4183 if (out.nDepth < minDepth) {
4187 if (ignoreUnspendable && !out.fSpendable) {
4191 if (destinations.size()) {
4192 CTxDestination address;
4193 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
4197 if (!destinations.count(address)) {
4202 CAmount nValue = out.tx->vout[out.i].nValue; // komodo_interest
4208 CAmount getBalanceZaddr(std::string address, int minDepth = 1, bool ignoreUnspendable=true) {
4209 CAmount balance = 0;
4210 std::vector<SproutNoteEntry> sproutEntries;
4211 std::vector<SaplingNoteEntry> saplingEntries;
4212 LOCK2(cs_main, pwalletMain->cs_wallet);
4213 pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, address, minDepth, true, ignoreUnspendable);
4214 for (auto & entry : sproutEntries) {
4215 balance += CAmount(entry.note.value());
4217 for (auto & entry : saplingEntries) {
4218 balance += CAmount(entry.note.value());
4224 UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
4226 if (!EnsureWalletIsAvailable(fHelp))
4227 return NullUniValue;
4229 if (fHelp || params.size()==0 || params.size() >2)
4230 throw runtime_error(
4231 "z_listreceivedbyaddress \"address\" ( minconf )\n"
4232 "\nReturn a list of amounts received by a zaddr belonging to the node's wallet.\n"
4234 "1. \"address\" (string) The private address.\n"
4235 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
4238 " \"txid\": \"txid\", (string) the transaction id\n"
4239 " \"amount\": xxxxx, (numeric) the amount of value in the note\n"
4240 " \"memo\": xxxxx, (string) hexadecimal string representation of memo field\n"
4241 " \"jsindex\" (sprout) : n, (numeric) the joinsplit index\n"
4242 " \"jsoutindex\" (sprout) : n, (numeric) the output index of the joinsplit\n"
4243 " \"outindex\" (sapling) : n, (numeric) the output index\n"
4244 " \"change\": true|false, (boolean) true if the address that received the note is also one of the sending addresses\n"
4247 + HelpExampleCli("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
4248 + HelpExampleRpc("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
4251 LOCK2(cs_main, pwalletMain->cs_wallet);
4254 if (params.size() > 1) {
4255 nMinDepth = params[1].get_int();
4257 if (nMinDepth < 0) {
4258 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
4261 // Check that the from address is valid.
4262 auto fromaddress = params[0].get_str();
4264 auto zaddr = DecodePaymentAddress(fromaddress);
4265 if (!IsValidPaymentAddress(zaddr)) {
4266 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
4269 // Visitor to support Sprout and Sapling addrs
4270 if (!boost::apply_visitor(PaymentAddressBelongsToWallet(pwalletMain), zaddr)) {
4271 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
4274 UniValue result(UniValue::VARR);
4275 std::vector<SproutNoteEntry> sproutEntries;
4276 std::vector<SaplingNoteEntry> saplingEntries;
4277 pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, fromaddress, nMinDepth, false, false);
4279 std::set<std::pair<PaymentAddress, uint256>> nullifierSet;
4280 auto hasSpendingKey = boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr);
4281 if (hasSpendingKey) {
4282 nullifierSet = pwalletMain->GetNullifiersForAddresses({zaddr});
4285 if (boost::get<libzcash::SproutPaymentAddress>(&zaddr) != nullptr) {
4286 for (SproutNoteEntry & entry : sproutEntries) {
4287 UniValue obj(UniValue::VOBJ);
4288 obj.push_back(Pair("txid", entry.jsop.hash.ToString()));
4289 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.note.value()))));
4290 std::string data(entry.memo.begin(), entry.memo.end());
4291 obj.push_back(Pair("memo", HexStr(data)));
4292 obj.push_back(Pair("jsindex", entry.jsop.js));
4293 obj.push_back(Pair("jsoutindex", entry.jsop.n));
4294 if (hasSpendingKey) {
4295 obj.push_back(Pair("change", pwalletMain->IsNoteSproutChange(nullifierSet, entry.address, entry.jsop)));
4297 result.push_back(obj);
4299 } else if (boost::get<libzcash::SaplingPaymentAddress>(&zaddr) != nullptr) {
4300 for (SaplingNoteEntry & entry : saplingEntries) {
4301 UniValue obj(UniValue::VOBJ);
4302 obj.push_back(Pair("txid", entry.op.hash.ToString()));
4303 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.note.value()))));
4304 obj.push_back(Pair("memo", HexStr(entry.memo)));
4305 obj.push_back(Pair("outindex", (int)entry.op.n));
4306 if (hasSpendingKey) {
4307 obj.push_back(Pair("change", pwalletMain->IsNoteSaplingChange(nullifierSet, entry.address, entry.op)));
4309 result.push_back(obj);
4315 UniValue z_getbalance(const UniValue& params, bool fHelp)
4317 if (!EnsureWalletIsAvailable(fHelp))
4318 return NullUniValue;
4320 if (fHelp || params.size()==0 || params.size() >2)
4321 throw runtime_error(
4322 "z_getbalance \"address\" ( minconf )\n"
4323 "\nReturns the balance of a taddr or zaddr belonging to the node's wallet.\n"
4324 "\nCAUTION: If the wallet has only an incoming viewing key for this address, then spends cannot be"
4325 "\ndetected, and so the returned balance may be larger than the actual balance.\n"
4327 "1. \"address\" (string) The selected address. It may be a transparent or private address.\n"
4328 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
4330 "amount (numeric) The total amount in KMD received for this address.\n"
4332 "\nThe total amount received by address \"myaddress\"\n"
4333 + HelpExampleCli("z_getbalance", "\"myaddress\"") +
4334 "\nThe total amount received by address \"myaddress\" at least 5 blocks confirmed\n"
4335 + HelpExampleCli("z_getbalance", "\"myaddress\" 5") +
4336 "\nAs a json rpc call\n"
4337 + HelpExampleRpc("z_getbalance", "\"myaddress\", 5")
4340 LOCK2(cs_main, pwalletMain->cs_wallet);
4343 if (params.size() > 1) {
4344 nMinDepth = params[1].get_int();
4346 if (nMinDepth < 0) {
4347 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
4350 // Check that the from address is valid.
4351 auto fromaddress = params[0].get_str();
4352 bool fromTaddr = false;
4353 CTxDestination taddr = DecodeDestination(fromaddress);
4354 fromTaddr = IsValidDestination(taddr);
4356 auto res = DecodePaymentAddress(fromaddress);
4357 if (!IsValidPaymentAddress(res)) {
4358 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
4360 if (!boost::apply_visitor(PaymentAddressBelongsToWallet(pwalletMain), res)) {
4361 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, spending key or viewing key not found.");
4365 CAmount nBalance = 0;
4367 nBalance = getBalanceTaddr(fromaddress, nMinDepth, false);
4369 nBalance = getBalanceZaddr(fromaddress, nMinDepth, false);
4372 return ValueFromAmount(nBalance);
4376 UniValue z_gettotalbalance(const UniValue& params, bool fHelp)
4378 if (!EnsureWalletIsAvailable(fHelp))
4379 return NullUniValue;
4381 if (fHelp || params.size() > 2)
4382 throw runtime_error(
4383 "z_gettotalbalance ( minconf includeWatchonly )\n"
4384 "\nReturn the total value of funds stored in the node's wallet.\n"
4385 "\nCAUTION: If the wallet contains any addresses for which it only has incoming viewing keys,"
4386 "\nthe returned private balance may be larger than the actual balance, because spends cannot"
4387 "\nbe detected with incoming viewing keys.\n"
4389 "1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
4390 "2. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress' and 'z_importviewingkey')\n"
4393 " \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
4394 " \"private\": xxxxx, (numeric) the total balance of shielded funds (in both Sprout and Sapling addresses)\n"
4395 " \"total\": xxxxx, (numeric) the total balance of both transparent and shielded funds\n"
4398 "\nThe total amount in the wallet\n"
4399 + HelpExampleCli("z_gettotalbalance", "") +
4400 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
4401 + HelpExampleCli("z_gettotalbalance", "5") +
4402 "\nAs a json rpc call\n"
4403 + HelpExampleRpc("z_gettotalbalance", "5")
4406 LOCK2(cs_main, pwalletMain->cs_wallet);
4409 if (params.size() > 0) {
4410 nMinDepth = params[0].get_int();
4412 if (nMinDepth < 0) {
4413 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
4416 bool fIncludeWatchonly = false;
4417 if (params.size() > 1) {
4418 fIncludeWatchonly = params[1].get_bool();
4421 // getbalance and "getbalance * 1 true" should return the same number
4422 // but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
4423 // pwalletMain->GetBalance() does not accept min depth parameter
4424 // so we use our own method to get balance of utxos.
4425 CAmount nBalance = getBalanceTaddr("", nMinDepth, !fIncludeWatchonly);
4426 CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth, !fIncludeWatchonly);
4427 uint64_t interest = komodo_interestsum();
4428 CAmount nTotalBalance = nBalance + nPrivateBalance;
4429 UniValue result(UniValue::VOBJ);
4430 result.push_back(Pair("transparent", FormatMoney(nBalance)));
4431 //result.push_back(Pair("interest", FormatMoney(interest)));
4432 result.push_back(Pair("private", FormatMoney(nPrivateBalance)));
4433 result.push_back(Pair("total", FormatMoney(nTotalBalance)));
4437 UniValue z_viewtransaction(const UniValue& params, bool fHelp)
4439 if (!EnsureWalletIsAvailable(fHelp))
4440 return NullUniValue;
4442 if (fHelp || params.size() != 1)
4443 throw runtime_error(
4444 "z_viewtransaction \"txid\"\n"
4445 "\nGet detailed shielded information about in-wallet transaction <txid>\n"
4447 "1. \"txid\" (string, required) The transaction id\n"
4450 " \"txid\" : \"transactionid\", (string) The transaction id\n"
4453 " \"type\" : \"sprout|sapling\", (string) The type of address\n"
4454 " \"js\" : n, (numeric, sprout) the index of the JSDescription within vJoinSplit\n"
4455 " \"jsSpend\" : n, (numeric, sprout) the index of the spend within the JSDescription\n"
4456 " \"spend\" : n, (numeric, sapling) the index of the spend within vShieldedSpend\n"
4457 " \"txidPrev\" : \"transactionid\", (string) The id for the transaction this note was created in\n"
4458 " \"jsPrev\" : n, (numeric, sprout) the index of the JSDescription within vJoinSplit\n"
4459 " \"jsOutputPrev\" : n, (numeric, sprout) the index of the output within the JSDescription\n"
4460 " \"outputPrev\" : n, (numeric, sapling) the index of the output within the vShieldedOutput\n"
4461 " \"address\" : \"zaddress\", (string) The z address involved in the transaction\n"
4462 " \"value\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n"
4463 " \"valueZat\" : xxxx (numeric) The amount in zatoshis\n"
4467 " \"outputs\" : [\n"
4469 " \"type\" : \"sprout|sapling\", (string) The type of address\n"
4470 " \"js\" : n, (numeric, sprout) the index of the JSDescription within vJoinSplit\n"
4471 " \"jsOutput\" : n, (numeric, sprout) the index of the output within the JSDescription\n"
4472 " \"output\" : n, (numeric, sapling) the index of the output within the vShieldedOutput\n"
4473 " \"address\" : \"address\", (string) The Verus private address involved in the transaction\n"
4474 " \"recovered\" : true|false (boolean, sapling) True if the output is not for an address in the wallet\n"
4475 " \"value\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n"
4476 " \"valueZat\" : xxxx (numeric) The amount in zatoshis\n"
4477 " \"memo\" : \"hexmemo\", (string) Hexademical string representation of the memo field\n"
4478 " \"memoStr\" : \"memo\", (string) Only returned if memo contains valid UTF-8 text.\n"
4485 + HelpExampleCli("z_viewtransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
4486 + HelpExampleRpc("z_viewtransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
4489 LOCK2(cs_main, pwalletMain->cs_wallet);
4492 hash.SetHex(params[0].get_str());
4494 UniValue entry(UniValue::VOBJ);
4495 if (!pwalletMain->mapWallet.count(hash))
4496 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
4497 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
4499 entry.push_back(Pair("txid", hash.GetHex()));
4501 UniValue spends(UniValue::VARR);
4502 UniValue outputs(UniValue::VARR);
4504 // Sprout spends - retained for old sprout addresses and transactions
4505 for (size_t i = 0; i < wtx.vJoinSplit.size(); ++i) {
4506 for (size_t j = 0; j < wtx.vJoinSplit[i].nullifiers.size(); ++j) {
4507 auto nullifier = wtx.vJoinSplit[i].nullifiers[j];
4509 // Fetch the note that is being spent, if ours
4510 auto res = pwalletMain->mapSproutNullifiersToNotes.find(nullifier);
4511 if (res == pwalletMain->mapSproutNullifiersToNotes.end()) {
4514 auto jsop = res->second;
4515 auto wtxPrev = pwalletMain->mapWallet.at(jsop.hash);
4517 auto decrypted = wtxPrev.DecryptSproutNote(jsop);
4518 auto notePt = decrypted.first;
4519 auto pa = decrypted.second;
4521 UniValue entry(UniValue::VOBJ);
4522 entry.push_back(Pair("type", ADDR_TYPE_SPROUT));
4523 entry.push_back(Pair("js", (int)i));
4524 entry.push_back(Pair("jsSpend", (int)j));
4525 entry.push_back(Pair("txidPrev", jsop.hash.GetHex()));
4526 entry.push_back(Pair("jsPrev", (int)jsop.js));
4527 entry.push_back(Pair("jsOutputPrev", (int)jsop.n));
4528 entry.push_back(Pair("address", EncodePaymentAddress(pa)));
4529 entry.push_back(Pair("value", ValueFromAmount(notePt.value())));
4530 entry.push_back(Pair("valueZat", notePt.value()));
4531 outputs.push_back(entry);
4536 for (auto & pair : wtx.mapSproutNoteData) {
4537 JSOutPoint jsop = pair.first;
4539 auto decrypted = wtx.DecryptSproutNote(jsop);
4540 auto notePt = decrypted.first;
4541 auto pa = decrypted.second;
4542 auto memo = notePt.memo();
4544 UniValue entry(UniValue::VOBJ);
4545 entry.push_back(Pair("type", ADDR_TYPE_SPROUT));
4546 entry.push_back(Pair("js", (int)jsop.js));
4547 entry.push_back(Pair("jsOutput", (int)jsop.n));
4548 entry.push_back(Pair("address", EncodePaymentAddress(pa)));
4549 entry.push_back(Pair("value", ValueFromAmount(notePt.value())));
4550 entry.push_back(Pair("valueZat", notePt.value()));
4551 entry.push_back(Pair("memo", HexStr(memo)));
4552 if (memo[0] <= 0xf4) {
4553 auto end = std::find_if(memo.rbegin(), memo.rend(), [](unsigned char v) { return v != 0; });
4554 std::string memoStr(memo.begin(), end.base());
4555 //if (utf8::is_valid(memoStr))
4557 entry.push_back(Pair("memoStr", memoStr));
4560 outputs.push_back(entry);
4564 std::set<uint256> ovks;
4565 for (size_t i = 0; i < wtx.vShieldedSpend.size(); ++i) {
4566 auto spend = wtx.vShieldedSpend[i];
4568 // Fetch teh note that is being spent
4569 auto res = pwalletMain->mapSaplingNullifiersToNotes.find(spend.nullifier);
4570 if (res == pwalletMain->mapSaplingNullifiersToNotes.end()) {
4573 auto op = res->second;
4574 auto wtxPrev = pwalletMain->mapWallet.at(op.hash);
4576 auto decrypted = wtxPrev.DecryptSaplingNote(op).get();
4577 auto notePt = decrypted.first;
4578 auto pa = decrypted.second;
4580 // Store the OutgoingViewingKey for recovering outputs
4581 libzcash::SaplingFullViewingKey fvk;
4582 assert(pwalletMain->GetSaplingFullViewingKey(wtxPrev.mapSaplingNoteData.at(op).ivk, fvk));
4583 ovks.insert(fvk.ovk);
4585 UniValue entry(UniValue::VOBJ);
4586 entry.push_back(Pair("type", ADDR_TYPE_SAPLING));
4587 entry.push_back(Pair("spend", (int)i));
4588 entry.push_back(Pair("txidPrev", op.hash.GetHex()));
4589 entry.push_back(Pair("outputPrev", (int)op.n));
4590 entry.push_back(Pair("address", EncodePaymentAddress(pa)));
4591 entry.push_back(Pair("value", ValueFromAmount(notePt.value())));
4592 entry.push_back(Pair("valueZat", notePt.value()));
4593 spends.push_back(entry);
4597 for (uint32_t i = 0; i < wtx.vShieldedOutput.size(); ++i) {
4598 auto op = SaplingOutPoint(hash, i);
4600 SaplingNotePlaintext notePt;
4601 SaplingPaymentAddress pa;
4604 auto decrypted = wtx.DecryptSaplingNote(op);
4606 notePt = decrypted->first;
4607 pa = decrypted->second;
4608 isRecovered = false;
4610 // Try recovering the output
4611 auto recovered = wtx.RecoverSaplingNote(op, ovks);
4613 notePt = recovered->first;
4614 pa = recovered->second;
4621 auto memo = notePt.memo();
4623 UniValue entry(UniValue::VOBJ);
4624 entry.push_back(Pair("type", ADDR_TYPE_SAPLING));
4625 entry.push_back(Pair("output", (int)op.n));
4626 entry.push_back(Pair("recovered", isRecovered));
4627 entry.push_back(Pair("address", EncodePaymentAddress(pa)));
4628 entry.push_back(Pair("value", ValueFromAmount(notePt.value())));
4629 entry.push_back(Pair("valueZat", notePt.value()));
4630 entry.push_back(Pair("memo", HexStr(memo)));
4631 if (memo[0] <= 0xf4) {
4632 auto end = std::find_if(memo.rbegin(), memo.rend(), [](unsigned char v) { return v != 0; });
4633 std::string memoStr(memo.begin(), end.base());
4634 //if (utf8::is_valid(memoStr))
4636 entry.push_back(Pair("memoStr", memoStr));
4639 outputs.push_back(entry);
4642 entry.push_back(Pair("spends", spends));
4643 entry.push_back(Pair("outputs", outputs));
4648 UniValue z_getoperationresult(const UniValue& params, bool fHelp)
4650 if (!EnsureWalletIsAvailable(fHelp))
4651 return NullUniValue;
4653 if (fHelp || params.size() > 1)
4654 throw runtime_error(
4655 "z_getoperationresult ([\"operationid\", ... ]) \n"
4656 "\nRetrieve the result and status of an operation which has finished, and then remove the operation from memory."
4657 + HelpRequiringPassphrase() + "\n"
4659 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
4661 "\" [object, ...]\" (array) A list of JSON objects\n"
4663 + HelpExampleCli("z_getoperationresult", "'[\"operationid\", ... ]'")
4664 + HelpExampleRpc("z_getoperationresult", "'[\"operationid\", ... ]'")
4667 // This call will remove finished operations
4668 return z_getoperationstatus_IMPL(params, true);
4671 UniValue z_getoperationstatus(const UniValue& params, bool fHelp)
4673 if (!EnsureWalletIsAvailable(fHelp))
4674 return NullUniValue;
4676 if (fHelp || params.size() > 1)
4677 throw runtime_error(
4678 "z_getoperationstatus ([\"operationid\", ... ]) \n"
4679 "\nGet operation status and any associated result or error data. The operation will remain in memory."
4680 + HelpRequiringPassphrase() + "\n"
4682 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
4684 "\" [object, ...]\" (array) A list of JSON objects\n"
4686 + HelpExampleCli("z_getoperationstatus", "'[\"operationid\", ... ]'")
4687 + HelpExampleRpc("z_getoperationstatus", "'[\"operationid\", ... ]'")
4690 // This call is idempotent so we don't want to remove finished operations
4691 return z_getoperationstatus_IMPL(params, false);
4694 UniValue z_getoperationstatus_IMPL(const UniValue& params, bool fRemoveFinishedOperations=false)
4696 LOCK2(cs_main, pwalletMain->cs_wallet);
4698 std::set<AsyncRPCOperationId> filter;
4699 if (params.size()==1) {
4700 UniValue ids = params[0].get_array();
4701 for (const UniValue & v : ids.getValues()) {
4702 filter.insert(v.get_str());
4705 bool useFilter = (filter.size()>0);
4707 UniValue ret(UniValue::VARR);
4708 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4709 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
4711 for (auto id : ids) {
4712 if (useFilter && !filter.count(id))
4715 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
4718 // It's possible that the operation was removed from the internal queue and map during this loop
4719 // throw JSONRPCError(RPC_INVALID_PARAMETER, "No operation exists for that id.");
4722 UniValue obj = operation->getStatus();
4723 std::string s = obj["status"].get_str();
4724 if (fRemoveFinishedOperations) {
4725 // Caller is only interested in retrieving finished results
4726 if ("success"==s || "failed"==s || "cancelled"==s) {
4728 q->popOperationForId(id);
4735 std::vector<UniValue> arrTmp = ret.getValues();
4737 // sort results chronologically by creation_time
4738 std::sort(arrTmp.begin(), arrTmp.end(), [](UniValue a, UniValue b) -> bool {
4739 const int64_t t1 = find_value(a.get_obj(), "creation_time").get_int64();
4740 const int64_t t2 = find_value(b.get_obj(), "creation_time").get_int64();
4746 ret.push_backV(arrTmp);
4752 // JSDescription size depends on the transaction version
4753 #define V3_JS_DESCRIPTION_SIZE (GetSerializeSize(JSDescription(), SER_NETWORK, (OVERWINTER_TX_VERSION | (1 << 31))))
4754 // Here we define the maximum number of zaddr outputs that can be included in a transaction.
4755 // If input notes are small, we might actually require more than one joinsplit per zaddr output.
4756 // For now though, we assume we use one joinsplit per zaddr output (and the second output note is change).
4757 // We reduce the result by 1 to ensure there is room for non-joinsplit CTransaction data.
4758 #define Z_SENDMANY_MAX_ZADDR_OUTPUTS_BEFORE_SAPLING ((MAX_TX_SIZE_BEFORE_SAPLING / V3_JS_DESCRIPTION_SIZE) - 1)
4760 // transaction.h comment: spending taddr output requires CTxIn >= 148 bytes and typical taddr txout is 34 bytes
4761 #define CTXIN_SPEND_DUST_SIZE 148
4762 #define CTXOUT_REGULAR_SIZE 34
4764 UniValue z_sendmany(const UniValue& params, bool fHelp)
4766 if (!EnsureWalletIsAvailable(fHelp))
4767 return NullUniValue;
4769 if (fHelp || params.size() < 2 || params.size() > 4)
4770 throw runtime_error(
4771 "z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee )\n"
4772 "\nSend multiple times. Amounts are decimal numbers with at most 8 digits of precision."
4773 "\nChange generated from a taddr flows to a new taddr address, while change generated from a zaddr returns to itself."
4774 "\nWhen sending coinbase UTXOs to a zaddr, change is not allowed. The entire value of the UTXO(s) must be consumed."
4775 + strprintf("\nBefore Sapling activates, the maximum number of zaddr outputs is %d due to transaction size limits.\n", Z_SENDMANY_MAX_ZADDR_OUTPUTS_BEFORE_SAPLING)
4776 + HelpRequiringPassphrase() + "\n"
4778 "1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from.\n"
4779 "2. \"amounts\" (array, required) An array of json objects representing the amounts to send.\n"
4781 " \"address\":address (string, required) The address is a taddr or zaddr\n"
4782 " \"amount\":amount (numeric, required) The numeric amount in KMD is the value\n"
4783 " \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
4785 "3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
4786 "4. fee (numeric, optional, default="
4787 + strprintf("%s", FormatMoney(ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
4789 "\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
4791 + HelpExampleCli("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" '[{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]'")
4792 + HelpExampleRpc("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", [{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]")
4795 LOCK2(cs_main, pwalletMain->cs_wallet);
4797 // Check that the from address is valid.
4798 auto fromaddress = params[0].get_str();
4799 bool fromTaddr = false;
4800 bool fromSapling = false;
4802 uint32_t branchId = CurrentEpochBranchId(chainActive.Height(), Params().GetConsensus());
4804 CTxDestination taddr = DecodeDestination(fromaddress);
4805 fromTaddr = IsValidDestination(taddr);
4807 auto res = DecodePaymentAddress(fromaddress);
4808 if (!IsValidPaymentAddress(res, branchId)) {
4810 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
4813 // Check that we have the spending key
4814 if (!boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), res)) {
4815 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
4818 // Remember whether this is a Sprout or Sapling address
4819 fromSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
4821 // This logic will need to be updated if we add a new shielded pool
4822 bool fromSprout = !(fromTaddr || fromSapling);
4824 UniValue outputs = params[1].get_array();
4826 if (outputs.size()==0)
4827 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
4829 // Keep track of addresses to spot duplicates
4830 set<std::string> setAddress;
4832 // Track whether we see any Sprout addresses
4833 bool noSproutAddrs = !fromSprout;
4836 std::vector<SendManyRecipient> taddrRecipients;
4837 std::vector<SendManyRecipient> zaddrRecipients;
4838 CAmount nTotalOut = 0;
4840 bool containsSproutOutput = false;
4841 bool containsSaplingOutput = false;
4843 for (const UniValue& o : outputs.getValues()) {
4845 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
4847 // sanity check, report error if unknown key-value pairs
4848 for (const string& name_ : o.getKeys()) {
4849 std::string s = name_;
4850 if (s != "address" && s != "amount" && s!="memo")
4851 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown key: ")+s);
4854 string address = find_value(o, "address").get_str();
4855 bool isZaddr = false;
4856 CTxDestination taddr = DecodeDestination(address);
4857 if (!IsValidDestination(taddr)) {
4858 auto res = DecodePaymentAddress(address);
4859 if (IsValidPaymentAddress(res, branchId)) {
4862 bool toSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
4863 bool toSprout = !toSapling;
4864 noSproutAddrs = noSproutAddrs && toSapling;
4866 containsSproutOutput |= toSprout;
4867 containsSaplingOutput |= toSapling;
4869 // Sending to both Sprout and Sapling is currently unsupported using z_sendmany
4870 if (containsSproutOutput && containsSaplingOutput) {
4872 RPC_INVALID_PARAMETER,
4873 "Cannot send to both Sprout and Sapling addresses using z_sendmany");
4876 // If sending between shielded addresses, they must be the same type
4877 if ((fromSprout && toSapling) || (fromSapling && toSprout)) {
4879 RPC_INVALID_PARAMETER,
4880 "Cannot send between Sprout and Sapling addresses using z_sendmany");
4883 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
4886 else if ( ASSETCHAINS_PRIVATE != 0 )
4887 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
4889 if (setAddress.count(address))
4890 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address);
4891 setAddress.insert(address);
4893 UniValue memoValue = find_value(o, "memo");
4895 if (!memoValue.isNull()) {
4896 memo = memoValue.get_str();
4898 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo cannot be used with a taddr. It can only be used with a zaddr.");
4899 } else if (!IsHex(memo)) {
4900 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
4902 if (memo.length() > ZC_MEMO_SIZE*2) {
4903 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
4907 UniValue av = find_value(o, "amount");
4908 CAmount nAmount = AmountFromValue( av );
4910 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
4913 zaddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
4915 taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
4918 nTotalOut += nAmount;
4921 int nextBlockHeight = chainActive.Height() + 1;
4922 CMutableTransaction mtx;
4923 mtx.fOverwintered = true;
4924 mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
4925 mtx.nVersion = SAPLING_TX_VERSION;
4926 unsigned int max_tx_size = MAX_TX_SIZE_AFTER_SAPLING;
4927 if (!Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_SAPLING)) {
4928 if (Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_OVERWINTER)) {
4929 mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
4930 mtx.nVersion = OVERWINTER_TX_VERSION;
4932 mtx.fOverwintered = false;
4936 max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING;
4938 // Check the number of zaddr outputs does not exceed the limit.
4939 if (zaddrRecipients.size() > Z_SENDMANY_MAX_ZADDR_OUTPUTS_BEFORE_SAPLING) {
4940 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, too many zaddr outputs");
4942 // If Sapling is not active, do not allow sending from or sending to Sapling addresses.
4943 if (fromSapling || containsSaplingOutput) {
4944 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
4948 // As a sanity check, estimate and verify that the size of the transaction will be valid.
4949 // Depending on the input notes, the actual tx size may turn out to be larger and perhaps invalid.
4951 for (int i = 0; i < zaddrRecipients.size(); i++) {
4952 auto address = std::get<0>(zaddrRecipients[i]);
4953 auto res = DecodePaymentAddress(address);
4954 bool toSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
4956 mtx.vShieldedOutput.push_back(OutputDescription());
4958 JSDescription jsdesc;
4959 if (mtx.fOverwintered && (mtx.nVersion >= SAPLING_TX_VERSION)) {
4960 jsdesc.proof = GrothProof();
4962 mtx.vJoinSplit.push_back(jsdesc);
4965 CTransaction tx(mtx);
4966 txsize += GetSerializeSize(tx, SER_NETWORK, tx.nVersion);
4968 txsize += CTXIN_SPEND_DUST_SIZE;
4969 txsize += CTXOUT_REGULAR_SIZE; // There will probably be taddr change
4971 txsize += CTXOUT_REGULAR_SIZE * taddrRecipients.size();
4972 if (txsize > max_tx_size) {
4973 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Too many outputs, size of raw transaction would be larger than limit of %d bytes", max_tx_size ));
4976 // Minimum confirmations
4978 if (params.size() > 2) {
4979 nMinDepth = params[2].get_int();
4981 if (nMinDepth < 0) {
4982 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
4985 // Fee in Zatoshis, not currency format)
4986 CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE;
4987 CAmount nDefaultFee = nFee;
4989 if (params.size() > 3) {
4990 if (params[3].get_real() == 0.0) {
4993 nFee = AmountFromValue( params[3] );
4996 // Check that the user specified fee is not absurd.
4997 // This allows amount=0 (and all amount < nDefaultFee) transactions to use the default network fee
4998 // or anything less than nDefaultFee instead of being forced to use a custom fee and leak metadata
4999 if (nTotalOut < nDefaultFee) {
5000 if (nFee > nDefaultFee) {
5001 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Small transaction amount %s has fee %s that is greater than the default fee %s", FormatMoney(nTotalOut), FormatMoney(nFee), FormatMoney(nDefaultFee)));
5004 // Check that the user specified fee is not absurd.
5005 if (nFee > nTotalOut) {
5006 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the sum of outputs %s and also greater than the default fee", FormatMoney(nFee), FormatMoney(nTotalOut)));
5011 // Use input parameters as the optional context info to be returned by z_getoperationstatus and z_getoperationresult.
5012 UniValue o(UniValue::VOBJ);
5013 o.push_back(Pair("fromaddress", params[0]));
5014 o.push_back(Pair("amounts", params[1]));
5015 o.push_back(Pair("minconf", nMinDepth));
5016 o.push_back(Pair("fee", std::stod(FormatMoney(nFee))));
5017 UniValue contextInfo = o;
5019 // Builder (used if Sapling addresses are involved)
5020 boost::optional<TransactionBuilder> builder;
5021 if (noSproutAddrs) {
5022 builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain);
5025 // Contextual transaction we will build on
5026 // (used if no Sapling addresses are involved)
5027 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextBlockHeight);
5028 bool isShielded = !fromTaddr || zaddrRecipients.size() > 0;
5029 if (contextualTx.nVersion == 1 && isShielded) {
5030 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
5033 // Create operation and add to global queue
5034 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
5035 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(builder, contextualTx, fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee, contextInfo) );
5036 q->addOperation(operation);
5037 AsyncRPCOperationId operationId = operation->getId();
5041 UniValue z_setmigration(const UniValue& params, bool fHelp) {
5042 if (!EnsureWalletIsAvailable(fHelp))
5043 return NullUniValue;
5044 if (fHelp || params.size() != 1)
5045 throw runtime_error(
5046 "z_setmigration enabled\n"
5047 "When enabled the Sprout to Sapling migration will attempt to migrate all funds from this wallet’s\n"
5048 "Sprout addresses to either the address for Sapling account 0 or the address specified by the parameter\n"
5049 "'-migrationdestaddress'.\n"
5051 "This migration is designed to minimize information leakage. As a result for wallets with a significant\n"
5052 "Sprout balance, this process may take several weeks. The migration works by sending, up to 5, as many\n"
5053 "transactions as possible whenever the blockchain reaches a height equal to 499 modulo 500. The transaction\n"
5054 "amounts are picked according to the random distribution specified in ZIP 308. The migration will end once\n"
5055 "the wallet’s Sprout balance is below " + strprintf("%s %s", FormatMoney(CENT), CURRENCY_UNIT) + ".\n"
5057 "1. enabled (boolean, required) 'true' or 'false' to enable or disable respectively.\n"
5059 LOCK(pwalletMain->cs_wallet);
5060 pwalletMain->fSaplingMigrationEnabled = params[0].get_bool();
5061 return NullUniValue;
5064 UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) {
5065 if (!EnsureWalletIsAvailable(fHelp))
5066 return NullUniValue;
5067 if (fHelp || params.size() != 0)
5068 throw runtime_error(
5069 "z_getmigrationstatus\n"
5070 "Returns information about the status of the Sprout to Sapling migration.\n"
5071 "Note: A transaction is defined as finalized if it has at least ten confirmations.\n"
5072 "Also, it is possible that manually created transactions involving this wallet\n"
5073 "will be included in the result.\n"
5076 " \"enabled\": true|false, (boolean) Whether or not migration is enabled\n"
5077 " \"destination_address\": \"zaddr\", (string) The Sapling address that will receive Sprout funds\n"
5078 " \"unmigrated_amount\": nnn.n, (numeric) The total amount of unmigrated " + CURRENCY_UNIT +" \n"
5079 " \"unfinalized_migrated_amount\": nnn.n, (numeric) The total amount of unfinalized " + CURRENCY_UNIT + " \n"
5080 " \"finalized_migrated_amount\": nnn.n, (numeric) The total amount of finalized " + CURRENCY_UNIT + " \n"
5081 " \"finalized_migration_transactions\": nnn, (numeric) The number of migration transactions involving this wallet\n"
5082 " \"time_started\": ttt, (numeric, optional) The block time of the first migration transaction as a Unix timestamp\n"
5083 " \"migration_txids\": [txids] (json array of strings) An array of all migration txids involving this wallet\n"
5086 LOCK2(cs_main, pwalletMain->cs_wallet);
5087 UniValue migrationStatus(UniValue::VOBJ);
5088 migrationStatus.push_back(Pair("enabled", pwalletMain->fSaplingMigrationEnabled));
5089 // The "destination_address" field MAY be omitted if the "-migrationdestaddress"
5090 // parameter is not set and no default address has yet been generated.
5091 // Note: The following function may return the default address even if it has not been added to the wallet
5092 auto destinationAddress = AsyncRPCOperation_saplingmigration::getMigrationDestAddress(pwalletMain->GetHDSeedForRPC());
5093 migrationStatus.push_back(Pair("destination_address", EncodePaymentAddress(destinationAddress)));
5094 // The values of "unmigrated_amount" and "migrated_amount" MUST take into
5095 // account failed transactions, that were not mined within their expiration
5098 std::vector<SproutNoteEntry> sproutEntries;
5099 std::vector<SaplingNoteEntry> saplingEntries;
5100 std::set<PaymentAddress> noFilter;
5101 // Here we are looking for any and all Sprout notes for which we have the spending key, including those
5102 // which are locked and/or only exist in the mempool, as they should be included in the unmigrated amount.
5103 pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, noFilter, 0, INT_MAX, true, true, false);
5104 CAmount unmigratedAmount = 0;
5105 for (const auto& sproutEntry : sproutEntries) {
5106 unmigratedAmount += sproutEntry.note.value();
5108 migrationStatus.push_back(Pair("unmigrated_amount", FormatMoney(unmigratedAmount)));
5110 // "migration_txids" is a list of strings representing transaction IDs of all
5111 // known migration transactions involving this wallet, as lowercase hexadecimal
5112 // in RPC byte order.
5113 UniValue migrationTxids(UniValue::VARR);
5114 CAmount unfinalizedMigratedAmount = 0;
5115 CAmount finalizedMigratedAmount = 0;
5116 int numFinalizedMigrationTxs = 0;
5117 uint64_t timeStarted = 0;
5118 for (const auto& txPair : pwalletMain->mapWallet) {
5119 CWalletTx tx = txPair.second;
5120 // A given transaction is defined as a migration transaction iff it has:
5121 // * one or more Sprout JoinSplits with nonzero vpub_new field; and
5122 // * no Sapling Spends, and;
5123 // * one or more Sapling Outputs.
5124 if (tx.vJoinSplit.size() > 0 && tx.vShieldedSpend.empty() && tx.vShieldedOutput.size() > 0) {
5125 bool nonZeroVPubNew = false;
5126 for (const auto& js : tx.vJoinSplit) {
5127 if (js.vpub_new > 0) {
5128 nonZeroVPubNew = true;
5132 if (!nonZeroVPubNew) {
5135 migrationTxids.push_back(txPair.first.ToString());
5136 // A transaction is "finalized" iff it has at least 10 confirmations.
5137 // TODO: subject to change, if the recommended number of confirmations changes.
5138 if (tx.GetDepthInMainChain() >= 10) {
5139 finalizedMigratedAmount -= tx.valueBalance;
5140 ++numFinalizedMigrationTxs;
5142 unfinalizedMigratedAmount -= tx.valueBalance;
5144 // If the transaction is in the mempool it will not be associated with a block yet
5145 if (tx.hashBlock.IsNull() || mapBlockIndex[tx.hashBlock] == nullptr) {
5148 CBlockIndex* blockIndex = mapBlockIndex[tx.hashBlock];
5149 // The value of "time_started" is the earliest Unix timestamp of any known
5150 // migration transaction involving this wallet; if there is no such transaction,
5151 // then the field is absent.
5152 if (timeStarted == 0 || timeStarted > blockIndex->GetBlockTime()) {
5153 timeStarted = blockIndex->GetBlockTime();
5157 migrationStatus.push_back(Pair("unfinalized_migrated_amount", FormatMoney(unfinalizedMigratedAmount)));
5158 migrationStatus.push_back(Pair("finalized_migrated_amount", FormatMoney(finalizedMigratedAmount)));
5159 migrationStatus.push_back(Pair("finalized_migration_transactions", numFinalizedMigrationTxs));
5160 if (timeStarted > 0) {
5161 migrationStatus.push_back(Pair("time_started", timeStarted));
5163 migrationStatus.push_back(Pair("migration_txids", migrationTxids));
5164 return migrationStatus;
5168 When estimating the number of coinbase utxos we can shield in a single transaction:
5169 1. Joinsplit description is 1802 bytes.
5170 2. Transaction overhead ~ 100 bytes
5171 3. Spending a typical P2PKH is >=148 bytes, as defined in CTXIN_SPEND_DUST_SIZE.
5172 4. Spending a multi-sig P2SH address can vary greatly:
5173 https://github.com/bitcoin/bitcoin/blob/c3ad56f4e0b587d8d763af03d743fdfc2d180c9b/src/main.cpp#L517
5174 In real-world coinbase utxos, we consider a 3-of-3 multisig, where the size is roughly:
5175 (3*(33+1))+3 = 105 byte redeem script
5176 105 + 1 + 3*(73+1) = 328 bytes of scriptSig, rounded up to 400 based on testnet experiments.
5178 #define CTXIN_SPEND_P2SH_SIZE 400
5180 #define SHIELD_COINBASE_DEFAULT_LIMIT 50
5182 UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
5184 if (!EnsureWalletIsAvailable(fHelp))
5185 return NullUniValue;
5187 if (fHelp || params.size() < 2 || params.size() > 4)
5188 throw runtime_error(
5189 "z_shieldcoinbase \"fromaddress\" \"tozaddress\" ( fee ) ( limit )\n"
5190 "\nShield transparent coinbase funds by sending to a shielded zaddr. This is an asynchronous operation and utxos"
5191 "\nselected for shielding will be locked. If there is an error, they are unlocked. The RPC call `listlockunspent`"
5192 "\ncan be used to return a list of locked utxos. The number of coinbase utxos selected for shielding can be limited"
5193 "\nby the caller. If the limit parameter is set to zero, and Overwinter is not yet active, the -mempooltxinputlimit"
5194 "\noption will determine the number of uxtos. Any limit is constrained by the consensus rule defining a maximum"
5195 "\ntransaction size of "
5196 + strprintf("%d bytes before Sapling, and %d bytes once Sapling activates.", MAX_TX_SIZE_BEFORE_SAPLING, MAX_TX_SIZE_AFTER_SAPLING)
5197 + HelpRequiringPassphrase() + "\n"
5199 "1. \"fromaddress\" (string, required) The address is a taddr or \"*\" for all taddrs belonging to the wallet.\n"
5200 "2. \"toaddress\" (string, required) The address is a zaddr.\n"
5201 "3. fee (numeric, optional, default="
5202 + strprintf("%s", FormatMoney(SHIELD_COINBASE_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
5203 "4. limit (numeric, optional, default="
5204 + strprintf("%d", SHIELD_COINBASE_DEFAULT_LIMIT) + ") Limit on the maximum number of utxos to shield. Set to 0 to use node option -mempooltxinputlimit (before Overwinter), or as many as will fit in the transaction (after Overwinter).\n"
5207 " \"remainingUTXOs\": xxx (numeric) Number of coinbase utxos still available for shielding.\n"
5208 " \"remainingValue\": xxx (numeric) Value of coinbase utxos still available for shielding.\n"
5209 " \"shieldingUTXOs\": xxx (numeric) Number of coinbase utxos being shielded.\n"
5210 " \"shieldingValue\": xxx (numeric) Value of coinbase utxos being shielded.\n"
5211 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
5214 + HelpExampleCli("z_shieldcoinbase", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
5215 + HelpExampleRpc("z_shieldcoinbase", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
5218 LOCK2(cs_main, pwalletMain->cs_wallet);
5220 // Validate the from address
5221 auto fromaddress = params[0].get_str();
5222 bool isFromWildcard = fromaddress == "*";
5223 CTxDestination taddr;
5224 if (!isFromWildcard) {
5225 taddr = DecodeDestination(fromaddress);
5226 if (!IsValidDestination(taddr)) {
5227 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or \"*\".");
5231 // Validate the destination address
5232 auto destaddress = params[1].get_str();
5233 if (!IsValidPaymentAddressString(destaddress, CurrentEpochBranchId(chainActive.Height(), Params().GetConsensus()))) {
5234 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
5237 // Convert fee from currency format to zatoshis
5238 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
5239 if (params.size() > 2) {
5240 if (params[2].get_real() == 0.0) {
5243 nFee = AmountFromValue( params[2] );
5247 int nLimit = SHIELD_COINBASE_DEFAULT_LIMIT;
5248 if (params.size() > 3) {
5249 nLimit = params[3].get_int();
5251 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of utxos cannot be negative");
5255 int nextBlockHeight = chainActive.Height() + 1;
5256 bool overwinterActive = Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_OVERWINTER);
5257 unsigned int max_tx_size = MAX_TX_SIZE_AFTER_SAPLING;
5258 if (!Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_SAPLING)) {
5259 max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING;
5260 auto res = DecodePaymentAddress(destaddress);
5261 // If Sapling is not active, do not allow sending to a Sapling address.
5262 if (IsValidPaymentAddress(res)) {
5263 bool toSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
5265 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
5268 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
5272 // Prepare to get coinbase utxos
5273 std::vector<ShieldCoinbaseUTXO> inputs;
5274 CAmount shieldedValue = 0;
5275 CAmount remainingValue = 0;
5276 size_t estimatedTxSize = 2000; // 1802 joinsplit description + tx overhead + wiggle room
5279 uint64_t utxoCounter = 0;
5281 size_t utxoCounter = 0;
5284 bool maxedOutFlag = false;
5285 size_t mempoolLimit = (nLimit != 0) ? nLimit : (overwinterActive ? 0 : (size_t)GetArg("-mempooltxinputlimit", 0));
5287 // Set of addresses to filter utxos by
5288 std::set<CTxDestination> destinations = {};
5289 if (!isFromWildcard) {
5290 destinations.insert(taddr);
5293 // Get available utxos
5294 vector<COutput> vecOutputs;
5295 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true, true);
5297 // Find unspent coinbase utxos and update estimated size
5298 BOOST_FOREACH(const COutput& out, vecOutputs) {
5299 if (!out.fSpendable) {
5303 CTxDestination address;
5304 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
5308 // If taddr is not wildcard "*", filter utxos
5309 if (destinations.size() > 0 && !destinations.count(address)) {
5313 if (!out.tx->IsCoinBase()) {
5318 auto scriptPubKey = out.tx->vout[out.i].scriptPubKey;
5319 CAmount nValue = out.tx->vout[out.i].nValue;
5321 if (!maxedOutFlag) {
5322 size_t increase = (boost::get<CScriptID>(&address) != nullptr) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
5323 if (estimatedTxSize + increase >= max_tx_size ||
5324 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
5326 maxedOutFlag = true;
5328 estimatedTxSize += increase;
5329 ShieldCoinbaseUTXO utxo = {out.tx->GetHash(), out.i, scriptPubKey, nValue};
5330 inputs.push_back(utxo);
5331 shieldedValue += nValue;
5336 remainingValue += nValue;
5341 uint64_t numUtxos = inputs.size();
5343 size_t numUtxos = inputs.size();
5346 if (numUtxos == 0) {
5347 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any coinbase funds to shield.");
5350 if (shieldedValue < nFee) {
5351 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
5352 strprintf("Insufficient coinbase funds, have %s, which is less than miners fee %s",
5353 FormatMoney(shieldedValue), FormatMoney(nFee)));
5356 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
5357 CAmount netAmount = shieldedValue - nFee;
5358 if (nFee > netAmount) {
5359 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
5362 // Keep record of parameters in context object
5363 UniValue contextInfo(UniValue::VOBJ);
5364 contextInfo.push_back(Pair("fromaddress", params[0]));
5365 contextInfo.push_back(Pair("toaddress", params[1]));
5366 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
5368 // Builder (used if Sapling addresses are involved)
5369 TransactionBuilder builder = TransactionBuilder(
5370 Params().GetConsensus(), nextBlockHeight, pwalletMain);
5372 // Contextual transaction we will build on
5373 int blockHeight = chainActive.LastTip()->GetHeight();
5374 nextBlockHeight = blockHeight + 1;
5375 // (used if no Sapling addresses are involved)
5376 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
5377 Params().GetConsensus(), nextBlockHeight);
5378 contextualTx.nLockTime = chainActive.LastTip()->GetHeight();
5380 if (contextualTx.nVersion == 1) {
5381 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
5384 // Create operation and add to global queue
5385 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
5386 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(builder, contextualTx, inputs, destaddress, nFee, contextInfo) );
5387 q->addOperation(operation);
5388 AsyncRPCOperationId operationId = operation->getId();
5390 // Return continuation information
5391 UniValue o(UniValue::VOBJ);
5392 o.push_back(Pair("remainingUTXOs", static_cast<uint64_t>(utxoCounter - numUtxos)));
5393 o.push_back(Pair("remainingValue", ValueFromAmount(remainingValue)));
5394 o.push_back(Pair("shieldingUTXOs", static_cast<uint64_t>(numUtxos)));
5395 o.push_back(Pair("shieldingValue", ValueFromAmount(shieldedValue)));
5396 o.push_back(Pair("opid", operationId));
5401 #define MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT 50
5402 #define MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT 20
5403 #define MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT 200
5405 #define JOINSPLIT_SIZE GetSerializeSize(JSDescription(), SER_NETWORK, PROTOCOL_VERSION)
5406 #define OUTPUTDESCRIPTION_SIZE GetSerializeSize(OutputDescription(), SER_NETWORK, PROTOCOL_VERSION)
5407 #define SPENDDESCRIPTION_SIZE GetSerializeSize(SpendDescription(), SER_NETWORK, PROTOCOL_VERSION)
5409 UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
5411 if (!EnsureWalletIsAvailable(fHelp))
5412 return NullUniValue;
5414 string enableArg = "zmergetoaddress";
5415 auto fEnableMergeToAddress = fExperimentalMode && GetBoolArg("-" + enableArg, false);
5416 std::string strDisabledMsg = "";
5417 if (!fEnableMergeToAddress) {
5418 strDisabledMsg = experimentalDisabledHelpMsg("z_mergetoaddress", enableArg);
5421 if (fHelp || params.size() < 2 || params.size() > 6)
5422 throw runtime_error(
5423 "z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n"
5425 "\nMerge multiple UTXOs and notes into a single UTXO or note. Protected coinbase UTXOs are ignored, use `z_shieldcoinbase`"
5426 "\nto combine those into a single note."
5427 "\n\nThis is an asynchronous operation, and UTXOs selected for merging will be locked. If there is an error, they"
5428 "\nare unlocked. The RPC call `listlockunspent` can be used to return a list of locked UTXOs."
5429 "\n\nThe number of UTXOs and notes selected for merging can be limited by the caller. If the transparent limit"
5430 "\nparameter is set to zero, and Overwinter is not yet active, the -mempooltxinputlimit option will determine the"
5431 "\nnumber of UTXOs. After Overwinter has activated -mempooltxinputlimit is ignored and having a transparent"
5432 "\ninput limit of zero will mean limit the number of UTXOs based on the size of the transaction. Any limit is"
5433 "\nconstrained by the consensus rule defining a maximum transaction size of "
5434 + strprintf("%d bytes before Sapling, and %d", MAX_TX_SIZE_BEFORE_SAPLING, MAX_TX_SIZE_AFTER_SAPLING)
5435 + "\nbytes once Sapling activates."
5436 + HelpRequiringPassphrase() + "\n"
5438 "1. fromaddresses (array, required) A JSON array with addresses.\n"
5439 " The following special strings are accepted inside the array:\n"
5440 " - \"ANY_TADDR\": Merge UTXOs from any t-addrs belonging to the wallet.\n"
5441 " - \"ANY_SPROUT\": Merge notes from any Sprout zaddrs belonging to the wallet.\n"
5442 " - \"ANY_SAPLING\": Merge notes from any Sapling zaddrs belonging to the wallet.\n"
5443 " While it is possible to use a variety of different combinations of addresses and the above values,\n"
5444 " it is not possible to send funds from both sprout and sapling addresses simultaneously. If a special\n"
5445 " string is given, any given addresses of that type will be counted as duplicates and cause an error.\n"
5447 " \"address\" (string) Can be a t-addr or a zaddr\n"
5450 "2. \"toaddress\" (string, required) The t-addr or zaddr to send the funds to.\n"
5451 "3. fee (numeric, optional, default="
5452 + strprintf("%s", FormatMoney(MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
5453 "4. transparent_limit (numeric, optional, default="
5454 + 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 (before Overwinter), or as many as will fit in the transaction (after Overwinter).\n"
5455 "5. shielded_limit (numeric, optional, default="
5456 + strprintf("%d Sprout or %d Sapling Notes", MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT, MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT) + ") Limit on the maximum number of notes to merge. Set to 0 to merge as many as will fit in the transaction.\n"
5457 "6. \"memo\" (string, optional) Encoded as hex. When toaddress is a zaddr, this will be stored in the memo field of the new note.\n"
5460 " \"remainingUTXOs\": xxx (numeric) Number of UTXOs still available for merging.\n"
5461 " \"remainingTransparentValue\": xxx (numeric) Value of UTXOs still available for merging.\n"
5462 " \"remainingNotes\": xxx (numeric) Number of notes still available for merging.\n"
5463 " \"remainingShieldedValue\": xxx (numeric) Value of notes still available for merging.\n"
5464 " \"mergingUTXOs\": xxx (numeric) Number of UTXOs being merged.\n"
5465 " \"mergingTransparentValue\": xxx (numeric) Value of UTXOs being merged.\n"
5466 " \"mergingNotes\": xxx (numeric) Number of notes being merged.\n"
5467 " \"mergingShieldedValue\": xxx (numeric) Value of notes being merged.\n"
5468 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
5471 + HelpExampleCli("z_mergetoaddress", "'[\"ANY_SAPLING\", \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"]' ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf")
5472 + HelpExampleRpc("z_mergetoaddress", "[\"ANY_SAPLING\", \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"], \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
5475 if (!fEnableMergeToAddress) {
5476 throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_mergetoaddress is disabled. Run './zcash-cli help z_mergetoaddress' for instructions on how to enable this feature.");
5479 LOCK2(cs_main, pwalletMain->cs_wallet);
5481 bool useAnyUTXO = false;
5482 bool useAnySprout = false;
5483 bool useAnySapling = false;
5484 std::set<CTxDestination> taddrs = {};
5485 std::set<libzcash::PaymentAddress> zaddrs = {};
5487 uint32_t branchId = CurrentEpochBranchId(chainActive.Height(), Params().GetConsensus());
5489 UniValue addresses = params[0].get_array();
5490 if (addresses.size()==0)
5491 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, fromaddresses array is empty.");
5493 // Keep track of addresses to spot duplicates
5494 std::set<std::string> setAddress;
5497 for (const UniValue& o : addresses.getValues()) {
5499 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
5501 std::string address = o.get_str();
5503 if (address == "ANY_TADDR") {
5505 } else if (address == "ANY_SPROUT") {
5506 useAnySprout = true;
5507 } else if (address == "ANY_SAPLING") {
5508 useAnySapling = true;
5510 CTxDestination taddr = DecodeDestination(address);
5511 if (IsValidDestination(taddr)) {
5512 taddrs.insert(taddr);
5514 auto zaddr = DecodePaymentAddress(address);
5515 if (IsValidPaymentAddress(zaddr)) {
5516 zaddrs.insert(zaddr);
5518 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Unknown address format: ") + address);
5523 if (setAddress.count(address))
5524 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + address);
5525 setAddress.insert(address);
5528 if (useAnyUTXO && taddrs.size() > 0) {
5529 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify specific taddrs when using \"ANY_TADDR\"");
5531 if ((useAnySprout || useAnySapling) && zaddrs.size() > 0) {
5532 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify specific zaddrs when using \"ANY_SPROUT\" or \"ANY_SAPLING\"");
5535 const int nextBlockHeight = chainActive.Height() + 1;
5536 const bool overwinterActive = Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_OVERWINTER);
5537 const bool saplingActive = Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_SAPLING);
5539 // Validate the destination address
5540 auto destaddress = params[1].get_str();
5541 bool isToSproutZaddr = false;
5542 bool isToSaplingZaddr = false;
5543 CTxDestination taddr = DecodeDestination(destaddress);
5544 if (!IsValidDestination(taddr)) {
5545 if (IsValidPaymentAddressString(destaddress, branchId)) {
5546 // Is this a Sapling address?
5547 auto res = DecodePaymentAddress(destaddress);
5548 if (IsValidPaymentAddress(res)) {
5549 isToSaplingZaddr = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
5551 isToSproutZaddr = true;
5554 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
5557 else if ( ASSETCHAINS_PRIVATE != 0 )
5558 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
5560 // Convert fee from currency format to zatoshis
5561 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
5562 if (params.size() > 2) {
5563 if (params[2].get_real() == 0.0) {
5566 nFee = AmountFromValue( params[2] );
5570 int nUTXOLimit = MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT;
5571 if (params.size() > 3) {
5572 nUTXOLimit = params[3].get_int();
5573 if (nUTXOLimit < 0) {
5574 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of UTXOs cannot be negative");
5578 int sproutNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT;
5579 int saplingNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT;
5580 if (params.size() > 4) {
5581 int nNoteLimit = params[4].get_int();
5582 if (nNoteLimit < 0) {
5583 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of notes cannot be negative");
5585 sproutNoteLimit = nNoteLimit;
5586 saplingNoteLimit = nNoteLimit;
5590 if (params.size() > 5) {
5591 memo = params[5].get_str();
5592 if (!(isToSproutZaddr || isToSaplingZaddr)) {
5593 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
5594 } else if (!IsHex(memo)) {
5595 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
5597 if (memo.length() > ZC_MEMO_SIZE*2) {
5598 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
5602 MergeToAddressRecipient recipient(destaddress, memo);
5604 // Prepare to get UTXOs and notes
5605 std::vector<MergeToAddressInputUTXO> utxoInputs;
5606 std::vector<MergeToAddressInputSproutNote> sproutNoteInputs;
5607 std::vector<MergeToAddressInputSaplingNote> saplingNoteInputs;
5608 CAmount mergedUTXOValue = 0;
5609 CAmount mergedNoteValue = 0;
5610 CAmount remainingUTXOValue = 0;
5611 CAmount remainingNoteValue = 0;
5613 uint64_t utxoCounter = 0;
5614 uint64_t noteCounter = 0;
5616 size_t utxoCounter = 0;
5617 size_t noteCounter = 0;
5619 bool maxedOutUTXOsFlag = false;
5620 bool maxedOutNotesFlag = false;
5621 size_t mempoolLimit = (nUTXOLimit != 0) ? nUTXOLimit : (overwinterActive ? 0 : (size_t)GetArg("-mempooltxinputlimit", 0));
5623 unsigned int max_tx_size = saplingActive ? MAX_TX_SIZE_AFTER_SAPLING : MAX_TX_SIZE_BEFORE_SAPLING;
5624 size_t estimatedTxSize = 200; // tx overhead + wiggle room
5625 if (isToSproutZaddr) {
5626 estimatedTxSize += JOINSPLIT_SIZE;
5627 } else if (isToSaplingZaddr) {
5628 estimatedTxSize += OUTPUTDESCRIPTION_SIZE;
5631 if (useAnyUTXO || taddrs.size() > 0) {
5632 // Get available utxos
5633 vector<COutput> vecOutputs;
5634 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true, false);
5636 // Find unspent utxos and update estimated size
5637 for (const COutput& out : vecOutputs) {
5638 if (!out.fSpendable) {
5642 CScript scriptPubKey = out.tx->vout[out.i].scriptPubKey;
5644 CTxDestination address;
5645 if (!ExtractDestination(scriptPubKey, address)) {
5648 // If taddr is not wildcard "*", filter utxos
5649 if (taddrs.size() > 0 && !taddrs.count(address)) {
5654 CAmount nValue = out.tx->vout[out.i].nValue;
5656 if (!maxedOutUTXOsFlag) {
5657 size_t increase = (boost::get<CScriptID>(&address) != nullptr) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
5658 if (estimatedTxSize + increase >= max_tx_size ||
5659 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
5661 maxedOutUTXOsFlag = true;
5663 estimatedTxSize += increase;
5664 COutPoint utxo(out.tx->GetHash(), out.i);
5665 utxoInputs.emplace_back(utxo, nValue, scriptPubKey);
5666 mergedUTXOValue += nValue;
5670 if (maxedOutUTXOsFlag) {
5671 remainingUTXOValue += nValue;
5676 if (useAnySprout || useAnySapling || zaddrs.size() > 0) {
5677 // Get available notes
5678 std::vector<SproutNoteEntry> sproutEntries;
5679 std::vector<SaplingNoteEntry> saplingEntries;
5680 pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs);
5682 // If Sapling is not active, do not allow sending from a sapling addresses.
5683 if (!saplingActive && saplingEntries.size() > 0) {
5684 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
5686 // Do not include Sprout/Sapling notes if using "ANY_SAPLING"/"ANY_SPROUT" respectively
5688 saplingEntries.clear();
5690 if (useAnySapling) {
5691 sproutEntries.clear();
5693 // Sending from both Sprout and Sapling is currently unsupported using z_mergetoaddress
5694 if ((sproutEntries.size() > 0 && saplingEntries.size() > 0) || (useAnySprout && useAnySapling)) {
5696 RPC_INVALID_PARAMETER,
5697 "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress");
5699 // If sending between shielded addresses, they must be the same type
5700 if ((saplingEntries.size() > 0 && isToSproutZaddr) || (sproutEntries.size() > 0 && isToSaplingZaddr)) {
5702 RPC_INVALID_PARAMETER,
5703 "Cannot send between Sprout and Sapling addresses using z_mergetoaddress");
5706 // Find unspent notes and update estimated size
5707 for (const SproutNoteEntry& entry : sproutEntries) {
5709 CAmount nValue = entry.note.value();
5711 if (!maxedOutNotesFlag) {
5712 // If we haven't added any notes yet and the merge is to a
5713 // z-address, we have already accounted for the first JoinSplit.
5714 size_t increase = (sproutNoteInputs.empty() && !isToSproutZaddr) || (sproutNoteInputs.size() % 2 == 0) ? JOINSPLIT_SIZE : 0;
5715 if (estimatedTxSize + increase >= max_tx_size ||
5716 (sproutNoteLimit > 0 && noteCounter > sproutNoteLimit))
5718 maxedOutNotesFlag = true;
5720 estimatedTxSize += increase;
5721 auto zaddr = entry.address;
5722 SproutSpendingKey zkey;
5723 pwalletMain->GetSproutSpendingKey(zaddr, zkey);
5724 sproutNoteInputs.emplace_back(entry.jsop, entry.note, nValue, zkey);
5725 mergedNoteValue += nValue;
5729 if (maxedOutNotesFlag) {
5730 remainingNoteValue += nValue;
5734 for (const SaplingNoteEntry& entry : saplingEntries) {
5736 CAmount nValue = entry.note.value();
5737 if (!maxedOutNotesFlag) {
5738 size_t increase = SPENDDESCRIPTION_SIZE;
5739 if (estimatedTxSize + increase >= max_tx_size ||
5740 (saplingNoteLimit > 0 && noteCounter > saplingNoteLimit))
5742 maxedOutNotesFlag = true;
5744 estimatedTxSize += increase;
5745 libzcash::SaplingExtendedSpendingKey extsk;
5746 if (!pwalletMain->GetSaplingExtendedSpendingKey(entry.address, extsk)) {
5747 throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find spending key for payment address.");
5749 saplingNoteInputs.emplace_back(entry.op, entry.note, nValue, extsk.expsk);
5750 mergedNoteValue += nValue;
5754 if (maxedOutNotesFlag) {
5755 remainingNoteValue += nValue;
5761 uint64_t numUtxos = utxoInputs.size(); //ca333
5763 size_t numUtxos = utxoInputs.size();
5766 size_t numNotes = sproutNoteInputs.size() + saplingNoteInputs.size();
5768 if (numUtxos == 0 && numNotes == 0) {
5769 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any funds to merge.");
5772 // Sanity check: Don't do anything if:
5773 // - We only have one from address
5774 // - It's equal to toaddress
5775 // - The address only contains a single UTXO or note
5776 if (setAddress.size() == 1 && setAddress.count(destaddress) && (numUtxos + numNotes) == 1) {
5777 throw JSONRPCError(RPC_INVALID_PARAMETER, "Destination address is also the only source address, and all its funds are already merged.");
5780 CAmount mergedValue = mergedUTXOValue + mergedNoteValue;
5781 if (mergedValue < nFee) {
5782 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
5783 strprintf("Insufficient funds, have %s, which is less than miners fee %s",
5784 FormatMoney(mergedValue), FormatMoney(nFee)));
5787 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
5788 CAmount netAmount = mergedValue - nFee;
5789 if (nFee > netAmount) {
5790 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
5793 // Keep record of parameters in context object
5794 UniValue contextInfo(UniValue::VOBJ);
5795 contextInfo.push_back(Pair("fromaddresses", params[0]));
5796 contextInfo.push_back(Pair("toaddress", params[1]));
5797 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
5799 // Contextual transaction we will build on
5800 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
5801 Params().GetConsensus(),
5803 bool isSproutShielded = sproutNoteInputs.size() > 0 || isToSproutZaddr;
5804 if (contextualTx.nVersion == 1 && isSproutShielded) {
5805 contextualTx.nVersion = 2; // Tx format should support vJoinSplit
5808 // Builder (used if Sapling addresses are involved)
5809 boost::optional<TransactionBuilder> builder;
5810 if (isToSaplingZaddr || saplingNoteInputs.size() > 0) {
5811 builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain);
5813 // Create operation and add to global queue
5814 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
5815 std::shared_ptr<AsyncRPCOperation> operation(
5816 new AsyncRPCOperation_mergetoaddress(builder, contextualTx, utxoInputs, sproutNoteInputs, saplingNoteInputs, recipient, nFee, contextInfo) );
5817 q->addOperation(operation);
5818 AsyncRPCOperationId operationId = operation->getId();
5820 // Return continuation information
5821 UniValue o(UniValue::VOBJ);
5822 o.push_back(Pair("remainingUTXOs", static_cast<uint64_t>(utxoCounter - numUtxos)));
5823 o.push_back(Pair("remainingTransparentValue", ValueFromAmount(remainingUTXOValue)));
5824 o.push_back(Pair("remainingNotes", static_cast<uint64_t>(noteCounter - numNotes)));
5825 o.push_back(Pair("remainingShieldedValue", ValueFromAmount(remainingNoteValue)));
5826 o.push_back(Pair("mergingUTXOs", static_cast<uint64_t>(numUtxos)));
5827 o.push_back(Pair("mergingTransparentValue", ValueFromAmount(mergedUTXOValue)));
5828 o.push_back(Pair("mergingNotes", static_cast<uint64_t>(numNotes)));
5829 o.push_back(Pair("mergingShieldedValue", ValueFromAmount(mergedNoteValue)));
5830 o.push_back(Pair("opid", operationId));
5835 UniValue z_listoperationids(const UniValue& params, bool fHelp)
5837 if (!EnsureWalletIsAvailable(fHelp))
5838 return NullUniValue;
5840 if (fHelp || params.size() > 1)
5841 throw runtime_error(
5842 "z_listoperationids\n"
5843 "\nReturns the list of operation ids currently known to the wallet.\n"
5845 "1. \"status\" (string, optional) Filter result by the operation's state e.g. \"success\".\n"
5847 "[ (json array of string)\n"
5848 " \"operationid\" (string) an operation id belonging to the wallet\n"
5852 + HelpExampleCli("z_listoperationids", "")
5853 + HelpExampleRpc("z_listoperationids", "")
5856 LOCK2(cs_main, pwalletMain->cs_wallet);
5859 bool useFilter = false;
5860 if (params.size()==1) {
5861 filter = params[0].get_str();
5865 UniValue ret(UniValue::VARR);
5866 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
5867 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
5868 for (auto id : ids) {
5869 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
5873 std::string state = operation->getStateAsString();
5874 if (useFilter && filter.compare(state)!=0)
5883 #include "script/sign.h"
5884 int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
5885 extern std::string NOTARY_PUBKEY;
5886 uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime,char *destaddr);
5887 int8_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256 txid,int32_t vout);
5888 void komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n);
5890 int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33)
5892 set<CBitcoinAddress> setAddress; uint8_t *script,utxosig[128]; uint256 utxotxid; uint64_t utxovalue; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector<COutput> vecOutputs; uint32_t utxovout,eligible,earliest = 0; CScript best_scriptPubKey; bool fNegative,fOverflow;
5893 bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr;
5894 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
5895 const CKeyStore& keystore = *pwalletMain;
5896 assert(pwalletMain != NULL);
5897 LOCK2(cs_main, pwalletMain->cs_wallet);
5899 memset(&utxotxid,0,sizeof(utxotxid));
5900 memset(&utxovout,0,sizeof(utxovout));
5901 memset(utxosig,0,sizeof(utxosig));
5902 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
5903 BOOST_FOREACH(const COutput& out, vecOutputs)
5905 if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth )
5907 if ( setAddress.size() )
5909 CTxDestination address;
5910 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
5912 if (!setAddress.count(address))
5915 CAmount nValue = out.tx->vout[out.i].nValue;
5916 if ( nValue != 10000 )
5918 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
5919 CTxDestination address;
5920 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
5922 //entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
5923 //if (pwalletMain->mapAddressBook.count(address))
5924 // entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
5926 script = (uint8_t *)&out.tx->vout[out.i].scriptPubKey[0];
5927 if ( out.tx->vout[out.i].scriptPubKey.size() != 35 || script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(notarypub33,script+1,33) != 0 )
5929 //fprintf(stderr,"scriptsize.%d [0] %02x\n",(int32_t)out.tx->vout[out.i].scriptPubKey.size(),script[0]);
5932 utxovalue = (uint64_t)nValue;
5933 //decode_hex((uint8_t *)&utxotxid,32,(char *)out.tx->GetHash().GetHex().c_str());
5934 utxotxid = out.tx->GetHash();
5936 best_scriptPubKey = out.tx->vout[out.i].scriptPubKey;
5937 //fprintf(stderr,"check %s/v%d %llu\n",(char *)utxotxid.GetHex().c_str(),utxovout,(long long)utxovalue);
5939 txNew.vin.resize(1);
5940 txNew.vout.resize(1);
5941 txfee = utxovalue / 2;
5942 //for (i=0; i<32; i++)
5943 // ((uint8_t *)&revtxid)[i] = ((uint8_t *)&utxotxid)[31 - i];
5944 txNew.vin[0].prevout.hash = utxotxid; //revtxid;
5945 txNew.vin[0].prevout.n = utxovout;
5946 txNew.vout[0].scriptPubKey = CScript() << ParseHex(CRYPTO777_PUBSECPSTR) << OP_CHECKSIG;
5947 txNew.vout[0].nValue = utxovalue - txfee;
5948 CTransaction txNewConst(txNew);
5949 signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, utxovalue, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId);
5951 fprintf(stderr,"notaryvin failed to create signature\n");
5954 UpdateTransaction(txNew,0,sigdata);
5955 ptr = (uint8_t *)&sigdata.scriptSig[0];
5956 siglen = sigdata.scriptSig.size();
5957 for (i=0; i<siglen; i++)
5958 utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]);
5959 //fprintf(stderr," siglen.%d notaryvin %s/v%d\n",siglen,utxotxid.GetHex().c_str(),utxovout);
5966 struct komodo_staking
5970 arith_uint256 hashval;
5972 uint32_t segid32,txtime;
5974 CScript scriptPubKey;
5977 struct komodo_staking *komodo_addutxo(struct komodo_staking *array,int32_t *numkp,int32_t *maxkp,uint32_t txtime,uint64_t nValue,uint256 txid,int32_t vout,char *address,uint8_t *hashbuf,CScript pk)
5979 uint256 hash; uint32_t segid32; struct komodo_staking *kp;
5980 segid32 = komodo_stakehash(&hash,address,hashbuf,txid,vout);
5981 if ( *numkp >= *maxkp )
5984 array = (struct komodo_staking *)realloc(array,sizeof(*array) * (*maxkp));
5986 kp = &array[(*numkp)++];
5987 memset(kp,0,sizeof(*kp));
5988 strcpy(kp->address,address);
5991 kp->hashval = UintToArith256(hash);
5992 kp->txtime = txtime;
5993 kp->segid32 = segid32;
5994 kp->nValue = nValue;
5995 kp->scriptPubKey = pk;
5999 arith_uint256 _komodo_eligible(struct komodo_staking *kp,arith_uint256 ratio,uint32_t blocktime,int32_t iter,int32_t minage,int32_t segid,int32_t nHeight,uint32_t prevtime)
6001 int32_t diff; uint64_t coinage; arith_uint256 coinage256,hashval;
6002 diff = (iter + blocktime - kp->txtime - minage);
6005 else if ( diff > 3600*24*30 )
6009 coinage = ((uint64_t)kp->nValue/COIN * diff);
6010 if ( blocktime+iter+segid*2 > prevtime+480 )
6011 coinage *= ((blocktime+iter+segid*2) - (prevtime+400));
6012 //if ( nHeight >= 2500 && blocktime+iter+segid*2 > prevtime+180 )
6013 // coinage *= ((blocktime+iter+segid*2) - (prevtime+60));
6014 coinage256 = arith_uint256(coinage+1);
6015 hashval = ratio * (kp->hashval / coinage256);
6016 //if ( nHeight >= 900 && nHeight < 916 )
6017 // hashval = (hashval / coinage256);
6021 uint32_t komodo_eligible(arith_uint256 bnTarget,arith_uint256 ratio,struct komodo_staking *kp,int32_t nHeight,uint32_t blocktime,uint32_t prevtime,int32_t minage,uint8_t *hashbuf)
6023 int32_t maxiters = 600; uint256 hash;
6024 int32_t segid,iter,diff; uint64_t coinage; arith_uint256 hashval,coinage256;
6025 komodo_stakehash(&hash,kp->address,hashbuf,kp->txid,kp->vout);
6026 kp->hashval = UintToArith256(hash);
6027 segid = ((nHeight + kp->segid32) & 0x3f);
6028 hashval = _komodo_eligible(kp,ratio,blocktime,maxiters,minage,segid,nHeight,prevtime);
6029 //for (int i=32; i>=0; i--)
6030 // fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
6031 //fprintf(stderr," b.%u minage.%d segid.%d ht.%d prev.%u\n",blocktime,minage,segid,nHeight,prevtime);
6032 if ( hashval <= bnTarget )
6034 for (iter=0; iter<maxiters; iter++)
6036 if ( blocktime+iter+segid*2 < kp->txtime+minage )
6038 hashval = _komodo_eligible(kp,ratio,blocktime,iter,minage,segid,nHeight,prevtime);
6039 if ( hashval <= bnTarget )
6041 //fprintf(stderr,"winner %.8f blocktime.%u iter.%d segid.%d\n",(double)kp->nValue/COIN,blocktime,iter,segid);
6043 blocktime += segid * 2;
6051 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)
6053 static struct komodo_staking *array; static int32_t numkp,maxkp; static uint32_t lasttime;
6054 set<CBitcoinAddress> setAddress; struct komodo_staking *kp; int32_t winners,segid,minage,nHeight,counter=0,i,m,siglen=0,nMinDepth = 1,nMaxDepth = 99999999; vector<COutput> vecOutputs; uint32_t block_from_future_rejecttime,besttime,eligible,eligible2,earliest = 0; CScript best_scriptPubKey; arith_uint256 mindiff,ratio,bnTarget; CBlockIndex *tipindex,*pindex; CTxDestination address; bool fNegative,fOverflow; uint8_t hashbuf[256]; CTransaction tx; uint256 hashBlock;
6055 bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
6056 mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
6057 ratio = (mindiff / bnTarget);
6058 assert(pwalletMain != NULL);
6059 LOCK2(cs_main, pwalletMain->cs_wallet);
6061 memset(utxotxidp,0,sizeof(*utxotxidp));
6062 memset(utxovoutp,0,sizeof(*utxovoutp));
6063 memset(utxosig,0,72);
6064 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
6065 if ( (tipindex= chainActive.Tip()) == 0 )
6067 nHeight = tipindex->GetHeight() + 1;
6068 if ( (minage= nHeight*3) > 6000 ) // about 100 blocks
6070 komodo_segids(hashbuf,nHeight-101,100);
6071 if ( *blocktimep > tipindex->nTime+60 )
6072 *blocktimep = tipindex->nTime+60;
6073 //fprintf(stderr,"Start scan of utxo for staking %u ht.%d\n",(uint32_t)time(NULL),nHeight);
6074 if ( time(NULL) > lasttime+600 )
6083 BOOST_FOREACH(const COutput& out, vecOutputs)
6085 if ( (tipindex= chainActive.Tip()) == 0 || tipindex->GetHeight()+1 > nHeight )
6087 fprintf(stderr,"chain tip changed during staking loop t.%u counter.%d\n",(uint32_t)time(NULL),counter);
6091 if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth )
6093 //fprintf(stderr,"komodo_staked invalid depth %d\n",(int32_t)out.nDepth);
6096 CAmount nValue = out.tx->vout[out.i].nValue;
6097 if ( nValue < COIN || !out.fSpendable )
6099 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
6100 if ( ExtractDestination(pk,address) != 0 )
6102 if ( IsMine(*pwalletMain,address) == 0 )
6104 if ( GetTransaction(out.tx->GetHash(),tx,hashBlock,true) != 0 && mapBlockIndex.count(hashBlock) && (pindex= mapBlockIndex[hashBlock]) != 0 )
6106 array = komodo_addutxo(array,&numkp,&maxkp,(uint32_t)pindex->nTime,(uint64_t)nValue,out.tx->GetHash(),out.i,(char *)CBitcoinAddress(address).ToString().c_str(),hashbuf,(CScript)pk);
6110 lasttime = (uint32_t)time(NULL);
6111 //fprintf(stderr,"finished kp data of utxo for staking %u ht.%d numkp.%d maxkp.%d\n",(uint32_t)time(NULL),nHeight,numkp,maxkp);
6113 block_from_future_rejecttime = (uint32_t)GetAdjustedTime() + 57;
6114 for (i=winners=0; i<numkp; i++)
6116 if ( (tipindex= chainActive.Tip()) == 0 || tipindex->GetHeight()+1 > nHeight )
6118 fprintf(stderr,"chain tip changed during staking loop t.%u counter.%d\n",(uint32_t)time(NULL),counter);
6122 if ( (eligible2= komodo_eligible(bnTarget,ratio,kp,nHeight,*blocktimep,(uint32_t)tipindex->nTime+27,minage,hashbuf)) == 0 )
6124 eligible = komodo_stake(0,bnTarget,nHeight,kp->txid,kp->vout,0,(uint32_t)tipindex->nTime+27,kp->address);
6125 //fprintf(stderr,"i.%d %u vs %u\n",i,eligible2,eligible);
6129 if ( eligible == komodo_stake(1,bnTarget,nHeight,kp->txid,kp->vout,eligible,(uint32_t)tipindex->nTime+27,kp->address) )
6131 while ( eligible == komodo_stake(1,bnTarget,nHeight,kp->txid,kp->vout,eligible,(uint32_t)tipindex->nTime+27,kp->address) )
6133 besttime = eligible;
6135 if ( eligible < block_from_future_rejecttime ) // nothing gained by going earlier
6138 //fprintf(stderr,"m.%d ht.%d validated winning blocktime %u -> %.8f eligible.%u test prior\n",m,nHeight,*blocktimep,(double)kp->nValue/COIN,eligible);
6143 fprintf(stderr,"ht.%d error validating winning blocktime %u -> %.8f eligible.%u test prior\n",nHeight,*blocktimep,(double)kp->nValue/COIN,eligible);
6146 eligible = besttime;
6148 //fprintf(stderr,"ht.%d validated winning [%d] -> %.8f eligible.%u test prior\n",nHeight,(int32_t)(eligible - tipindex->nTime),(double)kp->nValue/COIN,eligible);
6149 if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || kp->nValue < *utxovaluep)) )
6151 earliest = eligible;
6152 best_scriptPubKey = kp->scriptPubKey; //out.tx->vout[out.i].scriptPubKey;
6153 *utxovaluep = (uint64_t)kp->nValue;
6154 //decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str());
6155 decode_hex((uint8_t *)utxotxidp,32,(char *)kp->txid.GetHex().c_str());
6156 *utxovoutp = kp->vout;
6157 *txtimep = kp->txtime;//(uint32_t)out.tx->nLockTime;
6158 fprintf(stderr,"ht.%d earliest.%u [%d].%d (%s) nValue %.8f locktime.%u counter.%d winners.%d\n",nHeight,earliest,(int32_t)(earliest - tipindex->nTime),m,kp->address,(double)kp->nValue/COIN,*txtimep,counter,winners);
6160 } //else fprintf(stderr,"utxo not eligible\n");
6161 } //else fprintf(stderr,"no tipindex\n");
6162 if ( numkp < 10000 && array != 0 )
6169 if ( earliest != 0 )
6171 bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid;
6172 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
6173 const CKeyStore& keystore = *pwalletMain;
6174 txNew.vin.resize(1);
6175 txNew.vout.resize(1);
6177 for (i=0; i<32; i++)
6178 ((uint8_t *)&revtxid)[i] = ((uint8_t *)utxotxidp)[31 - i];
6179 txNew.vin[0].prevout.hash = revtxid;
6180 txNew.vin[0].prevout.n = *utxovoutp;
6181 txNew.vout[0].scriptPubKey = best_scriptPubKey;// CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG;
6182 txNew.vout[0].nValue = *utxovaluep - txfee;
6183 txNew.nLockTime = earliest;
6184 CTransaction txNewConst(txNew);
6185 signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, *utxovaluep, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId);
6187 fprintf(stderr,"failed to create signature\n");
6190 UpdateTransaction(txNew,0,sigdata);
6191 ptr = (uint8_t *)&sigdata.scriptSig[0];
6192 siglen = sigdata.scriptSig.size();
6193 for (i=0; i<siglen; i++)
6194 utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]);
6195 //fprintf(stderr," siglen.%d\n",siglen);
6196 //fprintf(stderr,"best %u from %u, gap %d lag.%d\n",earliest,*blocktimep,(int32_t)(earliest - *blocktimep),(int32_t)(time(NULL) - *blocktimep));
6197 *blocktimep = earliest;
6199 } //else fprintf(stderr,"no earliest utxo for staking\n");
6200 //fprintf(stderr,"end scan of utxo for staking t.%u counter.%d numkp.%d winners.%d\n",(uint32_t)time(NULL),counter,numkp,winners);
6204 int32_t verus_staked(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &nBits, arith_uint256 &hashResult, uint8_t *utxosig, CPubKey &pk)
6206 return pwalletMain->VerusStakeTransaction(pBlock, txNew, nBits, hashResult, utxosig, pk);
6209 int32_t ensure_CCrequirements()
6211 extern uint8_t NOTARY_PUBKEY33[];
6213 if ( NOTARY_PUBKEY33[0] == 0 )
6215 else if ( GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX) == 0 )
6217 else if ( GetBoolArg("-spentindex", DEFAULT_SPENTINDEX) == 0 )
6222 #include "../cc/CCfaucet.h"
6223 #include "../cc/CCassets.h"
6224 #include "../cc/CCrewards.h"
6225 #include "../cc/CCdice.h"
6226 #include "../cc/CCfsm.h"
6227 #include "../cc/CCauction.h"
6228 #include "../cc/CClotto.h"
6229 #include "../cc/CCchannels.h"
6230 #include "../cc/CCOracles.h"
6231 #include "../cc/CCGateways.h"
6233 UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector<unsigned char> &pubkey)
6235 UniValue result(UniValue::VOBJ); char destaddr[64],str[64]; CPubKey pk;
6236 pk = GetUnspendable(cp,0);
6237 GetCCaddress(cp,destaddr,pk);
6238 if ( strcmp(destaddr,cp->unspendableCCaddr) != 0 )
6241 Myprivkey(priv); // it is assumed the CC's normal address'es -pubkey was used
6242 fprintf(stderr,"fix mismatched CCaddr %s -> %s\n",cp->unspendableCCaddr,destaddr);
6243 strcpy(cp->unspendableCCaddr,destaddr);
6245 result.push_back(Pair("result", "success"));
6246 sprintf(str,"%sCCaddress",name);
6247 result.push_back(Pair(str,cp->unspendableCCaddr));
6248 sprintf(str,"%smarker",name);
6249 result.push_back(Pair(str,cp->normaladdr));
6250 result.push_back(Pair("GatewaysPubkey","03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40"));
6251 if ( _GetCCaddress(destaddr,EVAL_ASSETS,pubkey2pk(pubkey)) > 0 )
6253 sprintf(str,"%sCCassets",name);
6254 result.push_back(Pair(str,destaddr));
6256 if ( pubkey.size() == 33 )
6258 if ( GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0 )
6259 result.push_back(Pair("CCaddress",destaddr));
6261 if ( GetCCaddress(cp,destaddr,pubkey2pk(Mypubkey())) != 0 )
6262 result.push_back(Pair("myCCaddress",destaddr));
6263 if ( Getscriptaddress(destaddr,(CScript() << Mypubkey() << OP_CHECKSIG)) != 0 )
6264 result.push_back(Pair("myaddress",destaddr));
6268 UniValue channelsaddress(const UniValue& params, bool fHelp)
6270 UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::vector<unsigned char> destpubkey; CPubKey pk,pk2; char destaddr[64];
6271 cp = CCinit(&C,EVAL_CHANNELS);
6272 if ( fHelp || params.size() != 1 )
6273 throw runtime_error("channelsaddress destpubkey\n");
6274 if ( ensure_CCrequirements() < 0 )
6275 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6276 destpubkey = ParseHex(params[0].get_str().c_str());
6277 pk = pubkey2pk(Mypubkey());
6278 pk2 = pubkey2pk(destpubkey);
6279 result = CCaddress(cp,(char *)"Channels",destpubkey);
6280 result.push_back(Pair("otherpubkey", params[0].get_str()));
6281 GetCCaddress1of2(cp,destaddr,pk,pk2);
6282 result.push_back(Pair("channeladdress",destaddr));
6286 UniValue oraclesaddress(const UniValue& params, bool fHelp)
6288 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6289 cp = CCinit(&C,EVAL_ORACLES);
6290 if ( fHelp || params.size() > 1 )
6291 throw runtime_error("oraclesaddress [pubkey]\n");
6292 if ( ensure_CCrequirements() < 0 )
6293 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6294 if ( params.size() == 1 )
6295 pubkey = ParseHex(params[0].get_str().c_str());
6296 return(CCaddress(cp,(char *)"Oracles",pubkey));
6299 UniValue pricesaddress(const UniValue& params, bool fHelp)
6301 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6302 cp = CCinit(&C,EVAL_PRICES);
6303 if ( fHelp || params.size() > 1 )
6304 throw runtime_error("pricesaddress [pubkey]\n");
6305 if ( ensure_CCrequirements() < 0 )
6306 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6307 if ( params.size() == 1 )
6308 pubkey = ParseHex(params[0].get_str().c_str());
6309 return(CCaddress(cp,(char *)"Prices",pubkey));
6312 UniValue pegsaddress(const UniValue& params, bool fHelp)
6314 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6315 cp = CCinit(&C,EVAL_PEGS);
6316 if ( fHelp || params.size() > 1 )
6317 throw runtime_error("pegssaddress [pubkey]\n");
6318 if ( ensure_CCrequirements() < 0 )
6319 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6320 if ( params.size() == 1 )
6321 pubkey = ParseHex(params[0].get_str().c_str());
6322 return(CCaddress(cp,(char *)"Pegs",pubkey));
6325 UniValue triggersaddress(const UniValue& params, bool fHelp)
6327 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6328 cp = CCinit(&C,EVAL_TRIGGERS);
6329 if ( fHelp || params.size() > 1 )
6330 throw runtime_error("triggersaddress [pubkey]\n");
6331 if ( ensure_CCrequirements() < 0 )
6332 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6333 if ( params.size() == 1 )
6334 pubkey = ParseHex(params[0].get_str().c_str());
6335 return(CCaddress(cp,(char *)"Triggers",pubkey));
6338 UniValue paymentsaddress(const UniValue& params, bool fHelp)
6340 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6341 cp = CCinit(&C,EVAL_PAYMENTS);
6342 if ( fHelp || params.size() > 1 )
6343 throw runtime_error("paymentsaddress [pubkey]\n");
6344 if ( ensure_CCrequirements() < 0 )
6345 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6346 if ( params.size() == 1 )
6347 pubkey = ParseHex(params[0].get_str().c_str());
6348 return(CCaddress(cp,(char *)"Payments",pubkey));
6351 UniValue gatewaysaddress(const UniValue& params, bool fHelp)
6353 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6354 cp = CCinit(&C,EVAL_GATEWAYS);
6355 if ( fHelp || params.size() > 1 )
6356 throw runtime_error("gatewaysaddress [pubkey]\n");
6357 if ( ensure_CCrequirements() < 0 )
6358 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6359 if ( params.size() == 1 )
6360 pubkey = ParseHex(params[0].get_str().c_str());
6361 return(CCaddress(cp,(char *)"Gateways",pubkey));
6364 UniValue mofnaddress(const UniValue& params, bool fHelp)
6366 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6367 cp = CCinit(&C,EVAL_MOFN);
6368 if ( fHelp || params.size() > 1 )
6369 throw runtime_error("mofnaddress [pubkey]\n");
6370 if ( ensure_CCrequirements() < 0 )
6371 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6372 if ( params.size() == 1 )
6373 pubkey = ParseHex(params[0].get_str().c_str());
6374 return(CCaddress(cp,(char *)"MofN",pubkey));
6377 UniValue lottoaddress(const UniValue& params, bool fHelp)
6379 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6380 cp = CCinit(&C,EVAL_LOTTO);
6381 if ( fHelp || params.size() > 1 )
6382 throw runtime_error("lottoaddress [pubkey]\n");
6383 if ( ensure_CCrequirements() < 0 )
6384 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6385 if ( params.size() == 1 )
6386 pubkey = ParseHex(params[0].get_str().c_str());
6387 return(CCaddress(cp,(char *)"Lotto",pubkey));
6390 UniValue FSMaddress(const UniValue& params, bool fHelp)
6392 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6393 cp = CCinit(&C,EVAL_FSM);
6394 if ( fHelp || params.size() > 1 )
6395 throw runtime_error("FSMaddress [pubkey]\n");
6396 if ( ensure_CCrequirements() < 0 )
6397 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6398 if ( params.size() == 1 )
6399 pubkey = ParseHex(params[0].get_str().c_str());
6400 return(CCaddress(cp,(char *)"FSM",pubkey));
6403 UniValue auctionaddress(const UniValue& params, bool fHelp)
6405 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6406 cp = CCinit(&C,EVAL_AUCTION);
6407 if ( fHelp || params.size() > 1 )
6408 throw runtime_error("auctionaddress [pubkey]\n");
6409 if ( ensure_CCrequirements() < 0 )
6410 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6411 if ( params.size() == 1 )
6412 pubkey = ParseHex(params[0].get_str().c_str());
6413 return(CCaddress(cp,(char *)"Auction",pubkey));
6416 UniValue diceaddress(const UniValue& params, bool fHelp)
6418 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6419 cp = CCinit(&C,EVAL_DICE);
6420 if ( fHelp || params.size() > 1 )
6421 throw runtime_error("diceaddress [pubkey]\n");
6422 if ( ensure_CCrequirements() < 0 )
6423 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6424 if ( params.size() == 1 )
6425 pubkey = ParseHex(params[0].get_str().c_str());
6426 return(CCaddress(cp,(char *)"Dice",pubkey));
6429 UniValue faucetaddress(const UniValue& params, bool fHelp)
6431 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6433 cp = CCinit(&C,EVAL_FAUCET);
6434 if ( fHelp || params.size() > 1 )
6435 throw runtime_error("faucetaddress [pubkey]\n");
6436 errno = ensure_CCrequirements();
6438 throw runtime_error(strprintf("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet. ERR=%d\n", errno));
6439 if ( params.size() == 1 )
6440 pubkey = ParseHex(params[0].get_str().c_str());
6441 return(CCaddress(cp,(char *)"Faucet",pubkey));
6444 UniValue rewardsaddress(const UniValue& params, bool fHelp)
6446 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6447 cp = CCinit(&C,EVAL_REWARDS);
6448 if ( fHelp || params.size() > 1 )
6449 throw runtime_error("rewardsaddress [pubkey]\n");
6450 if ( ensure_CCrequirements() < 0 )
6451 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6452 if ( params.size() == 1 )
6453 pubkey = ParseHex(params[0].get_str().c_str());
6454 return(CCaddress(cp,(char *)"Rewards",pubkey));
6457 UniValue tokenaddress(const UniValue& params, bool fHelp)
6459 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6460 cp = CCinit(&C,EVAL_ASSETS);
6461 if ( fHelp || params.size() > 1 )
6462 throw runtime_error("tokenaddress [pubkey]\n");
6463 if ( ensure_CCrequirements() < 0 )
6464 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6465 if ( params.size() == 1 )
6466 pubkey = ParseHex(params[0].get_str().c_str());
6467 return(CCaddress(cp,(char *)"Assets",pubkey));
6470 UniValue channelsinfo(const UniValue& params, bool fHelp)
6472 if ( fHelp || params.size() != 0 )
6473 throw runtime_error("channelsinfo\n");
6474 if ( ensure_CCrequirements() < 0 )
6475 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6476 return(ChannelsInfo());
6479 UniValue channelsopen(const UniValue& params, bool fHelp)
6481 UniValue result(UniValue::VOBJ); int32_t numpayments; int64_t payment; std::vector<unsigned char> destpub; struct CCcontract_info *cp,C; std::string hex;
6482 cp = CCinit(&C,EVAL_CHANNELS);
6483 if ( fHelp || params.size() != 3 )
6484 throw runtime_error("channelsopen destpubkey numpayments payment\n");
6485 if ( ensure_CCrequirements() < 0 )
6486 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6488 destpub = ParseHex(params[0].get_str().c_str());
6489 numpayments = atoi(params[1].get_str().c_str());
6490 payment = atol(params[2].get_str().c_str());
6491 hex = ChannelOpen(0,pubkey2pk(destpub),numpayments,payment);
6492 if ( hex.size() > 0 )
6494 result.push_back(Pair("result", "success"));
6495 result.push_back(Pair("hex", hex));
6496 } else ERR_RESULT("couldnt create channelsopen transaction");
6500 UniValue channelsstop(const UniValue& params, bool fHelp)
6502 UniValue result(UniValue::VOBJ); std::vector<unsigned char> destpub; struct CCcontract_info *cp,C; std::string hex; uint256 origtxid;
6503 cp = CCinit(&C,EVAL_CHANNELS);
6504 if ( fHelp || params.size() != 2 )
6505 throw runtime_error("channelsstop destpubkey origtxid\n");
6506 if ( ensure_CCrequirements() < 0 )
6507 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6509 destpub = ParseHex(params[0].get_str().c_str());
6510 origtxid = Parseuint256((char *)params[1].get_str().c_str());
6511 hex = ChannelStop(0,pubkey2pk(destpub),origtxid);
6512 if ( hex.size() > 0 )
6514 result.push_back(Pair("result", "success"));
6515 result.push_back(Pair("hex", hex));
6516 } else ERR_RESULT("couldnt create channelsstop transaction");
6520 UniValue channelspayment(const UniValue& params, bool fHelp)
6522 UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 origtxid,prevtxid; int32_t n; int64_t amount;
6523 cp = CCinit(&C,EVAL_CHANNELS);
6524 if ( fHelp || params.size() != 4 )
6525 throw runtime_error("channelspayment prevtxid origtxid n amount\n");
6526 if ( ensure_CCrequirements() < 0 )
6527 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6529 prevtxid = Parseuint256((char *)params[0].get_str().c_str());
6530 origtxid = Parseuint256((char *)params[1].get_str().c_str());
6531 n = atoi((char *)params[2].get_str().c_str());
6532 amount = atoi((char *)params[3].get_str().c_str());
6533 hex = ChannelPayment(0,prevtxid,origtxid,n,amount);
6534 if ( hex.size() > 0 )
6536 result.push_back(Pair("result", "success"));
6537 result.push_back(Pair("hex", hex));
6538 } else ERR_RESULT("couldnt create channelspayment transaction");
6542 UniValue channelscollect(const UniValue& params, bool fHelp)
6544 UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 origtxid,paytxid; int32_t n; int64_t amount;
6545 cp = CCinit(&C,EVAL_CHANNELS);
6546 if ( fHelp || params.size() != 4 )
6547 throw runtime_error("channelscollect paytxid origtxid n amount\n");
6548 if ( ensure_CCrequirements() < 0 )
6549 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6551 paytxid = Parseuint256((char *)params[0].get_str().c_str());
6552 origtxid = Parseuint256((char *)params[1].get_str().c_str());
6553 n = atoi((char *)params[2].get_str().c_str());
6554 amount = atoi((char *)params[3].get_str().c_str());
6555 hex = ChannelCollect(0,paytxid,origtxid,n,amount);
6556 if ( hex.size() > 0 )
6558 result.push_back(Pair("result", "success"));
6559 result.push_back(Pair("hex", hex));
6560 } else ERR_RESULT("couldnt create channelscollect transaction");
6564 UniValue channelsrefund(const UniValue& params, bool fHelp)
6566 UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 origtxid,stoptxid;
6567 cp = CCinit(&C,EVAL_CHANNELS);
6568 if ( fHelp || params.size() != 2 )
6569 throw runtime_error("channelsrefund stoptxid origtxid\n");
6570 if ( ensure_CCrequirements() < 0 )
6571 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6573 stoptxid = Parseuint256((char *)params[0].get_str().c_str());
6574 origtxid = Parseuint256((char *)params[1].get_str().c_str());
6575 hex = ChannelRefund(0,stoptxid,origtxid);
6576 if ( hex.size() > 0 )
6578 result.push_back(Pair("result", "success"));
6579 result.push_back(Pair("hex", hex));
6580 } else ERR_RESULT("couldnt create channelsrefund transaction");
6584 UniValue rewardscreatefunding(const UniValue& params, bool fHelp)
6586 UniValue result(UniValue::VOBJ); char *name; int64_t funds,APR,minseconds,maxseconds,mindeposit; std::string hex;
6587 if ( fHelp || params.size() > 6 || params.size() < 2 )
6588 throw runtime_error("rewardscreatefunding name amount APR mindays maxdays mindeposit\n");
6589 if ( ensure_CCrequirements() < 0 )
6590 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6591 const CKeyStore& keystore = *pwalletMain;
6592 LOCK2(cs_main, pwalletMain->cs_wallet);
6593 // default to OOT params
6595 minseconds = maxseconds = 60 * 3600 * 24;
6596 mindeposit = 100 * COIN;
6597 name = (char *)params[0].get_str().c_str();
6598 funds = atof(params[1].get_str().c_str()) * COIN;
6600 if (!VALID_PLAN_NAME(name)) {
6601 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
6606 ERR_RESULT("funds must be positive");
6609 if ( params.size() > 2 )
6611 APR = atof(params[2].get_str().c_str()) * COIN;
6612 if ( APR > REWARDSCC_MAXAPR )
6614 ERR_RESULT("25% APR is maximum");
6617 if ( params.size() > 3 )
6619 minseconds = atol(params[3].get_str().c_str()) * 3600 * 24;
6620 if ( minseconds < 0 ) {
6621 ERR_RESULT("mindays must be non-negative");
6624 if ( params.size() > 4 )
6626 maxseconds = atol(params[4].get_str().c_str()) * 3600 * 24;
6627 if ( maxseconds <= 0 ) {
6628 ERR_RESULT("maxdays must be positive");
6631 if ( maxseconds < minseconds ) {
6632 ERR_RESULT("maxdays must be greater than mindays");
6635 if ( params.size() > 5 )
6636 mindeposit = atof(params[5].get_str().c_str()) * COIN;
6637 if ( mindeposit <= 0 ) {
6638 ERR_RESULT("mindeposit must be positive");
6644 hex = RewardsCreateFunding(0,name,funds,APR,minseconds,maxseconds,mindeposit);
6645 if ( hex.size() > 0 )
6647 result.push_back(Pair("result", "success"));
6648 result.push_back(Pair("hex", hex));
6649 } else ERR_RESULT("couldnt create rewards funding transaction");
6653 UniValue rewardslock(const UniValue& params, bool fHelp)
6655 UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid; int64_t amount; std::string hex;
6656 if ( fHelp || params.size() != 3 )
6657 throw runtime_error("rewardslock name fundingtxid amount\n");
6658 if ( ensure_CCrequirements() < 0 )
6659 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6660 const CKeyStore& keystore = *pwalletMain;
6661 LOCK2(cs_main, pwalletMain->cs_wallet);
6662 name = (char *)params[0].get_str().c_str();
6663 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
6664 amount = atof(params[2].get_str().c_str()) * COIN;
6665 hex = RewardsLock(0,name,fundingtxid,amount);
6667 if (!VALID_PLAN_NAME(name)) {
6668 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
6671 if ( CCerror != "" ){
6672 ERR_RESULT(CCerror);
6673 } else if ( amount > 0 ) {
6674 if ( hex.size() > 0 )
6676 result.push_back(Pair("result", "success"));
6677 result.push_back(Pair("hex", hex));
6678 } else ERR_RESULT( "couldnt create rewards lock transaction");
6679 } else ERR_RESULT("amount must be positive");
6683 UniValue rewardsaddfunding(const UniValue& params, bool fHelp)
6685 UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid; int64_t amount; std::string hex;
6686 if ( fHelp || params.size() != 3 )
6687 throw runtime_error("rewardsaddfunding name fundingtxid amount\n");
6688 if ( ensure_CCrequirements() < 0 )
6689 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6690 const CKeyStore& keystore = *pwalletMain;
6691 LOCK2(cs_main, pwalletMain->cs_wallet);
6692 name = (char *)params[0].get_str().c_str();
6693 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
6694 amount = atof(params[2].get_str().c_str()) * COIN;
6695 hex = RewardsAddfunding(0,name,fundingtxid,amount);
6697 if (!VALID_PLAN_NAME(name)) {
6698 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
6701 if (CCerror != "") {
6702 ERR_RESULT(CCerror);
6703 } else if (amount > 0) {
6704 if ( hex.size() > 0 )
6706 result.push_back(Pair("result", "success"));
6707 result.push_back(Pair("hex", hex));
6709 result.push_back(Pair("result", "error"));
6710 result.push_back(Pair("error", "couldnt create rewards addfunding transaction"));
6713 ERR_RESULT("funding amount must be positive");
6718 UniValue rewardsunlock(const UniValue& params, bool fHelp)
6720 UniValue result(UniValue::VOBJ); std::string hex; char *name; uint256 fundingtxid,txid;
6721 if ( fHelp || params.size() > 3 || params.size() < 2 )
6722 throw runtime_error("rewardsunlock name fundingtxid [txid]\n");
6723 if ( ensure_CCrequirements() < 0 )
6724 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6725 const CKeyStore& keystore = *pwalletMain;
6726 LOCK2(cs_main, pwalletMain->cs_wallet);
6727 name = (char *)params[0].get_str().c_str();
6728 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
6730 if (!VALID_PLAN_NAME(name)) {
6731 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
6734 if ( params.size() > 2 )
6735 txid = Parseuint256((char *)params[2].get_str().c_str());
6736 else memset(&txid,0,sizeof(txid));
6737 hex = RewardsUnlock(0,name,fundingtxid,txid);
6738 if (CCerror != "") {
6739 ERR_RESULT(CCerror);
6740 } else if ( hex.size() > 0 ) {
6741 result.push_back(Pair("result", "success"));
6742 result.push_back(Pair("hex", hex));
6743 } else ERR_RESULT("couldnt create rewards unlock transaction");
6747 UniValue rewardslist(const UniValue& params, bool fHelp)
6749 if ( fHelp || params.size() > 0 )
6750 throw runtime_error("rewardslist\n");
6751 if ( ensure_CCrequirements() < 0 )
6752 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6753 return(RewardsList());
6756 UniValue rewardsinfo(const UniValue& params, bool fHelp)
6758 uint256 fundingtxid;
6759 if ( fHelp || params.size() != 1 )
6760 throw runtime_error("rewardsinfo fundingtxid\n");
6761 if ( ensure_CCrequirements() < 0 )
6762 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6763 fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
6764 return(RewardsInfo(fundingtxid));
6767 UniValue gatewayslist(const UniValue& params, bool fHelp)
6769 if ( fHelp || params.size() > 0 )
6770 throw runtime_error("gatewayslist\n");
6771 if ( ensure_CCrequirements() < 0 )
6772 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6773 return(GatewaysList());
6776 UniValue gatewaysinfo(const UniValue& params, bool fHelp)
6779 if ( fHelp || params.size() != 1 )
6780 throw runtime_error("gatewaysinfo bindtxid\n");
6781 if ( ensure_CCrequirements() < 0 )
6782 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6783 txid = Parseuint256((char *)params[0].get_str().c_str());
6784 return(GatewaysInfo(txid));
6787 UniValue gatewaysbind(const UniValue& params, bool fHelp)
6789 UniValue result(UniValue::VOBJ); uint256 tokenid,oracletxid; int32_t i; int64_t totalsupply; std::vector<CPubKey> pubkeys; uint8_t M,N; std::string hex,coin; std::vector<unsigned char> pubkey;
6790 if ( fHelp || params.size() < 6 )
6791 throw runtime_error("gatewaysbind tokenid oracletxid coin tokensupply M N pubkey(s)\n");
6792 if ( ensure_CCrequirements() < 0 )
6793 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6794 tokenid = Parseuint256((char *)params[0].get_str().c_str());
6795 oracletxid = Parseuint256((char *)params[1].get_str().c_str());
6796 coin = params[2].get_str();
6797 totalsupply = atol((char *)params[3].get_str().c_str());
6798 M = atoi((char *)params[4].get_str().c_str());
6799 N = atoi((char *)params[5].get_str().c_str());
6800 if ( M > N || N == 0 || N > 15 || totalsupply < COIN/100 || tokenid == zeroid )
6801 throw runtime_error("illegal M or N > 15 or tokensupply or invalid tokenid\n");
6804 if ( params.size() < 6+i+1 )
6805 throw runtime_error("not enough parameters for N pubkeys\n");
6806 pubkey = ParseHex(params[6+i].get_str().c_str());
6807 pubkeys.push_back(pubkey2pk(pubkey));
6809 hex = GatewaysBind(0,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys);
6810 if ( hex.size() > 0 )
6812 result.push_back(Pair("result", "success"));
6813 result.push_back(Pair("hex", hex));
6814 } else ERR_RESULT("couldnt gatewaysbind");
6818 UniValue gatewaysdeposit(const UniValue& params, bool fHelp)
6820 UniValue result(UniValue::VOBJ); int32_t i,claimvout,height; int64_t amount; std::string hex,coin,deposithex; uint256 bindtxid,cointxid; std::vector<uint8_t>proof,destpub,pubkey;
6821 if ( fHelp || params.size() != 9 )
6822 throw runtime_error("gatewaysdeposit bindtxid height coin cointxid claimvout deposithex proof destpub amount\n");
6823 if ( ensure_CCrequirements() < 0 )
6824 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6825 bindtxid = Parseuint256((char *)params[0].get_str().c_str());
6826 height = atoi((char *)params[1].get_str().c_str());
6827 coin = params[2].get_str();
6828 cointxid = Parseuint256((char *)params[3].get_str().c_str());
6829 claimvout = atoi((char *)params[4].get_str().c_str());
6830 deposithex = params[5].get_str();
6831 proof = ParseHex(params[6].get_str());
6832 destpub = ParseHex(params[7].get_str());
6833 amount = atof((char *)params[8].get_str().c_str()) * COIN;
6834 if ( amount <= 0 || claimvout < 0 )
6835 throw runtime_error("invalid param: amount, numpks or claimvout\n");
6836 hex = GatewaysDeposit(0,bindtxid,height,coin,cointxid,claimvout,deposithex,proof,pubkey2pk(destpub),amount);
6837 if ( hex.size() > 0 )
6839 result.push_back(Pair("result", "success"));
6840 result.push_back(Pair("hex", hex));
6841 } else ERR_RESULT("couldnt gatewaysdeposit");
6845 UniValue gatewaysclaim(const UniValue& params, bool fHelp)
6847 UniValue result(UniValue::VOBJ); std::string hex,coin; uint256 bindtxid,deposittxid; std::vector<uint8_t>destpub; int64_t amount;
6848 if ( fHelp || params.size() != 5 )
6849 throw runtime_error("gatewaysclaim bindtxid coin deposittxid destpub amount\n");
6850 if ( ensure_CCrequirements() < 0 )
6851 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6852 bindtxid = Parseuint256((char *)params[0].get_str().c_str());
6853 coin = params[1].get_str();
6854 deposittxid = Parseuint256((char *)params[2].get_str().c_str());
6855 destpub = ParseHex(params[3].get_str());
6856 amount = atof((char *)params[4].get_str().c_str()) * COIN;
6857 hex = GatewaysClaim(0,bindtxid,coin,deposittxid,pubkey2pk(destpub),amount);
6858 if ( hex.size() > 0 )
6860 result.push_back(Pair("result", "success"));
6861 result.push_back(Pair("hex", hex));
6862 } else ERR_RESULT("couldnt gatewaysclaim");
6866 UniValue gatewayswithdraw(const UniValue& params, bool fHelp)
6868 UniValue result(UniValue::VOBJ); uint256 bindtxid; int64_t amount; std::string hex,coin; std::vector<uint8_t> withdrawpub;
6869 if ( fHelp || params.size() != 4 )
6870 throw runtime_error("gatewayswithdraw bindtxid coin withdrawpub amount\n");
6871 if ( ensure_CCrequirements() < 0 )
6872 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6873 bindtxid = Parseuint256((char *)params[0].get_str().c_str());
6874 coin = params[1].get_str();
6875 withdrawpub = ParseHex(params[2].get_str());
6876 amount = atof((char *)params[3].get_str().c_str()) * COIN;
6877 hex = GatewaysWithdraw(0,bindtxid,coin,withdrawpub,amount);
6878 if ( hex.size() > 0 )
6880 result.push_back(Pair("result", "success"));
6881 result.push_back(Pair("hex", hex));
6882 } else ERR_RESULT("couldnt gatewayswithdraw");
6886 UniValue gatewaysmarkdone(const UniValue& params, bool fHelp)
6888 UniValue result(UniValue::VOBJ); uint256 withdrawtxid; std::string hex;
6889 if ( fHelp || params.size() != 1 )
6890 throw runtime_error("gatewaysmarkdone withdrawtxid\n");
6891 if ( ensure_CCrequirements() < 0 )
6892 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6893 withdrawtxid = Parseuint256((char *)params[0].get_str().c_str());
6894 hex = GatewaysMarkdone(0,withdrawtxid);
6895 if ( hex.size() > 0 )
6897 result.push_back(Pair("result", "success"));
6898 result.push_back(Pair("hex", hex));
6899 } else ERR_RESULT("couldnt gatewaysmarkdone");
6903 UniValue gatewayspending(const UniValue& params, bool fHelp)
6905 uint256 bindtxid; std::string coin;
6906 if ( fHelp || params.size() != 2 )
6907 throw runtime_error("gatewayspending bindtxid coin\n");
6908 if ( ensure_CCrequirements() < 0 )
6909 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6910 bindtxid = Parseuint256((char *)params[0].get_str().c_str());
6911 coin = params[1].get_str();
6912 return(GatewaysPendingWithdraws(bindtxid,coin));
6915 UniValue oracleslist(const UniValue& params, bool fHelp)
6917 if ( fHelp || params.size() > 0 )
6918 throw runtime_error("oracleslist\n");
6919 if ( ensure_CCrequirements() < 0 )
6920 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6921 return(OraclesList());
6924 UniValue oraclesinfo(const UniValue& params, bool fHelp)
6927 if ( fHelp || params.size() != 1 )
6928 throw runtime_error("oraclesinfo oracletxid\n");
6929 if ( ensure_CCrequirements() < 0 )
6930 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6931 txid = Parseuint256((char *)params[0].get_str().c_str());
6932 return(OracleInfo(txid));
6935 UniValue oraclesregister(const UniValue& params, bool fHelp)
6937 UniValue result(UniValue::VOBJ); uint256 txid; int64_t datafee; std::string hex;
6938 if ( fHelp || params.size() != 2 )
6939 throw runtime_error("oraclesregister oracletxid datafee\n");
6940 if ( ensure_CCrequirements() < 0 )
6941 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6942 txid = Parseuint256((char *)params[0].get_str().c_str());
6943 datafee = atol((char *)params[1].get_str().c_str());
6944 hex = OracleRegister(0,txid,datafee);
6945 if ( hex.size() > 0 )
6947 result.push_back(Pair("result", "success"));
6948 result.push_back(Pair("hex", hex));
6949 } else ERR_RESULT("couldnt register with oracle txid");
6953 UniValue oraclessubscribe(const UniValue& params, bool fHelp)
6955 UniValue result(UniValue::VOBJ); uint256 txid; int64_t amount; std::string hex; std::vector<unsigned char> pubkey;
6956 if ( fHelp || params.size() != 3 )
6957 throw runtime_error("oraclessubscribe oracletxid publisher amount\n");
6958 if ( ensure_CCrequirements() < 0 )
6959 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6960 txid = Parseuint256((char *)params[0].get_str().c_str());
6961 pubkey = ParseHex(params[1].get_str().c_str());
6962 amount = atof((char *)params[2].get_str().c_str()) * COIN;
6963 hex = OracleSubscribe(0,txid,pubkey2pk(pubkey),amount);
6964 if ( hex.size() > 0 )
6966 result.push_back(Pair("result", "success"));
6967 result.push_back(Pair("hex", hex));
6968 } else ERR_RESULT("couldnt subscribe with oracle txid");
6972 UniValue oraclessamples(const UniValue& params, bool fHelp)
6974 UniValue result(UniValue::VOBJ); uint256 txid,batontxid; int32_t num;
6975 if ( fHelp || params.size() != 3 )
6976 throw runtime_error("oraclessamples oracletxid batonutxo num\n");
6977 if ( ensure_CCrequirements() < 0 )
6978 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6979 txid = Parseuint256((char *)params[0].get_str().c_str());
6980 batontxid = Parseuint256((char *)params[1].get_str().c_str());
6981 num = atoi((char *)params[2].get_str().c_str());
6982 return(OracleDataSamples(txid,batontxid,num));
6985 UniValue oraclesdata(const UniValue& params, bool fHelp)
6987 UniValue result(UniValue::VOBJ); uint256 txid; std::vector<unsigned char> data; std::string hex;
6988 if ( fHelp || params.size() != 2 )
6989 throw runtime_error("oraclesdata oracletxid hexstr\n");
6990 if ( ensure_CCrequirements() < 0 )
6991 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6992 txid = Parseuint256((char *)params[0].get_str().c_str());
6993 data = ParseHex(params[1].get_str().c_str());
6994 hex = OracleData(0,txid,data);
6995 if ( hex.size() > 0 )
6997 result.push_back(Pair("result", "success"));
6998 result.push_back(Pair("hex", hex));
6999 } else ERR_RESULT("couldnt publish data with oracle txid");
7003 UniValue oraclescreate(const UniValue& params, bool fHelp)
7005 UniValue result(UniValue::VOBJ); std::string name,description,format,hex;
7006 if ( fHelp || params.size() != 3 )
7007 throw runtime_error("oraclescreate name description format\n");
7008 if ( ensure_CCrequirements() < 0 )
7009 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7010 const CKeyStore& keystore = *pwalletMain;
7011 LOCK2(cs_main, pwalletMain->cs_wallet);
7012 name = params[0].get_str();
7013 if ( name.size() == 0 || name.size() > 32)
7015 ERR_RESULT("oracles name must not be empty and up to 32 characters");
7018 description = params[1].get_str();
7019 if ( description.size() > 4096 )
7021 ERR_RESULT("oracles description must be <= 4096 characters");
7024 format = params[2].get_str();
7025 if ( format.size() > 4096 )
7027 ERR_RESULT("oracles format must be <= 4096 characters");
7030 hex = OracleCreate(0,name,description,format);
7031 if ( hex.size() > 0 )
7033 result.push_back(Pair("result", "success"));
7034 result.push_back(Pair("hex", hex));
7035 } else ERR_RESULT("couldnt create oracle");
7039 UniValue FSMcreate(const UniValue& params, bool fHelp)
7041 UniValue result(UniValue::VOBJ); std::string name,states,hex;
7042 if ( fHelp || params.size() != 2 )
7043 throw runtime_error("FSMcreate name states\n");
7044 if ( ensure_CCrequirements() < 0 )
7045 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7046 const CKeyStore& keystore = *pwalletMain;
7047 LOCK2(cs_main, pwalletMain->cs_wallet);
7048 name = params[0].get_str();
7049 states = params[1].get_str();
7050 hex = FSMCreate(0,name,states);
7051 if ( hex.size() > 0 )
7053 result.push_back(Pair("result", "success"));
7054 result.push_back(Pair("hex", hex));
7055 } else result.push_back(Pair("error", "couldnt create FSM transaction"));
7059 UniValue FSMlist(const UniValue& params, bool fHelp)
7062 if ( fHelp || params.size() > 0 )
7063 throw runtime_error("FSMlist\n");
7064 if ( ensure_CCrequirements() < 0 )
7065 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7069 UniValue FSMinfo(const UniValue& params, bool fHelp)
7072 if ( fHelp || params.size() != 1 )
7073 throw runtime_error("FSMinfo fundingtxid\n");
7074 if ( ensure_CCrequirements() < 0 )
7075 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7076 FSMtxid = Parseuint256((char *)params[0].get_str().c_str());
7077 return(FSMInfo(FSMtxid));
7080 UniValue faucetinfo(const UniValue& params, bool fHelp)
7082 uint256 fundingtxid;
7083 if ( fHelp || params.size() != 0 )
7084 throw runtime_error("faucetinfo\n");
7085 if ( ensure_CCrequirements() < 0 )
7086 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7087 return(FaucetInfo());
7090 UniValue faucetfund(const UniValue& params, bool fHelp)
7092 UniValue result(UniValue::VOBJ); int64_t funds; std::string hex;
7093 if ( fHelp || params.size() > 1 )
7094 throw runtime_error("faucetfund amount\n");
7095 if ( ensure_CCrequirements() < 0 )
7096 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7097 const CKeyStore& keystore = *pwalletMain;
7098 LOCK2(cs_main, pwalletMain->cs_wallet);
7099 funds = atof(params[0].get_str().c_str()) * COIN;
7101 hex = FaucetFund(0,(uint64_t) funds);
7102 if ( hex.size() > 0 )
7104 result.push_back(Pair("result", "success"));
7105 result.push_back(Pair("hex", hex));
7106 } else ERR_RESULT("couldnt create faucet funding transaction");
7107 } else ERR_RESULT( "funding amount must be positive");
7111 UniValue faucetget(const UniValue& params, bool fHelp)
7113 UniValue result(UniValue::VOBJ); std::string hex;
7114 if ( fHelp || params.size() > 0 )
7115 throw runtime_error("faucetget\n");
7116 if ( ensure_CCrequirements() < 0 )
7117 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7118 const CKeyStore& keystore = *pwalletMain;
7119 LOCK2(cs_main, pwalletMain->cs_wallet);
7121 if ( hex.size() > 0 ) {
7122 result.push_back(Pair("result", "success"));
7123 result.push_back(Pair("hex", hex));
7124 } else ERR_RESULT("couldnt create faucet get transaction");
7128 UniValue dicefund(const UniValue& params, bool fHelp)
7130 UniValue result(UniValue::VOBJ); int64_t funds,minbet,maxbet,maxodds,timeoutblocks; std::string hex; char *name;
7131 if ( fHelp || params.size() != 6 )
7132 throw runtime_error("dicefund name funds minbet maxbet maxodds timeoutblocks\n");
7133 if ( ensure_CCrequirements() < 0 )
7134 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7135 const CKeyStore& keystore = *pwalletMain;
7136 LOCK2(cs_main, pwalletMain->cs_wallet);
7137 name = (char *)params[0].get_str().c_str();
7138 funds = atof(params[1].get_str().c_str()) * COIN;
7139 minbet = atof(params[2].get_str().c_str()) * COIN;
7140 maxbet = atof(params[3].get_str().c_str()) * COIN;
7141 maxodds = atol(params[4].get_str().c_str());
7142 timeoutblocks = atol(params[5].get_str().c_str());
7144 if (!VALID_PLAN_NAME(name)) {
7145 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
7149 hex = DiceCreateFunding(0,name,funds,minbet,maxbet,maxodds,timeoutblocks);
7150 if (CCerror != "") {
7151 ERR_RESULT(CCerror);
7152 } else if ( hex.size() > 0 ) {
7153 result.push_back(Pair("result", "success"));
7154 result.push_back(Pair("hex", hex));
7156 ERR_RESULT( "couldnt create dice funding transaction");
7161 UniValue diceaddfunds(const UniValue& params, bool fHelp)
7163 UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid; int64_t amount; std::string hex;
7164 if ( fHelp || params.size() != 3 )
7165 throw runtime_error("diceaddfunds name fundingtxid amount\n");
7166 if ( ensure_CCrequirements() < 0 )
7167 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7168 const CKeyStore& keystore = *pwalletMain;
7169 LOCK2(cs_main, pwalletMain->cs_wallet);
7170 name = (char *)params[0].get_str().c_str();
7171 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
7172 amount = atof(params[2].get_str().c_str()) * COIN;
7173 if (!VALID_PLAN_NAME(name)) {
7174 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
7178 hex = DiceAddfunding(0,name,fundingtxid,amount);
7179 if (CCerror != "") {
7180 ERR_RESULT(CCerror);
7181 } else if ( hex.size() > 0 ) {
7182 result.push_back(Pair("result", "success"));
7183 result.push_back(Pair("hex", hex));
7184 } else ERR_RESULT("couldnt create dice addfunding transaction");
7185 } else ERR_RESULT("amount must be positive");
7189 UniValue dicebet(const UniValue& params, bool fHelp)
7191 UniValue result(UniValue::VOBJ); std::string hex; uint256 fundingtxid; int64_t amount,odds; char *name;
7192 if ( fHelp || params.size() != 4 )
7193 throw runtime_error("dicebet name fundingtxid amount odds\n");
7194 if ( ensure_CCrequirements() < 0 )
7195 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7196 const CKeyStore& keystore = *pwalletMain;
7197 LOCK2(cs_main, pwalletMain->cs_wallet);
7198 name = (char *)params[0].get_str().c_str();
7199 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
7200 amount = atof(params[2].get_str().c_str()) * COIN;
7201 odds = atol(params[3].get_str().c_str());
7203 if (!VALID_PLAN_NAME(name)) {
7204 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
7207 if (amount > 0 && odds > 0) {
7208 hex = DiceBet(0,name,fundingtxid,amount,odds);
7209 if ( hex.size() > 0 )
7211 result.push_back(Pair("result", "success"));
7212 result.push_back(Pair("hex", hex));
7213 } else ERR_RESULT("couldnt create dice bet transaction. make sure your address has funds");
7215 ERR_RESULT("amount and odds must be positive");
7220 UniValue dicefinish(const UniValue& params, bool fHelp)
7222 UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid,bettxid; std::string hex; int32_t r;
7223 if ( fHelp || params.size() != 3 )
7224 throw runtime_error("dicefinish name fundingtxid bettxid\n");
7225 if ( ensure_CCrequirements() < 0 )
7226 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7227 const CKeyStore& keystore = *pwalletMain;
7228 LOCK2(cs_main, pwalletMain->cs_wallet);
7229 name = (char *)params[0].get_str().c_str();
7230 if (!VALID_PLAN_NAME(name)) {
7231 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
7234 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
7235 bettxid = Parseuint256((char *)params[2].get_str().c_str());
7236 hex = DiceBetFinish(&r,0,name,fundingtxid,bettxid,1);
7237 if ( CCerror != "" )
7239 ERR_RESULT(CCerror);
7240 } else if ( hex.size() > 0 )
7242 result.push_back(Pair("result", "success"));
7243 result.push_back(Pair("hex", hex));
7244 } else ERR_RESULT( "couldnt create dicefinish transaction");
7248 UniValue dicestatus(const UniValue& params, bool fHelp)
7250 UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid,bettxid; std::string status; double winnings;
7251 if ( fHelp || (params.size() != 2 && params.size() != 3) )
7252 throw runtime_error("dicestatus name fundingtxid bettxid\n");
7253 if ( ensure_CCrequirements() < 0 )
7254 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7255 const CKeyStore& keystore = *pwalletMain;
7256 LOCK2(cs_main, pwalletMain->cs_wallet);
7257 name = (char *)params[0].get_str().c_str();
7258 if (!VALID_PLAN_NAME(name)) {
7259 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
7262 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
7263 memset(&bettxid,0,sizeof(bettxid));
7264 if ( params.size() == 3 )
7265 bettxid = Parseuint256((char *)params[2].get_str().c_str());
7266 winnings = DiceStatus(0,name,fundingtxid,bettxid);
7267 if (CCerror != "") {
7268 ERR_RESULT(CCerror);
7271 result.push_back(Pair("result", "success"));
7272 if ( winnings >= 0. )
7274 if ( winnings > 0. )
7276 if ( params.size() == 3 )
7278 result.push_back(Pair("status", "win"));
7279 result.push_back(Pair("won", winnings));
7283 result.push_back(Pair("status", "finalized"));
7284 result.push_back(Pair("n", (int64_t)winnings));
7289 if ( params.size() == 3 )
7290 result.push_back(Pair("status", "loss"));
7291 else result.push_back(Pair("status", "no pending bets"));
7293 } else result.push_back(Pair("status", "bet still pending"));
7297 UniValue dicelist(const UniValue& params, bool fHelp)
7300 if ( fHelp || params.size() > 0 )
7301 throw runtime_error("dicelist\n");
7302 if ( ensure_CCrequirements() < 0 )
7303 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7307 UniValue diceinfo(const UniValue& params, bool fHelp)
7309 uint256 fundingtxid;
7310 if ( fHelp || params.size() != 1 )
7311 throw runtime_error("diceinfo fundingtxid\n");
7312 if ( ensure_CCrequirements() < 0 )
7313 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7314 fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
7315 return(DiceInfo(fundingtxid));
7318 UniValue tokenlist(const UniValue& params, bool fHelp)
7321 if ( fHelp || params.size() > 0 )
7322 throw runtime_error("tokenlist\n");
7323 if ( ensure_CCrequirements() < 0 )
7324 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7325 return(AssetList());
7328 UniValue tokeninfo(const UniValue& params, bool fHelp)
7331 if ( fHelp || params.size() != 1 )
7332 throw runtime_error("tokeninfo tokenid\n");
7333 if ( ensure_CCrequirements() < 0 )
7334 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7335 tokenid = Parseuint256((char *)params[0].get_str().c_str());
7336 return(AssetInfo(tokenid));
7339 UniValue tokenorders(const UniValue& params, bool fHelp)
7342 if ( fHelp || params.size() > 1 )
7343 throw runtime_error("tokenorders [tokenid]\n");
7344 if ( ensure_CCrequirements() < 0 )
7345 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7346 if ( params.size() == 1 )
7347 tokenid = Parseuint256((char *)params[0].get_str().c_str());
7348 else memset(&tokenid,0,sizeof(tokenid));
7349 return(AssetOrders(tokenid));
7352 UniValue tokenbalance(const UniValue& params, bool fHelp)
7354 UniValue result(UniValue::VOBJ); char destaddr[64]; uint256 tokenid; uint64_t balance; std::vector<unsigned char> pubkey; struct CCcontract_info *cp,C;
7355 cp = CCinit(&C,EVAL_ASSETS);
7356 if ( fHelp || params.size() > 2 )
7357 throw runtime_error("tokenbalance tokenid [pubkey]\n");
7358 if ( ensure_CCrequirements() < 0 )
7359 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7361 tokenid = Parseuint256((char *)params[0].get_str().c_str());
7362 if ( params.size() == 2 )
7363 pubkey = ParseHex(params[1].get_str().c_str());
7364 else pubkey = Mypubkey();
7365 result.push_back(Pair("result", "success"));
7366 if ( GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0 )
7367 result.push_back(Pair("CCaddress",destaddr));
7368 balance = GetAssetBalance(pubkey2pk(pubkey),tokenid);
7369 result.push_back(Pair("tokenid", params[0].get_str()));
7370 result.push_back(Pair("balance", (int64_t)balance));
7374 UniValue tokencreate(const UniValue& params, bool fHelp)
7376 UniValue result(UniValue::VOBJ); std::string name,description,hex; uint64_t supply;
7377 if ( fHelp || params.size() > 3 || params.size() < 2 )
7378 throw runtime_error("tokencreate name supply description\n");
7379 if ( ensure_CCrequirements() < 0 )
7380 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7381 const CKeyStore& keystore = *pwalletMain;
7382 LOCK2(cs_main, pwalletMain->cs_wallet);
7383 name = params[0].get_str();
7384 supply = atof(params[1].get_str().c_str()) * COIN;
7385 if ( name.size() == 0 || name.size() > 32)
7387 ERR_RESULT("Token name must not be empty and up to 32 characters");
7392 ERR_RESULT("Token supply must be positive");
7395 if ( params.size() == 3 )
7397 description = params[2].get_str();
7398 if ( description.size() > 4096 )
7400 ERR_RESULT("Token description must be <= 4096 characters");
7404 hex = CreateAsset(0,supply,name,description);
7405 if ( hex.size() > 0 )
7407 result.push_back(Pair("result", "success"));
7408 result.push_back(Pair("hex", hex));
7409 } else ERR_RESULT("couldnt create transaction");
7413 UniValue tokentransfer(const UniValue& params, bool fHelp)
7415 UniValue result(UniValue::VOBJ); std::string hex; int64_t amount; uint256 tokenid;
7416 if ( fHelp || params.size() != 3 )
7417 throw runtime_error("tokentransfer tokenid destpubkey amount\n");
7418 if ( ensure_CCrequirements() < 0 )
7419 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7420 const CKeyStore& keystore = *pwalletMain;
7421 LOCK2(cs_main, pwalletMain->cs_wallet);
7422 tokenid = Parseuint256((char *)params[0].get_str().c_str());
7423 std::vector<unsigned char> pubkey(ParseHex(params[1].get_str().c_str()));
7424 amount = atol(params[2].get_str().c_str());
7425 if ( tokenid == zeroid )
7427 ERR_RESULT("invalid tokenid");
7432 ERR_RESULT("amount must be positive");
7435 hex = AssetTransfer(0,tokenid,pubkey,amount);
7437 if ( hex.size() > 0 )
7439 result.push_back(Pair("result", "success"));
7440 result.push_back(Pair("hex", hex));
7441 } else ERR_RESULT("couldnt transfer assets");
7443 ERR_RESULT("amount must be positive");
7448 UniValue tokenbid(const UniValue& params, bool fHelp)
7450 UniValue result(UniValue::VOBJ); int64_t bidamount,numtokens; std::string hex; double price; uint256 tokenid;
7451 if ( fHelp || params.size() != 3 )
7452 throw runtime_error("tokenbid numtokens tokenid price\n");
7453 if ( ensure_CCrequirements() < 0 )
7454 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7455 const CKeyStore& keystore = *pwalletMain;
7456 LOCK2(cs_main, pwalletMain->cs_wallet);
7457 numtokens = atoi(params[0].get_str().c_str());
7458 tokenid = Parseuint256((char *)params[1].get_str().c_str());
7459 price = atof(params[2].get_str().c_str());
7460 bidamount = (price * numtokens) * COIN + 0.0000000049999;
7463 ERR_RESULT("price must be positive");
7466 if ( tokenid == zeroid )
7468 ERR_RESULT("invalid tokenid");
7471 if ( bidamount <= 0 )
7473 ERR_RESULT("bid amount must be positive");
7476 hex = CreateBuyOffer(0,bidamount,tokenid,numtokens);
7477 if (price > 0 && numtokens > 0) {
7478 if ( hex.size() > 0 )
7480 result.push_back(Pair("result", "success"));
7481 result.push_back(Pair("hex", hex));
7482 } else ERR_RESULT("couldnt create bid");
7484 ERR_RESULT("price and numtokens must be positive");
7489 UniValue tokencancelbid(const UniValue& params, bool fHelp)
7491 UniValue result(UniValue::VOBJ); std::string hex; int32_t i; uint256 tokenid,bidtxid;
7492 if ( fHelp || params.size() != 2 )
7493 throw runtime_error("tokencancelbid tokenid bidtxid\n");
7494 if ( ensure_CCrequirements() < 0 )
7495 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7496 const CKeyStore& keystore = *pwalletMain;
7497 LOCK2(cs_main, pwalletMain->cs_wallet);
7498 tokenid = Parseuint256((char *)params[0].get_str().c_str());
7499 bidtxid = Parseuint256((char *)params[1].get_str().c_str());
7500 if ( tokenid == zeroid || bidtxid == zeroid )
7502 result.push_back(Pair("error", "invalid parameter"));
7505 hex = CancelBuyOffer(0,tokenid,bidtxid);
7506 if ( hex.size() > 0 )
7508 result.push_back(Pair("result", "success"));
7509 result.push_back(Pair("hex", hex));
7510 } else ERR_RESULT("couldnt cancel bid");
7514 UniValue tokenfillbid(const UniValue& params, bool fHelp)
7516 UniValue result(UniValue::VOBJ); int64_t fillamount; std::string hex; uint256 tokenid,bidtxid;
7517 if ( fHelp || params.size() != 3 )
7518 throw runtime_error("tokenfillbid tokenid bidtxid fillamount\n");
7519 if ( ensure_CCrequirements() < 0 )
7520 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7521 const CKeyStore& keystore = *pwalletMain;
7522 LOCK2(cs_main, pwalletMain->cs_wallet);
7523 tokenid = Parseuint256((char *)params[0].get_str().c_str());
7524 bidtxid = Parseuint256((char *)params[1].get_str().c_str());
7525 fillamount = atol(params[2].get_str().c_str());
7526 if ( fillamount <= 0 )
7528 ERR_RESULT("fillamount must be positive");
7531 if ( tokenid == zeroid || bidtxid == zeroid )
7533 ERR_RESULT("must provide tokenid and bidtxid");
7536 hex = FillBuyOffer(0,tokenid,bidtxid,fillamount);
7537 if ( hex.size() > 0 )
7539 result.push_back(Pair("result", "success"));
7540 result.push_back(Pair("hex", hex));
7541 } else ERR_RESULT("couldnt fill bid");
7545 UniValue tokenask(const UniValue& params, bool fHelp)
7547 UniValue result(UniValue::VOBJ); int64_t askamount,numtokens; std::string hex; double price; uint256 tokenid;
7548 if ( fHelp || params.size() != 3 )
7549 throw runtime_error("tokenask numtokens tokenid price\n");
7550 if ( ensure_CCrequirements() < 0 )
7551 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7552 const CKeyStore& keystore = *pwalletMain;
7553 LOCK2(cs_main, pwalletMain->cs_wallet);
7554 numtokens = atoi(params[0].get_str().c_str());
7555 tokenid = Parseuint256((char *)params[1].get_str().c_str());
7556 price = atof(params[2].get_str().c_str());
7557 askamount = (price * numtokens) * COIN + 0.0000000049999;
7558 if ( tokenid == zeroid || numtokens <= 0 || price <= 0 || askamount <= 0 )
7560 ERR_RESULT("invalid parameter");
7563 hex = CreateSell(0,numtokens,tokenid,askamount);
7564 if (price > 0 && numtokens > 0) {
7565 if ( hex.size() > 0 )
7567 result.push_back(Pair("result", "success"));
7568 result.push_back(Pair("hex", hex));
7569 } else ERR_RESULT("couldnt create ask");
7571 ERR_RESULT("price and numtokens must be positive");
7576 UniValue tokenswapask(const UniValue& params, bool fHelp)
7578 static uint256 zeroid;
7579 UniValue result(UniValue::VOBJ); int64_t askamount,numtokens; std::string hex; double price; uint256 tokenid,otherid;
7580 if ( fHelp || params.size() != 4 )
7581 throw runtime_error("tokenswapask numtokens tokenid otherid price\n");
7582 if ( ensure_CCrequirements() < 0 )
7583 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7584 const CKeyStore& keystore = *pwalletMain;
7585 LOCK2(cs_main, pwalletMain->cs_wallet);
7586 numtokens = atoi(params[0].get_str().c_str());
7587 tokenid = Parseuint256((char *)params[1].get_str().c_str());
7588 otherid = Parseuint256((char *)params[2].get_str().c_str());
7589 price = atof(params[3].get_str().c_str());
7590 askamount = (price * numtokens);
7591 hex = CreateSwap(0,numtokens,tokenid,otherid,askamount);
7592 if (price > 0 && numtokens > 0) {
7593 if ( hex.size() > 0 )
7595 result.push_back(Pair("result", "success"));
7596 result.push_back(Pair("hex", hex));
7597 } else ERR_RESULT("couldnt create swap");
7599 ERR_RESULT("price and numtokens must be positive");
7604 UniValue tokencancelask(const UniValue& params, bool fHelp)
7606 UniValue result(UniValue::VOBJ); std::string hex; int32_t i; uint256 tokenid,asktxid;
7607 if ( fHelp || params.size() != 2 )
7608 throw runtime_error("tokencancelask tokenid asktxid\n");
7609 if ( ensure_CCrequirements() < 0 )
7610 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7611 const CKeyStore& keystore = *pwalletMain;
7612 LOCK2(cs_main, pwalletMain->cs_wallet);
7613 tokenid = Parseuint256((char *)params[0].get_str().c_str());
7614 asktxid = Parseuint256((char *)params[1].get_str().c_str());
7615 if ( tokenid == zeroid || asktxid == zeroid )
7617 result.push_back(Pair("error", "invalid parameter"));
7620 hex = CancelSell(0,tokenid,asktxid);
7621 if ( hex.size() > 0 )
7623 result.push_back(Pair("result", "success"));
7624 result.push_back(Pair("hex", hex));
7625 } else ERR_RESULT("couldnt cancel ask");
7629 UniValue tokenfillask(const UniValue& params, bool fHelp)
7631 UniValue result(UniValue::VOBJ); int64_t fillunits; std::string hex; uint256 tokenid,asktxid;
7632 if ( fHelp || params.size() != 3 )
7633 throw runtime_error("tokenfillask tokenid asktxid fillunits\n");
7634 if ( ensure_CCrequirements() < 0 )
7635 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7636 const CKeyStore& keystore = *pwalletMain;
7637 LOCK2(cs_main, pwalletMain->cs_wallet);
7638 tokenid = Parseuint256((char *)params[0].get_str().c_str());
7639 asktxid = Parseuint256((char *)params[1].get_str().c_str());
7640 fillunits = atol(params[2].get_str().c_str());
7641 if ( fillunits <= 0 )
7643 ERR_RESULT("fillunits must be positive");
7646 if ( tokenid == zeroid || asktxid == zeroid )
7648 result.push_back(Pair("error", "invalid parameter"));
7651 hex = FillSell(0,tokenid,zeroid,asktxid,fillunits);
7652 if (fillunits > 0) {
7653 if (CCerror != "") {
7654 ERR_RESULT(CCerror);
7655 } else if ( hex.size() > 0) {
7656 result.push_back(Pair("result", "success"));
7657 result.push_back(Pair("hex", hex));
7659 ERR_RESULT("couldnt fill bid");
7662 ERR_RESULT("fillunits must be positive");
7667 UniValue tokenfillswap(const UniValue& params, bool fHelp)
7669 static uint256 zeroid;
7670 UniValue result(UniValue::VOBJ); int64_t fillunits; std::string hex; uint256 tokenid,otherid,asktxid;
7671 if ( fHelp || params.size() != 4 )
7672 throw runtime_error("tokenfillswap tokenid otherid asktxid fillunits\n");
7673 if ( ensure_CCrequirements() < 0 )
7674 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7675 const CKeyStore& keystore = *pwalletMain;
7676 LOCK2(cs_main, pwalletMain->cs_wallet);
7677 tokenid = Parseuint256((char *)params[0].get_str().c_str());
7678 otherid = Parseuint256((char *)params[1].get_str().c_str());
7679 asktxid = Parseuint256((char *)params[2].get_str().c_str());
7680 fillunits = atol(params[3].get_str().c_str());
7681 hex = FillSell(0,tokenid,otherid,asktxid,fillunits);
7682 if (fillunits > 0) {
7683 if ( hex.size() > 0 ) {
7684 result.push_back(Pair("result", "success"));
7685 result.push_back(Pair("hex", hex));
7686 } else ERR_RESULT("couldnt fill bid");
7688 ERR_RESULT("fillunits must be positive");
7693 UniValue getbalance64(const UniValue& params, bool fHelp)
7695 set<CBitcoinAddress> setAddress; vector<COutput> vecOutputs;
7696 UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR),b(UniValue::VARR); CTxDestination address;
7697 const CKeyStore& keystore = *pwalletMain;
7698 CAmount nValues[64],nValues2[64],nValue,total,total2; int32_t i,segid;
7699 if (!EnsureWalletIsAvailable(fHelp))
7700 return NullUniValue;
7701 if (params.size() > 0)
7702 throw runtime_error("getbalance64\n");
7704 memset(nValues,0,sizeof(nValues));
7705 memset(nValues2,0,sizeof(nValues2));
7706 LOCK2(cs_main, pwalletMain->cs_wallet);
7707 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
7708 BOOST_FOREACH(const COutput& out, vecOutputs)
7710 nValue = out.tx->vout[out.i].nValue;
7711 if ( ExtractDestination(out.tx->vout[out.i].scriptPubKey, address) )
7713 segid = (komodo_segid32((char *)CBitcoinAddress(address).ToString().c_str()) & 0x3f);
7714 if ( out.nDepth < 100 )
7715 nValues2[segid] += nValue, total2 += nValue;
7716 else nValues[segid] += nValue, total += nValue;
7717 //fprintf(stderr,"%s %.8f depth.%d segid.%d\n",(char *)CBitcoinAddress(address).ToString().c_str(),(double)nValue/COIN,(int32_t)out.nDepth,segid);
7718 } else fprintf(stderr,"no destination\n");
7720 ret.push_back(Pair("mature",(double)total/COIN));
7721 ret.push_back(Pair("immature",(double)total2/COIN));
7722 for (i=0; i<64; i++)
7724 a.push_back((uint64_t)nValues[i]);
7725 b.push_back((uint64_t)nValues2[i]);
7727 ret.push_back(Pair("staking", a));
7728 ret.push_back(Pair("notstaking", b));
7732 extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp
7733 extern UniValue importprivkey(const UniValue& params, bool fHelp);
7734 extern UniValue importaddress(const UniValue& params, bool fHelp);
7735 extern UniValue dumpwallet(const UniValue& params, bool fHelp);
7736 extern UniValue importwallet(const UniValue& params, bool fHelp);
7737 extern UniValue z_exportkey(const UniValue& params, bool fHelp);
7738 extern UniValue z_importkey(const UniValue& params, bool fHelp);
7739 extern UniValue z_exportviewingkey(const UniValue& params, bool fHelp);
7740 extern UniValue z_importviewingkey(const UniValue& params, bool fHelp);
7741 extern UniValue z_exportwallet(const UniValue& params, bool fHelp);
7742 extern UniValue z_importwallet(const UniValue& params, bool fHelp);
7744 extern UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp); // in rpcdisclosure.cpp
7745 extern UniValue z_validatepaymentdisclosure(const UniValue ¶ms, bool fHelp);
7747 static const CRPCCommand commands[] =
7748 { // category name actor (function) okSafeMode
7749 // --------------------- ------------------------ ----------------------- ----------
7750 { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false },
7751 { "hidden", "resendwallettransactions", &resendwallettransactions, true },
7752 { "wallet", "addmultisigaddress", &addmultisigaddress, true },
7753 { "wallet", "backupwallet", &backupwallet, true },
7754 { "wallet", "dumpprivkey", &dumpprivkey, true },
7755 { "wallet", "dumpwallet", &dumpwallet, true },
7756 { "wallet", "encryptwallet", &encryptwallet, true },
7757 { "wallet", "getaccountaddress", &getaccountaddress, true },
7758 { "wallet", "getaccount", &getaccount, true },
7759 { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true },
7760 { "wallet", "getbalance", &getbalance, false },
7761 { "wallet", "getnewaddress", &getnewaddress, true },
7762 { "wallet", "getrawchangeaddress", &getrawchangeaddress, true },
7763 { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false },
7764 { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false },
7765 { "wallet", "gettransaction", &gettransaction, false },
7766 { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false },
7767 { "wallet", "getwalletinfo", &getwalletinfo, false },
7768 { "wallet", "convertpassphrase", &convertpassphrase, true },
7769 { "wallet", "importprivkey", &importprivkey, true },
7770 { "wallet", "importwallet", &importwallet, true },
7771 { "wallet", "importaddress", &importaddress, true },
7772 { "wallet", "keypoolrefill", &keypoolrefill, true },
7773 { "wallet", "listaccounts", &listaccounts, false },
7774 { "wallet", "listaddressgroupings", &listaddressgroupings, false },
7775 { "wallet", "listlockunspent", &listlockunspent, false },
7776 { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false },
7777 { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false },
7778 { "wallet", "listsinceblock", &listsinceblock, false },
7779 { "wallet", "listtransactions", &listtransactions, false },
7780 { "wallet", "listunspent", &listunspent, false },
7781 { "wallet", "lockunspent", &lockunspent, true },
7782 { "wallet", "move", &movecmd, false },
7783 { "wallet", "sendfrom", &sendfrom, false },
7784 { "wallet", "sendmany", &sendmany, false },
7785 { "wallet", "sendtoaddress", &sendtoaddress, false },
7786 { "wallet", "setaccount", &setaccount, true },
7787 { "wallet", "settxfee", &settxfee, true },
7788 { "wallet", "signmessage", &signmessage, true },
7789 { "wallet", "signfile", &signfile, true },
7790 { "hidden", "printapis", &printapis, true },
7791 // { "hidden", "signhash", &signhash, true }, // disable due to risk of signing something that doesn't contain the content
7792 { "wallet", "walletlock", &walletlock, true },
7793 { "wallet", "walletpassphrasechange", &walletpassphrasechange, true },
7794 { "wallet", "walletpassphrase", &walletpassphrase, true },
7795 { "wallet", "zcbenchmark", &zc_benchmark, true },
7796 { "wallet", "zcrawkeygen", &zc_raw_keygen, true },
7797 { "wallet", "zcrawjoinsplit", &zc_raw_joinsplit, true },
7798 { "wallet", "zcrawreceive", &zc_raw_receive, true },
7799 { "wallet", "zcsamplejoinsplit", &zc_sample_joinsplit, true },
7800 { "wallet", "z_listreceivedbyaddress", &z_listreceivedbyaddress, false },
7801 { "wallet", "z_listunspent", &z_listunspent, false },
7802 { "wallet", "z_getbalance", &z_getbalance, false },
7803 { "wallet", "z_gettotalbalance", &z_gettotalbalance, false },
7804 { "wallet", "z_mergetoaddress", &z_mergetoaddress, false },
7805 { "wallet", "z_sendmany", &z_sendmany, false },
7806 { "wallet", "z_setmigration", &z_setmigration, false },
7807 { "wallet", "z_getmigrationstatus", &z_getmigrationstatus, false },
7808 { "wallet", "z_shieldcoinbase", &z_shieldcoinbase, false },
7809 { "wallet", "z_getoperationstatus", &z_getoperationstatus, true },
7810 { "wallet", "z_getoperationresult", &z_getoperationresult, true },
7811 { "wallet", "z_listoperationids", &z_listoperationids, true },
7812 { "wallet", "z_getnewaddress", &z_getnewaddress, true },
7813 { "wallet", "z_listaddresses", &z_listaddresses, true },
7814 { "wallet", "z_exportkey", &z_exportkey, true },
7815 { "wallet", "z_importkey", &z_importkey, true },
7816 { "wallet", "z_exportviewingkey", &z_exportviewingkey, true },
7817 { "wallet", "z_importviewingkey", &z_importviewingkey, true },
7818 { "wallet", "z_exportwallet", &z_exportwallet, true },
7819 { "wallet", "z_importwallet", &z_importwallet, true },
7820 { "wallet", "z_viewtransaction", &z_viewtransaction, true },
7821 // TODO: rearrange into another category
7822 { "disclosure", "z_getpaymentdisclosure", &z_getpaymentdisclosure, true },
7823 { "disclosure", "z_validatepaymentdisclosure", &z_validatepaymentdisclosure, true }
7826 void RegisterWalletRPCCommands(CRPCTable &tableRPC)
7828 for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
7829 tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);