]> Git Repo - VerusCoin.git/blame - src/wallet/rpcwallet.cpp
tst
[VerusCoin.git] / src / wallet / rpcwallet.cpp
CommitLineData
e3bc5698 1// Copyright (c) 2010 Satoshi Nakamoto
f914f1a7 2// Copyright (c) 2009-2014 The Bitcoin Core developers
72fb3d29 3// Distributed under the MIT software license, see the accompanying
e3bc5698
JG
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
eda37330 6#include "amount.h"
51ed9ec9 7#include "base58.h"
be126699 8#include "consensus/upgrades.h"
ae775b5b 9#include "core_io.h"
e3bc5698 10#include "init.h"
8a893c94 11#include "main.h"
51ed9ec9
BD
12#include "net.h"
13#include "netbase.h"
8a893c94 14#include "rpcserver.h"
14f888ca 15#include "timedata.h"
51ed9ec9 16#include "util.h"
b93173de 17#include "utilmoneystr.h"
51ed9ec9
BD
18#include "wallet.h"
19#include "walletdb.h"
8cb25088 20#include "primitives/transaction.h"
6962bb3d 21#include "zcbenchmarks.h"
6aae9d1a 22#include "script/interpreter.h"
51ed9ec9 23
fc72c078
S
24#include "utiltime.h"
25#include "asyncrpcoperation.h"
ed21d5bd 26#include "asyncrpcqueue.h"
6e9c7629 27#include "wallet/asyncrpcoperation_mergetoaddress.h"
fc72c078 28#include "wallet/asyncrpcoperation_sendmany.h"
06c19063 29#include "wallet/asyncrpcoperation_shieldcoinbase.h"
fc72c078 30
320f2cc7
SB
31#include "sodium.h"
32
51ed9ec9
BD
33#include <stdint.h>
34
35#include <boost/assign/list_of.hpp>
25cf6f3d 36
a10a6e2a 37#include <univalue.h>
e3bc5698 38
bcbde86a
S
39#include <numeric>
40
e3bc5698
JG
41using namespace std;
42
2dc35992
SB
43using namespace libzcash;
44
1333d0d7 45extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
0d37ae3a 46extern UniValue TxJoinSplitToJSON(const CTransaction& tx);
2f151c30 47extern uint8_t ASSETCHAINS_PRIVATE;
890e708b 48uint32_t komodo_segid32(char *coinaddr);
f7cfb52d 49
51ed9ec9 50int64_t nWalletUnlockTime;
e3bc5698
JG
51static CCriticalSection cs_nWalletUnlockTime;
52
c1eae280 53// Private method:
0d37ae3a 54UniValue z_getoperationstatus_IMPL(const UniValue&, bool);
c1eae280 55
bdab0cf5 56std::string HelpRequiringPassphrase()
e3bc5698 57{
b0730874 58 return pwalletMain && pwalletMain->IsCrypted()
a6099ef3 59 ? "\nRequires wallet passphrase to be set with walletpassphrase call."
e3bc5698
JG
60 : "";
61}
62
b9fb692d
JS
63bool EnsureWalletIsAvailable(bool avoidException)
64{
65 if (!pwalletMain)
66 {
67 if (!avoidException)
68 throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
69 else
70 return false;
71 }
72 return true;
73}
74
bdab0cf5 75void EnsureWalletIsUnlocked()
e3bc5698
JG
76{
77 if (pwalletMain->IsLocked())
738835d7 78 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
e3bc5698
JG
79}
80
c60397dd 81uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight);
15bcd69e 82
d014114d 83void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
e3bc5698 84{
cbe3042f 85 //int32_t i,n,txheight; uint32_t locktime; uint64_t interest = 0;
86 int confirms = wtx.GetDepthInMainChain();
e3bc5698 87 entry.push_back(Pair("confirmations", confirms));
e07c8e91
LD
88 if (wtx.IsCoinBase())
89 entry.push_back(Pair("generated", true));
2b72d46f 90 if (confirms > 0)
e3bc5698
JG
91 {
92 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
93 entry.push_back(Pair("blockindex", wtx.nIndex));
209377a7 94 entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
9bb37bf0 95 entry.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight));
e3bc5698 96 }
805344dc 97 uint256 hash = wtx.GetHash();
731b89b8 98 entry.push_back(Pair("txid", hash.GetHex()));
38fc4b70 99 UniValue conflicts(UniValue::VARR);
731b89b8
GA
100 BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
101 conflicts.push_back(conflict.GetHex());
102 entry.push_back(Pair("walletconflicts", conflicts));
d56e30ca 103 entry.push_back(Pair("time", wtx.GetTxTime()));
4b61a6a4 104 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
e3bc5698
JG
105 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
106 entry.push_back(Pair(item.first, item.second));
f7cfb52d
S
107
108 entry.push_back(Pair("vjoinsplit", TxJoinSplitToJSON(wtx)));
e3bc5698
JG
109}
110
d014114d 111string AccountFromValue(const UniValue& value)
e3bc5698
JG
112{
113 string strAccount = value.get_str();
8b6a0cb8 114 //if (strAccount != "")
115 // throw JSONRPCError(RPC_WALLET_ACCOUNTS_UNSUPPORTED, "Accounts are unsupported");
e3bc5698
JG
116 return strAccount;
117}
118
1333d0d7 119char *komodo_chainname()
120{
121 return(ASSETCHAINS_SYMBOL[0] == 0 ? (char *)"KMD" : ASSETCHAINS_SYMBOL);
122}
123
d014114d 124UniValue getnewaddress(const UniValue& params, bool fHelp)
e3bc5698 125{
b9fb692d 126 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 127 return NullUniValue;
9d365796 128
e3bc5698
JG
129 if (fHelp || params.size() > 1)
130 throw runtime_error(
a6099ef3 131 "getnewaddress ( \"account\" )\n"
1333d0d7 132 "\nReturns a new " + strprintf("%s",komodo_chainname()) + " address for receiving payments.\n"
a6099ef3 133 "\nArguments:\n"
3c31eb24 134 "1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 135 "\nResult:\n"
1333d0d7 136 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) The new " + strprintf("%s",komodo_chainname()) + " address\n"
a6099ef3 137 "\nExamples:\n"
138 + HelpExampleCli("getnewaddress", "")
7b782f5b 139 + HelpExampleRpc("getnewaddress", "")
a6099ef3 140 );
e3bc5698 141
4401b2d7
EL
142 LOCK2(cs_main, pwalletMain->cs_wallet);
143
e3bc5698
JG
144 // Parse the account first so we don't generate a key if there's an error
145 string strAccount;
146 if (params.size() > 0)
147 strAccount = AccountFromValue(params[0]);
148
149 if (!pwalletMain->IsLocked())
150 pwalletMain->TopUpKeyPool();
151
152 // Generate a new key that is added to wallet
153 CPubKey newKey;
71ac5052 154 if (!pwalletMain->GetKeyFromPool(newKey))
738835d7 155 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e3bc5698
JG
156 CKeyID keyID = newKey.GetID();
157
a41d5fe0 158 pwalletMain->SetAddressBook(keyID, strAccount, "receive");
e3bc5698
JG
159
160 return CBitcoinAddress(keyID).ToString();
161}
162
163
164CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
165{
166 CWalletDB walletdb(pwalletMain->strWalletFile);
167
168 CAccount account;
169 walletdb.ReadAccount(strAccount, account);
170
171 bool bKeyUsed = false;
172
173 // Check if the current key has been used
174 if (account.vchPubKey.IsValid())
175 {
0be990ba 176 CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
e3bc5698
JG
177 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
178 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
179 ++it)
180 {
181 const CWalletTx& wtx = (*it).second;
182 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
183 if (txout.scriptPubKey == scriptPubKey)
184 bKeyUsed = true;
185 }
186 }
187
188 // Generate a new key
189 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
190 {
71ac5052 191 if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
738835d7 192 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e3bc5698 193
a41d5fe0 194 pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
e3bc5698
JG
195 walletdb.WriteAccount(strAccount, account);
196 }
197
198 return CBitcoinAddress(account.vchPubKey.GetID());
199}
200
d014114d 201UniValue getaccountaddress(const UniValue& params, bool fHelp)
e3bc5698 202{
b9fb692d 203 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 204 return NullUniValue;
9d365796 205
e3bc5698
JG
206 if (fHelp || params.size() != 1)
207 throw runtime_error(
a6099ef3 208 "getaccountaddress \"account\"\n"
1333d0d7 209 "\nDEPRECATED. Returns the current " + strprintf("%s",komodo_chainname()) + " address for receiving payments to this account.\n"
a6099ef3 210 "\nArguments:\n"
3c31eb24 211 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 212 "\nResult:\n"
1333d0d7 213 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) The account " + strprintf("%s",komodo_chainname()) + " address\n"
a6099ef3 214 "\nExamples:\n"
215 + HelpExampleCli("getaccountaddress", "")
216 + HelpExampleCli("getaccountaddress", "\"\"")
217 + HelpExampleCli("getaccountaddress", "\"myaccount\"")
218 + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
219 );
e3bc5698 220
4401b2d7
EL
221 LOCK2(cs_main, pwalletMain->cs_wallet);
222
e3bc5698
JG
223 // Parse the account first so we don't generate a key if there's an error
224 string strAccount = AccountFromValue(params[0]);
225
d014114d 226 UniValue ret(UniValue::VSTR);
e3bc5698
JG
227
228 ret = GetAccountAddress(strAccount).ToString();
e3bc5698
JG
229 return ret;
230}
231
232
d014114d 233UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
e5e9904c 234{
b9fb692d 235 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 236 return NullUniValue;
9d365796 237
e5e9904c
JG
238 if (fHelp || params.size() > 1)
239 throw runtime_error(
240 "getrawchangeaddress\n"
1333d0d7 241 "\nReturns a new " + strprintf("%s",komodo_chainname()) + " address, for receiving change.\n"
a6099ef3 242 "This is for use with raw transactions, NOT normal use.\n"
243 "\nResult:\n"
244 "\"address\" (string) The address\n"
245 "\nExamples:\n"
246 + HelpExampleCli("getrawchangeaddress", "")
247 + HelpExampleRpc("getrawchangeaddress", "")
248 );
e5e9904c 249
4401b2d7
EL
250 LOCK2(cs_main, pwalletMain->cs_wallet);
251
e5e9904c
JG
252 if (!pwalletMain->IsLocked())
253 pwalletMain->TopUpKeyPool();
254
255 CReserveKey reservekey(pwalletMain);
256 CPubKey vchPubKey;
257 if (!reservekey.GetReservedKey(vchPubKey))
6c37f7fd 258 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e5e9904c
JG
259
260 reservekey.KeepKey();
261
262 CKeyID keyID = vchPubKey.GetID();
263
264 return CBitcoinAddress(keyID).ToString();
265}
266
e3bc5698 267
d014114d 268UniValue setaccount(const UniValue& params, bool fHelp)
e3bc5698 269{
b9fb692d 270 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 271 return NullUniValue;
9d365796 272
e3bc5698
JG
273 if (fHelp || params.size() < 1 || params.size() > 2)
274 throw runtime_error(
1333d0d7 275 "setaccount \"" + strprintf("%s",komodo_chainname()) + "_address\" \"account\"\n"
7b782f5b 276 "\nDEPRECATED. Sets the account associated with the given address.\n"
a6099ef3 277 "\nArguments:\n"
1333d0d7 278 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to be associated with an account.\n"
3c31eb24 279 "2. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 280 "\nExamples:\n"
1333d0d7 281 + HelpExampleCli("setaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"tabby\"")
282 + HelpExampleRpc("setaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"tabby\"")
a6099ef3 283 );
e3bc5698 284
4401b2d7
EL
285 LOCK2(cs_main, pwalletMain->cs_wallet);
286
e3bc5698
JG
287 CBitcoinAddress address(params[0].get_str());
288 if (!address.IsValid())
1333d0d7 289 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
e3bc5698 290
e3bc5698
JG
291 string strAccount;
292 if (params.size() > 1)
293 strAccount = AccountFromValue(params[1]);
294
31d6390f
ES
295 // Only add the account if the address is yours.
296 if (IsMine(*pwalletMain, address.Get()))
e3bc5698 297 {
31d6390f
ES
298 // Detect when changing the account of an address that is the 'unused current key' of another account:
299 if (pwalletMain->mapAddressBook.count(address.Get()))
300 {
301 string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name;
302 if (address == GetAccountAddress(strOldAccount))
303 GetAccountAddress(strOldAccount, true);
304 }
305 pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
e3bc5698 306 }
31d6390f
ES
307 else
308 throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
e3bc5698 309
ed21d5bd 310 return NullUniValue;
e3bc5698
JG
311}
312
313
d014114d 314UniValue getaccount(const UniValue& params, bool fHelp)
e3bc5698 315{
b9fb692d 316 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 317 return NullUniValue;
9d365796 318
e3bc5698
JG
319 if (fHelp || params.size() != 1)
320 throw runtime_error(
1333d0d7 321 "getaccount \"" + strprintf("%s",komodo_chainname()) + "_address\"\n"
7b782f5b 322 "\nDEPRECATED. Returns the account associated with the given address.\n"
a6099ef3 323 "\nArguments:\n"
1333d0d7 324 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address for account lookup.\n"
a6099ef3 325 "\nResult:\n"
326 "\"accountname\" (string) the account address\n"
327 "\nExamples:\n"
1333d0d7 328 + HelpExampleCli("getaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"")
329 + HelpExampleRpc("getaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"")
a6099ef3 330 );
e3bc5698 331
4401b2d7
EL
332 LOCK2(cs_main, pwalletMain->cs_wallet);
333
e3bc5698
JG
334 CBitcoinAddress address(params[0].get_str());
335 if (!address.IsValid())
1333d0d7 336 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
e3bc5698
JG
337
338 string strAccount;
61885513
GA
339 map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
340 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty())
341 strAccount = (*mi).second.name;
e3bc5698
JG
342 return strAccount;
343}
344
345
d014114d 346UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
e3bc5698 347{
b9fb692d 348 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 349 return NullUniValue;
9d365796 350
e3bc5698
JG
351 if (fHelp || params.size() != 1)
352 throw runtime_error(
a6099ef3 353 "getaddressesbyaccount \"account\"\n"
7b782f5b 354 "\nDEPRECATED. Returns the list of addresses for the given account.\n"
a6099ef3 355 "\nArguments:\n"
3c31eb24 356 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 357 "\nResult:\n"
358 "[ (json array of string)\n"
1333d0d7 359 " \"" + strprintf("%s",komodo_chainname()) + "_address\" (string) a " + strprintf("%s",komodo_chainname()) + " address associated with the given account\n"
a6099ef3 360 " ,...\n"
361 "]\n"
362 "\nExamples:\n"
363 + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
364 + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
365 );
e3bc5698 366
4401b2d7
EL
367 LOCK2(cs_main, pwalletMain->cs_wallet);
368
e3bc5698
JG
369 string strAccount = AccountFromValue(params[0]);
370
371 // Find all addresses that have the given account
38fc4b70 372 UniValue ret(UniValue::VARR);
61885513 373 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
e3bc5698
JG
374 {
375 const CBitcoinAddress& address = item.first;
61885513 376 const string& strName = item.second.name;
e3bc5698
JG
377 if (strName == strAccount)
378 ret.push_back(address.ToString());
379 }
380 return ret;
381}
382
9415da7f 383static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew,uint8_t *opretbuf,int32_t opretlen,long int opretValue)
b93173de 384{
25cf6f3d
PK
385 CAmount curBalance = pwalletMain->GetBalance();
386
b93173de
PJ
387 // Check amount
388 if (nValue <= 0)
4be639ea 389 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
b93173de 390
25cf6f3d 391 if (nValue > curBalance)
b93173de
PJ
392 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
393
58c4c0bb 394 // Parse Zcash address
b93173de
PJ
395 CScript scriptPubKey = GetScriptForDestination(address);
396
397 // Create and send the transaction
398 CReserveKey reservekey(pwalletMain);
399 CAmount nFeeRequired;
25cf6f3d 400 std::string strError;
292623ad
CL
401 vector<CRecipient> vecSend;
402 int nChangePosRet = -1;
403 CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
404 vecSend.push_back(recipient);
b62d7030 405 if ( opretlen > 0 && opretbuf != 0 )
406 {
407 CScript opretpubkey; int32_t i; uint8_t *ptr;
408 opretpubkey.resize(opretlen);
409 ptr = (uint8_t *)opretpubkey.data();
410 for (i=0; i<opretlen; i++)
4aa2c64e 411 {
353edf5d 412 ptr[i] = opretbuf[i];
1919e9de 413 //printf("%02x",ptr[i]);
4aa2c64e 414 }
1919e9de 415 //printf(" opretbuf[%d]\n",opretlen);
b62d7030 416 CRecipient opret = { opretpubkey, opretValue, false };
417 vecSend.push_back(opret);
418 }
292623ad
CL
419 if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
420 if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
421 strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired));
422 throw JSONRPCError(RPC_WALLET_ERROR, strError);
b93173de
PJ
423 }
424 if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
425 throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
b93173de
PJ
426}
427
d014114d 428UniValue sendtoaddress(const UniValue& params, bool fHelp)
e3bc5698 429{
b9fb692d 430 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 431 return NullUniValue;
9d365796 432
292623ad 433 if (fHelp || params.size() < 2 || params.size() > 5)
e3bc5698 434 throw runtime_error(
1333d0d7 435 "sendtoaddress \"" + strprintf("%s",komodo_chainname()) + "_address\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
e743678d 436 "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
a6099ef3 437 + HelpRequiringPassphrase() +
438 "\nArguments:\n"
1333d0d7 439 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to send to.\n"
440 "2. \"amount\" (numeric, required) The amount in " + strprintf("%s",komodo_chainname()) + " to send. eg 0.1\n"
a6099ef3 441 "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
442 " This is not part of the transaction, just kept in your wallet.\n"
443 "4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
444 " to which you're sending the transaction. This is not part of the \n"
445 " transaction, just kept in your wallet.\n"
292623ad 446 "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
1333d0d7 447 " The recipient will receive less " + strprintf("%s",komodo_chainname()) + " than you enter in the amount field.\n"
a6099ef3 448 "\nResult:\n"
b5ef85c7 449 "\"transactionid\" (string) The transaction id.\n"
a6099ef3 450 "\nExamples:\n"
1333d0d7 451 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.1")
452 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.1 \"donation\" \"seans outpost\"")
453 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.1 \"\" \"\" true")
454 + HelpExampleRpc("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", 0.1, \"donation\", \"seans outpost\"")
a6099ef3 455 );
e3bc5698 456
2f151c30 457 if ( ASSETCHAINS_PRIVATE != 0 && AmountFromValue(params[1]) > 0 )
458 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
459
4401b2d7
EL
460 LOCK2(cs_main, pwalletMain->cs_wallet);
461
e3bc5698
JG
462 CBitcoinAddress address(params[0].get_str());
463 if (!address.IsValid())
1333d0d7 464 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
e3bc5698
JG
465
466 // Amount
a372168e 467 CAmount nAmount = AmountFromValue(params[1]);
e76a3849
WL
468 if (nAmount <= 0)
469 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
e3bc5698
JG
470
471 // Wallet comments
472 CWalletTx wtx;
ed21d5bd 473 if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty())
e3bc5698 474 wtx.mapValue["comment"] = params[2].get_str();
ed21d5bd 475 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
e3bc5698
JG
476 wtx.mapValue["to"] = params[3].get_str();
477
292623ad
CL
478 bool fSubtractFeeFromAmount = false;
479 if (params.size() > 4)
480 fSubtractFeeFromAmount = params[4].get_bool();
481
f914c7a1 482 EnsureWalletIsUnlocked();
e3bc5698 483
b62d7030 484 SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, wtx,0,0,0);
e3bc5698 485
805344dc 486 return wtx.GetHash().GetHex();
e3bc5698 487}
bdc72415 488#include "komodo_defs.h"
e3bc5698 489
64449ba8 490#define KOMODO_KVPROTECTED 1
638ac3ba 491#define KOMODO_KVBINARY 2
492#define KOMODO_KVDURATION 1440
ab6e81ec 493#define IGUANA_MAXSCRIPTSIZE 10001
0bda6249 494uint64_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);
353edf5d 495int32_t komodo_opreturnscript(uint8_t *script,uint8_t type,uint8_t *opret,int32_t opretlen);
9415da7f 496#define CRYPTO777_KMDADDR "RXL3YXG2ceaB6C5hfJcN4fvmLH2C34knhA"
598ee06a 497extern int32_t KOMODO_PAX;
94d3d09d 498extern uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE;
beb9352f 499int32_t komodo_is_issuer();
19cb746d 500int32_t iguana_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp);
48a3cd18 501int32_t komodo_isrealtime(int32_t *kmdheightp);
aa114a60 502int32_t pax_fiatstatus(uint64_t *available,uint64_t *deposited,uint64_t *issued,uint64_t *withdrawn,uint64_t *approved,uint64_t *redeemed,char *base);
6b5cfbb4 503int32_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);
51ff33a4 504int32_t komodo_kvcmp(uint8_t *refvalue,uint16_t refvaluesize,uint8_t *value,uint16_t valuesize);
6b5cfbb4 505uint64_t komodo_kvfee(uint32_t flags,int32_t opretlen,int32_t keylen);
506uint256 komodo_kvsig(uint8_t *buf,int32_t len,uint256 privkey);
507int32_t komodo_kvduration(uint32_t flags);
508uint256 komodo_kvprivkey(uint256 *pubkeyp,char *passphrase);
7112e5a7 509int32_t komodo_kvsigverify(uint8_t *buf,int32_t len,uint256 _pubkey,uint256 sig);
d7d27bb3 510
14f3daa6 511UniValue kvupdate(const UniValue& params, bool fHelp)
ab6e81ec 512{
684d42a2 513 static uint256 zeroes;
14f3daa6 514 CWalletTx wtx; UniValue ret(UniValue::VOBJ);
55791792 515 uint8_t keyvalue[IGUANA_MAXSCRIPTSIZE],opretbuf[IGUANA_MAXSCRIPTSIZE]; int32_t i,coresize,haveprivkey,duration,opretlen,height; uint16_t keylen=0,valuesize=0,refvaluesize=0; uint8_t *key,*value=0; uint32_t flags,tmpflags,n; struct komodo_kv *ptr; uint64_t fee; uint256 privkey,pubkey,refpubkey,sig;
2987e650 516 if (fHelp || params.size() < 3 )
38e9a59c
A
517 throw runtime_error(
518 "kvupdate key \"value\" days passphrase\n"
519 "\nStore a key value. This feature is only available for asset chains.\n"
520 "\nArguments:\n"
521 "1. key (string, required) key\n"
522 "2. \"value\" (string, required) value\n"
523 "3. days (numeric, required) amount of days(1440 blocks/day) before the key expires. Minimum 1 day\n"
524 "4. passphrase (string, optional) passphrase required to update this key\n"
525 "\nResult:\n"
526 "{\n"
527 " \"coin\": \"xxxxx\", (string) chain the key is stored on\n"
528 " \"height\": xxxxx, (numeric) height the key was stored at\n"
6f3db929
A
529 " \"expiration\": xxxxx, (numeric) height the key will expire\n"
530 " \"flags\": x, (string) amount of days the key will be stored \n"
531 " \"key\": \"xxxxx\", (numeric) stored key\n"
38e9a59c 532 " \"keylen\": xxxxx, (numeric) length of the key\n"
6f3db929
A
533 " \"value\": \"xxxxx\" (numeric) stored value\n"
534 " \"valuesize\": xxxxx, (string) length of the stored value\n"
38e9a59c 535 " \"fee\": xxxxx (string) transaction fee paid to store the key\n"
6f3db929 536 " \"txid\": \"xxxxx\" (string) transaction id\n"
38e9a59c
A
537 "}\n"
538 "\nExamples:\n"
539 + HelpExampleCli("kvupdate", "examplekey \"examplevalue\" 2 examplepassphrase")
540 + HelpExampleRpc("kvupdate", "examplekey \"examplevalue\" 2 examplepassphrase")
541 );
ab6e81ec 542 if (!EnsureWalletIsAvailable(fHelp))
543 return 0;
3e71f585 544 if ( ASSETCHAINS_SYMBOL[0] == 0 )
545 return(0);
ad2c025a 546 haveprivkey = 0;
547 memset(&sig,0,sizeof(sig));
548 memset(&privkey,0,sizeof(privkey));
3bd13500 549 memset(&refpubkey,0,sizeof(refpubkey));
ad2c025a 550 memset(&pubkey,0,sizeof(pubkey));
c929bc3e 551 if ( (n= (int32_t)params.size()) >= 3 )
3b4652ca 552 {
1919e9de 553 flags = atoi(params[2].get_str().c_str());
ebeae1eb 554 //printf("flags.%d (%s) n.%d\n",flags,params[2].get_str().c_str(),n);
3b4652ca 555 } else flags = 0;
c929bc3e 556 if ( n >= 4 )
66dc0c54 557 privkey = komodo_kvprivkey(&pubkey,(char *)(n >= 4 ? params[3].get_str().c_str() : "password"));
558 haveprivkey = 1;
559 flags |= 1;
ebeae1eb 560 /*for (i=0; i<32; i++)
66dc0c54 561 printf("%02x",((uint8_t *)&privkey)[i]);
562 printf(" priv, ");
563 for (i=0; i<32; i++)
564 printf("%02x",((uint8_t *)&pubkey)[i]);
565 printf(" pubkey, privkey derived from (%s)\n",(char *)params[3].get_str().c_str());
ebeae1eb 566 */
ab6e81ec 567 LOCK2(cs_main, pwalletMain->cs_wallet);
568 if ( (keylen= (int32_t)strlen(params[0].get_str().c_str())) > 0 )
569 {
570 key = (uint8_t *)params[0].get_str().c_str();
c929bc3e 571 if ( n >= 2 && params[1].get_str().c_str() != 0 )
51ff33a4 572 {
573 value = (uint8_t *)params[1].get_str().c_str();
574 valuesize = (int32_t)strlen(params[1].get_str().c_str());
575 }
6b5cfbb4 576 memcpy(keyvalue,key,keylen);
86131275 577 if ( (refvaluesize= komodo_kvsearch(&refpubkey,chainActive.LastTip()->nHeight,&tmpflags,&height,&keyvalue[keylen],key,keylen)) >= 0 )
05cbbacf 578 {
6b5cfbb4 579 if ( (tmpflags & KOMODO_KVPROTECTED) != 0 )
580 {
ebeae1eb 581 if ( memcmp(&refpubkey,&pubkey,sizeof(refpubkey)) != 0 )
6b5cfbb4 582 {
583 ret.push_back(Pair("error",(char *)"cant modify write once key without passphrase"));
584 return ret;
585 }
6b5cfbb4 586 }
55791792 587 if ( keylen+refvaluesize <= sizeof(keyvalue) )
e2843ac1 588 {
55791792 589 sig = komodo_kvsig(keyvalue,keylen+refvaluesize,privkey);
e2843ac1 590 if ( komodo_kvsigverify(keyvalue,keylen+refvaluesize,refpubkey,sig) < 0 )
ebeae1eb 591 {
592 ret.push_back(Pair("error",(char *)"error verifying sig, passphrase is probably wrong"));
e2843ac1 593 printf("VERIFY ERROR\n");
ebeae1eb 594 return ret;
595 } // else printf("verified immediately\n");
e2843ac1 596 }
05cbbacf 597 }
ebeae1eb 598 //for (i=0; i<32; i++)
599 // printf("%02x",((uint8_t *)&sig)[i]);
600 //printf(" sig for keylen.%d + valuesize.%d\n",keylen,refvaluesize);
ab6e81ec 601 ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)));
86131275 602 height = chainActive.LastTip()->nHeight;
6b5cfbb4 603 if ( memcmp(&zeroes,&refpubkey,sizeof(refpubkey)) != 0 )
604 ret.push_back(Pair("owner",refpubkey.GetHex()));
368da363 605 ret.push_back(Pair("height", (int64_t)height));
6b5cfbb4 606 duration = komodo_kvduration(flags); //((flags >> 2) + 1) * KOMODO_KVDURATION;
a6b182bd 607 ret.push_back(Pair("expiration", (int64_t)(height+duration)));
05cbbacf 608 ret.push_back(Pair("flags",(int64_t)flags));
ab6e81ec 609 ret.push_back(Pair("key",params[0].get_str()));
05cbbacf 610 ret.push_back(Pair("keylen",(int64_t)keylen));
c929bc3e 611 if ( n >= 2 && params[1].get_str().c_str() != 0 )
ab6e81ec 612 {
b9ecd81f 613 ret.push_back(Pair("value",params[1].get_str()));
614 ret.push_back(Pair("valuesize",valuesize));
ab6e81ec 615 }
616 iguana_rwnum(1,&keyvalue[0],sizeof(keylen),&keylen);
617 iguana_rwnum(1,&keyvalue[2],sizeof(valuesize),&valuesize);
368da363 618 iguana_rwnum(1,&keyvalue[4],sizeof(height),&height);
1919e9de 619 iguana_rwnum(1,&keyvalue[8],sizeof(flags),&flags);
620 memcpy(&keyvalue[12],key,keylen);
ab6e81ec 621 if ( value != 0 )
1919e9de 622 memcpy(&keyvalue[12 + keylen],value,valuesize);
6b5cfbb4 623 coresize = (int32_t)(sizeof(flags)+sizeof(height)+sizeof(uint16_t)*2+keylen+valuesize);
624 if ( haveprivkey != 0 )
625 {
626 for (i=0; i<32; i++)
627 keyvalue[12 + keylen + valuesize + i] = ((uint8_t *)&pubkey)[i];
628 coresize += 32;
629 if ( refvaluesize >=0 )
630 {
631 for (i=0; i<32; i++)
632 keyvalue[12 + keylen + valuesize + 32 + i] = ((uint8_t *)&sig)[i];
633 coresize += 32;
634 }
635 }
636 if ( (opretlen= komodo_opreturnscript(opretbuf,'K',keyvalue,coresize)) == 40 )
0b748e97 637 opretlen++;
1919e9de 638 //for (i=0; i<opretlen; i++)
639 // printf("%02x",opretbuf[i]);
640 //printf(" opretbuf keylen.%d valuesize.%d height.%d (%02x %02x %02x)\n",*(uint16_t *)&keyvalue[0],*(uint16_t *)&keyvalue[2],*(uint32_t *)&keyvalue[4],keyvalue[8],keyvalue[9],keyvalue[10]);
ab6e81ec 641 EnsureWalletIsUnlocked();
6b5cfbb4 642 fee = komodo_kvfee(flags,opretlen,keylen);
a6b182bd 643 ret.push_back(Pair("fee",(double)fee/COIN));
ab6e81ec 644 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
645 if (!destaddress.IsValid())
646 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
6685bab2 647 SendMoney(destaddress.Get(),10000,false,wtx,opretbuf,opretlen,fee);
a42fa6cf 648 ret.push_back(Pair("txid",wtx.GetHash().GetHex()));
1919e9de 649 } else ret.push_back(Pair("error",(char *)"null key"));
ab6e81ec 650 return ret;
651}
652
14f3daa6 653UniValue paxdeposit(const UniValue& params, bool fHelp)
c929bc3e 654{
655 uint64_t available,deposited,issued,withdrawn,approved,redeemed,seed,komodoshis = 0; int32_t height; char destaddr[64]; uint8_t i,pubkey37[33];
656 bool fSubtractFeeFromAmount = false;
43430608 657 if ( KOMODO_PAX == 0 )
e9d73912 658 {
b92d9db1 659 throw runtime_error("paxdeposit disabled without -pax");
e9d73912 660 }
c929bc3e 661 if ( komodo_is_issuer() != 0 )
662 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "paxdeposit only from KMD");
663 if (!EnsureWalletIsAvailable(fHelp))
4e5be259 664 throw runtime_error("paxdeposit needs wallet"); //return Value::null;
c929bc3e 665 if (fHelp || params.size() != 3)
666 throw runtime_error("paxdeposit address fiatoshis base");
667 LOCK2(cs_main, pwalletMain->cs_wallet);
668 CBitcoinAddress address(params[0].get_str());
669 if (!address.IsValid())
670 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
82fd1939 671 int64_t fiatoshis = atof(params[1].get_str().c_str()) * COIN;
c929bc3e 672 std::string base = params[2].get_str();
673 std::string dest;
86131275 674 height = chainActive.LastTip()->nHeight;
82fd1939 675 if ( pax_fiatstatus(&available,&deposited,&issued,&withdrawn,&approved,&redeemed,(char *)base.c_str()) != 0 || available < fiatoshis )
ea73ef00 676 {
f79f75be 677 fprintf(stderr,"available %llu vs fiatoshis %llu\n",(long long)available,(long long)fiatoshis);
82fd1939 678 throw runtime_error("paxdeposit not enough available inventory");
ea73ef00 679 }
c929bc3e 680 komodoshis = PAX_fiatdest(&seed,0,destaddr,pubkey37,(char *)params[0].get_str().c_str(),height,(char *)base.c_str(),fiatoshis);
681 dest.append(destaddr);
682 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
683 if (!destaddress.IsValid())
684 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
685 for (i=0; i<33; i++)
686 fprintf(stderr,"%02x",pubkey37[i]);
687 fprintf(stderr," ht.%d srcaddr.(%s) %s fiatoshis.%lld -> dest.(%s) komodoshis.%llu seed.%llx\n",height,(char *)params[0].get_str().c_str(),(char *)base.c_str(),(long long)fiatoshis,destaddr,(long long)komodoshis,(long long)seed);
688 EnsureWalletIsUnlocked();
689 CWalletTx wtx;
690 uint8_t opretbuf[64]; int32_t opretlen; uint64_t fee = komodoshis / 1000;
691 if ( fee < 10000 )
692 fee = 10000;
693 iguana_rwnum(1,&pubkey37[33],sizeof(height),&height);
694 opretlen = komodo_opreturnscript(opretbuf,'D',pubkey37,37);
695 SendMoney(address.Get(),fee,fSubtractFeeFromAmount,wtx,opretbuf,opretlen,komodoshis);
696 return wtx.GetHash().GetHex();
697}
698
14f3daa6 699UniValue paxwithdraw(const UniValue& params, bool fHelp)
c929bc3e 700{
701 CWalletTx wtx; std::string dest; int32_t kmdheight; uint64_t seed,komodoshis = 0; char destaddr[64]; uint8_t i,pubkey37[37]; bool fSubtractFeeFromAmount = false;
702 if ( ASSETCHAINS_SYMBOL[0] == 0 )
703 return(0);
704 if (!EnsureWalletIsAvailable(fHelp))
705 return 0;
16c7bf6b 706 throw runtime_error("paxwithdraw deprecated");
c929bc3e 707 if (fHelp || params.size() != 2)
708 throw runtime_error("paxwithdraw address fiatamount");
709 if ( komodo_isrealtime(&kmdheight) == 0 )
710 return(0);
711 LOCK2(cs_main, pwalletMain->cs_wallet);
712 CBitcoinAddress address(params[0].get_str());
713 if (!address.IsValid())
714 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
715 int64_t fiatoshis = atof(params[1].get_str().c_str()) * COIN;
716 komodoshis = PAX_fiatdest(&seed,1,destaddr,pubkey37,(char *)params[0].get_str().c_str(),kmdheight,ASSETCHAINS_SYMBOL,fiatoshis);
717 dest.append(destaddr);
718 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
719 if (!destaddress.IsValid())
720 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
721 for (i=0; i<33; i++)
722 printf("%02x",pubkey37[i]);
723 printf(" kmdheight.%d srcaddr.(%s) %s fiatoshis.%lld -> dest.(%s) komodoshis.%llu seed.%llx\n",kmdheight,(char *)params[0].get_str().c_str(),ASSETCHAINS_SYMBOL,(long long)fiatoshis,destaddr,(long long)komodoshis,(long long)seed);
724 EnsureWalletIsUnlocked();
725 uint8_t opretbuf[64]; int32_t opretlen; uint64_t fee = fiatoshis / 1000;
726 if ( fee < 10000 )
727 fee = 10000;
728 iguana_rwnum(1,&pubkey37[33],sizeof(kmdheight),&kmdheight);
729 opretlen = komodo_opreturnscript(opretbuf,'W',pubkey37,37);
730 SendMoney(destaddress.Get(),fee,fSubtractFeeFromAmount,wtx,opretbuf,opretlen,fiatoshis);
731 return wtx.GetHash().GetHex();
732}
733
d014114d 734UniValue listaddressgroupings(const UniValue& params, bool fHelp)
22dfd735 735{
b9fb692d 736 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 737 return NullUniValue;
9d365796 738
22dfd735 739 if (fHelp)
b1093efa
GM
740 throw runtime_error(
741 "listaddressgroupings\n"
a6099ef3 742 "\nLists groups of addresses which have had their common ownership\n"
b1093efa 743 "made public by common use as inputs or as the resulting change\n"
a6099ef3 744 "in past transactions\n"
745 "\nResult:\n"
746 "[\n"
747 " [\n"
748 " [\n"
1333d0d7 749 " \"" + strprintf("%s",komodo_chainname()) + " address\", (string) The " + strprintf("%s",komodo_chainname()) + " address\n"
750 " amount, (numeric) The amount in " + strprintf("%s",komodo_chainname()) + "\n"
7b782f5b 751 " \"account\" (string, optional) The account (DEPRECATED)\n"
a6099ef3 752 " ]\n"
753 " ,...\n"
754 " ]\n"
755 " ,...\n"
756 "]\n"
757 "\nExamples:\n"
758 + HelpExampleCli("listaddressgroupings", "")
759 + HelpExampleRpc("listaddressgroupings", "")
760 );
22dfd735 761
4401b2d7
EL
762 LOCK2(cs_main, pwalletMain->cs_wallet);
763
38fc4b70 764 UniValue jsonGroupings(UniValue::VARR);
a372168e 765 map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
b1093efa 766 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
22dfd735 767 {
38fc4b70 768 UniValue jsonGrouping(UniValue::VARR);
b1093efa 769 BOOST_FOREACH(CTxDestination address, grouping)
22dfd735 770 {
38fc4b70 771 UniValue addressInfo(UniValue::VARR);
b1093efa 772 addressInfo.push_back(CBitcoinAddress(address).ToString());
22dfd735 773 addressInfo.push_back(ValueFromAmount(balances[address]));
774 {
22dfd735 775 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
61885513 776 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
22dfd735 777 }
778 jsonGrouping.push_back(addressInfo);
779 }
780 jsonGroupings.push_back(jsonGrouping);
781 }
782 return jsonGroupings;
783}
784
d014114d 785UniValue signmessage(const UniValue& params, bool fHelp)
e3bc5698 786{
b9fb692d 787 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 788 return NullUniValue;
9d365796 789
e3bc5698
JG
790 if (fHelp || params.size() != 2)
791 throw runtime_error(
1333d0d7 792 "signmessage \"" + strprintf("%s",komodo_chainname()) + " address\" \"message\"\n"
a6099ef3 793 "\nSign a message with the private key of an address"
794 + HelpRequiringPassphrase() + "\n"
795 "\nArguments:\n"
1333d0d7 796 "1. \"" + strprintf("%s",komodo_chainname()) + " address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to use for the private key.\n"
a6099ef3 797 "2. \"message\" (string, required) The message to create a signature of.\n"
798 "\nResult:\n"
799 "\"signature\" (string) The signature of the message encoded in base 64\n"
800 "\nExamples:\n"
801 "\nUnlock the wallet for 30 seconds\n"
802 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
803 "\nCreate the signature\n"
1333d0d7 804 + HelpExampleCli("signmessage", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"my message\"") +
a6099ef3 805 "\nVerify the signature\n"
1333d0d7 806 + HelpExampleCli("verifymessage", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"signature\" \"my message\"") +
a6099ef3 807 "\nAs json rpc\n"
1333d0d7 808 + HelpExampleRpc("signmessage", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"my message\"")
a6099ef3 809 );
e3bc5698 810
4401b2d7
EL
811 LOCK2(cs_main, pwalletMain->cs_wallet);
812
e3bc5698
JG
813 EnsureWalletIsUnlocked();
814
815 string strAddress = params[0].get_str();
816 string strMessage = params[1].get_str();
817
818 CBitcoinAddress addr(strAddress);
819 if (!addr.IsValid())
738835d7 820 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
e3bc5698
JG
821
822 CKeyID keyID;
823 if (!addr.GetKeyID(keyID))
738835d7 824 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
e3bc5698
JG
825
826 CKey key;
827 if (!pwalletMain->GetKey(keyID, key))
738835d7 828 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
e3bc5698 829
8980a509 830 CHashWriter ss(SER_GETHASH, 0);
e3bc5698
JG
831 ss << strMessageMagic;
832 ss << strMessage;
833
834 vector<unsigned char> vchSig;
8980a509 835 if (!key.SignCompact(ss.GetHash(), vchSig))
738835d7 836 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
e3bc5698
JG
837
838 return EncodeBase64(&vchSig[0], vchSig.size());
839}
840
d014114d 841UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
e3bc5698 842{
b9fb692d 843 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 844 return NullUniValue;
9d365796 845
e3bc5698
JG
846 if (fHelp || params.size() < 1 || params.size() > 2)
847 throw runtime_error(
1333d0d7 848 "getreceivedbyaddress \"" + strprintf("%s",komodo_chainname()) + "_address\" ( minconf )\n"
849 "\nReturns the total amount received by the given " + strprintf("%s",komodo_chainname()) + " address in transactions with at least minconf confirmations.\n"
a6099ef3 850 "\nArguments:\n"
1333d0d7 851 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address for transactions.\n"
a6099ef3 852 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
853 "\nResult:\n"
1333d0d7 854 "amount (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received at this address.\n"
a6099ef3 855 "\nExamples:\n"
856 "\nThe amount from transactions with at least 1 confirmation\n"
1333d0d7 857 + HelpExampleCli("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"") +
a6099ef3 858 "\nThe amount including unconfirmed transactions, zero confirmations\n"
1333d0d7 859 + HelpExampleCli("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0") +
c938fb1f 860 "\nThe amount with at least 6 confirmations, very safe\n"
1333d0d7 861 + HelpExampleCli("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 6") +
a6099ef3 862 "\nAs a json rpc call\n"
1333d0d7 863 + HelpExampleRpc("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", 6")
a6099ef3 864 );
e3bc5698 865
4401b2d7
EL
866 LOCK2(cs_main, pwalletMain->cs_wallet);
867
e3bc5698
JG
868 // Bitcoin address
869 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
e3bc5698 870 if (!address.IsValid())
1333d0d7 871 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
0be990ba 872 CScript scriptPubKey = GetScriptForDestination(address.Get());
e3bc5698
JG
873 if (!IsMine(*pwalletMain,scriptPubKey))
874 return (double)0.0;
875
876 // Minimum confirmations
877 int nMinDepth = 1;
878 if (params.size() > 1)
879 nMinDepth = params[1].get_int();
880
881 // Tally
a372168e 882 CAmount nAmount = 0;
e3bc5698
JG
883 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
884 {
885 const CWalletTx& wtx = (*it).second;
75a4d512 886 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
887 continue;
888
889 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
890 if (txout.scriptPubKey == scriptPubKey)
891 if (wtx.GetDepthInMainChain() >= nMinDepth)
47658758 892 nAmount += txout.nValue; // komodo_interest?
e3bc5698
JG
893 }
894
895 return ValueFromAmount(nAmount);
896}
897
898
d014114d 899UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
e3bc5698 900{
b9fb692d 901 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 902 return NullUniValue;
9d365796 903
e3bc5698
JG
904 if (fHelp || params.size() < 1 || params.size() > 2)
905 throw runtime_error(
a6099ef3 906 "getreceivedbyaccount \"account\" ( minconf )\n"
7b782f5b 907 "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
a6099ef3 908 "\nArguments:\n"
3c31eb24 909 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 910 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
911 "\nResult:\n"
1333d0d7 912 "amount (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received for this account.\n"
a6099ef3 913 "\nExamples:\n"
914 "\nAmount received by the default account with at least 1 confirmation\n"
915 + HelpExampleCli("getreceivedbyaccount", "\"\"") +
916 "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
917 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
918 "\nThe amount with at least 6 confirmation, very safe\n"
919 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
920 "\nAs a json rpc call\n"
921 + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
922 );
e3bc5698 923
4401b2d7
EL
924 LOCK2(cs_main, pwalletMain->cs_wallet);
925
e3bc5698
JG
926 // Minimum confirmations
927 int nMinDepth = 1;
928 if (params.size() > 1)
929 nMinDepth = params[1].get_int();
930
931 // Get the set of pub keys assigned to account
932 string strAccount = AccountFromValue(params[0]);
3624356e 933 set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
e3bc5698
JG
934
935 // Tally
a372168e 936 CAmount nAmount = 0;
e3bc5698
JG
937 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
938 {
939 const CWalletTx& wtx = (*it).second;
75a4d512 940 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
941 continue;
942
943 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
944 {
945 CTxDestination address;
946 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
947 if (wtx.GetDepthInMainChain() >= nMinDepth)
47658758 948 nAmount += txout.nValue; // komodo_interest?
e3bc5698
JG
949 }
950 }
951
952 return (double)nAmount / (double)COIN;
953}
954
955
a372168e 956CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
e3bc5698 957{
a372168e 958 CAmount nBalance = 0;
e3bc5698
JG
959
960 // Tally wallet transactions
961 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
962 {
963 const CWalletTx& wtx = (*it).second;
75a4d512 964 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
e3bc5698
JG
965 continue;
966
a372168e 967 CAmount nReceived, nSent, nFee;
d4640d7d 968 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
e3bc5698
JG
969
970 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
971 nBalance += nReceived;
e07c8e91 972 nBalance -= nSent + nFee;
e3bc5698
JG
973 }
974
975 // Tally internal accounting entries
976 nBalance += walletdb.GetAccountCreditDebit(strAccount);
977
978 return nBalance;
979}
980
a372168e 981CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
e3bc5698
JG
982{
983 CWalletDB walletdb(pwalletMain->strWalletFile);
d4640d7d 984 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
e3bc5698
JG
985}
986
987
d014114d 988UniValue getbalance(const UniValue& params, bool fHelp)
e3bc5698 989{
b9fb692d 990 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 991 return NullUniValue;
9d365796 992
d4640d7d 993 if (fHelp || params.size() > 3)
e3bc5698 994 throw runtime_error(
d4640d7d 995 "getbalance ( \"account\" minconf includeWatchonly )\n"
3c31eb24 996 "\nReturns the server's total available balance.\n"
a6099ef3 997 "\nArguments:\n"
715e5bbe 998 "1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" or to the string \"*\", either of which will give the total available balance. Passing any other string will result in an error.\n"
a6099ef3 999 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
d4640d7d 1000 "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
a6099ef3 1001 "\nResult:\n"
1333d0d7 1002 "amount (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received for this account.\n"
a6099ef3 1003 "\nExamples:\n"
7b782f5b 1004 "\nThe total amount in the wallet\n"
a6099ef3 1005 + HelpExampleCli("getbalance", "") +
7b782f5b 1006 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3cf1f436 1007 + HelpExampleCli("getbalance", "\"*\" 6") +
a6099ef3 1008 "\nAs a json rpc call\n"
7b782f5b 1009 + HelpExampleRpc("getbalance", "\"*\", 6")
a6099ef3 1010 );
e3bc5698 1011
4401b2d7
EL
1012 LOCK2(cs_main, pwalletMain->cs_wallet);
1013
e3bc5698
JG
1014 if (params.size() == 0)
1015 return ValueFromAmount(pwalletMain->GetBalance());
1016
1017 int nMinDepth = 1;
1018 if (params.size() > 1)
1019 nMinDepth = params[1].get_int();
a3e192a3 1020 isminefilter filter = ISMINE_SPENDABLE;
a5c6c5d6
J
1021 if(params.size() > 2)
1022 if(params[2].get_bool())
a3e192a3 1023 filter = filter | ISMINE_WATCH_ONLY;
e3bc5698
JG
1024
1025 if (params[0].get_str() == "*") {
1026 // Calculate total balance a different way from GetBalance()
1027 // (GetBalance() sums up all unspent TxOuts)
c9fd9078 1028 // getbalance and "getbalance * 1 true" should return the same number
a372168e 1029 CAmount nBalance = 0;
e3bc5698
JG
1030 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1031 {
1032 const CWalletTx& wtx = (*it).second;
c9fd9078 1033 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
e3bc5698
JG
1034 continue;
1035
a372168e 1036 CAmount allFee;
e3bc5698 1037 string strSentAccount;
1b4568cb
CL
1038 list<COutputEntry> listReceived;
1039 list<COutputEntry> listSent;
d4640d7d 1040 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
e3bc5698
JG
1041 if (wtx.GetDepthInMainChain() >= nMinDepth)
1042 {
1b4568cb
CL
1043 BOOST_FOREACH(const COutputEntry& r, listReceived)
1044 nBalance += r.amount;
e3bc5698 1045 }
1b4568cb
CL
1046 BOOST_FOREACH(const COutputEntry& s, listSent)
1047 nBalance -= s.amount;
e3bc5698 1048 nBalance -= allFee;
e3bc5698
JG
1049 }
1050 return ValueFromAmount(nBalance);
1051 }
1052
1053 string strAccount = AccountFromValue(params[0]);
1054
a372168e 1055 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
e3bc5698
JG
1056
1057 return ValueFromAmount(nBalance);
1058}
1059
d014114d 1060UniValue getunconfirmedbalance(const UniValue &params, bool fHelp)
6027b460 1061{
b9fb692d 1062 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1063 return NullUniValue;
9d365796 1064
6027b460
MB
1065 if (fHelp || params.size() > 0)
1066 throw runtime_error(
1067 "getunconfirmedbalance\n"
1068 "Returns the server's total unconfirmed balance\n");
4401b2d7
EL
1069
1070 LOCK2(cs_main, pwalletMain->cs_wallet);
1071
6027b460
MB
1072 return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
1073}
1074
e3bc5698 1075
d014114d 1076UniValue movecmd(const UniValue& params, bool fHelp)
e3bc5698 1077{
b9fb692d 1078 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1079 return NullUniValue;
9d365796 1080
e3bc5698
JG
1081 if (fHelp || params.size() < 3 || params.size() > 5)
1082 throw runtime_error(
a6099ef3 1083 "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
7b782f5b 1084 "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
a6099ef3 1085 "\nArguments:\n"
3c31eb24
JG
1086 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1087 "2. \"toaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1333d0d7 1088 "3. amount (numeric) Quantity of " + strprintf("%s",komodo_chainname()) + " to move between accounts.\n"
091b2116
RN
1089 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
1090 "5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
a6099ef3 1091 "\nResult:\n"
45bfa137 1092 "true|false (boolean) true if successful.\n"
a6099ef3 1093 "\nExamples:\n"
1333d0d7 1094 "\nMove 0.01 " + strprintf("%s",komodo_chainname()) + " from the default account to the account named tabby\n"
a6099ef3 1095 + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
1333d0d7 1096 "\nMove 0.01 " + strprintf("%s",komodo_chainname()) + " timotei to akiko with a comment and funds have 6 confirmations\n"
a6099ef3 1097 + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
1098 "\nAs a json rpc call\n"
1099 + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
1100 );
b310ffff 1101 if ( ASSETCHAINS_PRIVATE != 0 )
1102 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
e3bc5698 1103
4401b2d7
EL
1104 LOCK2(cs_main, pwalletMain->cs_wallet);
1105
e3bc5698
JG
1106 string strFrom = AccountFromValue(params[0]);
1107 string strTo = AccountFromValue(params[1]);
a372168e 1108 CAmount nAmount = AmountFromValue(params[2]);
e76a3849
WL
1109 if (nAmount <= 0)
1110 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
e3bc5698
JG
1111 if (params.size() > 3)
1112 // unused parameter, used to be nMinDepth, keep type-checking it though
1113 (void)params[3].get_int();
1114 string strComment;
1115 if (params.size() > 4)
1116 strComment = params[4].get_str();
1117
1118 CWalletDB walletdb(pwalletMain->strWalletFile);
1119 if (!walletdb.TxnBegin())
738835d7 1120 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
e3bc5698 1121
51ed9ec9 1122 int64_t nNow = GetAdjustedTime();
e3bc5698
JG
1123
1124 // Debit
1125 CAccountingEntry debit;
4291e8fe 1126 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
e3bc5698
JG
1127 debit.strAccount = strFrom;
1128 debit.nCreditDebit = -nAmount;
1129 debit.nTime = nNow;
1130 debit.strOtherAccount = strTo;
1131 debit.strComment = strComment;
1132 walletdb.WriteAccountingEntry(debit);
1133
1134 // Credit
1135 CAccountingEntry credit;
4291e8fe 1136 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
e3bc5698
JG
1137 credit.strAccount = strTo;
1138 credit.nCreditDebit = nAmount;
1139 credit.nTime = nNow;
1140 credit.strOtherAccount = strFrom;
1141 credit.strComment = strComment;
1142 walletdb.WriteAccountingEntry(credit);
1143
1144 if (!walletdb.TxnCommit())
738835d7 1145 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
e3bc5698
JG
1146
1147 return true;
1148}
1149
1150
d014114d 1151UniValue sendfrom(const UniValue& params, bool fHelp)
e3bc5698 1152{
b9fb692d 1153 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1154 return NullUniValue;
9d365796 1155
e3bc5698
JG
1156 if (fHelp || params.size() < 3 || params.size() > 6)
1157 throw runtime_error(
1333d0d7 1158 "sendfrom \"fromaccount\" \"to" + strprintf("%s",komodo_chainname()) + "address\" amount ( minconf \"comment\" \"comment-to\" )\n"
1159 "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a " + strprintf("%s",komodo_chainname()) + " address.\n"
a6099ef3 1160 "The amount is a real and is rounded to the nearest 0.00000001."
1161 + HelpRequiringPassphrase() + "\n"
1162 "\nArguments:\n"
3c31eb24 1163 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1333d0d7 1164 "2. \"to" + strprintf("%s",komodo_chainname()) + "address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to send funds to.\n"
1165 "3. amount (numeric, required) The amount in " + strprintf("%s",komodo_chainname()) + " (transaction fee is added on top).\n"
a6099ef3 1166 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
1167 "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
1168 " This is not part of the transaction, just kept in your wallet.\n"
1169 "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n"
1170 " to which you're sending the transaction. This is not part of the transaction, \n"
1171 " it is just kept in your wallet.\n"
1172 "\nResult:\n"
b5ef85c7 1173 "\"transactionid\" (string) The transaction id.\n"
a6099ef3 1174 "\nExamples:\n"
1333d0d7 1175 "\nSend 0.01 " + strprintf("%s",komodo_chainname()) + " from the default account to the address, must have at least 1 confirmation\n"
1176 + HelpExampleCli("sendfrom", "\"\" \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.01") +
a6099ef3 1177 "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
1333d0d7 1178 + HelpExampleCli("sendfrom", "\"tabby\" \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.01 6 \"donation\" \"seans outpost\"") +
a6099ef3 1179 "\nAs a json rpc call\n"
1333d0d7 1180 + HelpExampleRpc("sendfrom", "\"tabby\", \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", 0.01, 6, \"donation\", \"seans outpost\"")
a6099ef3 1181 );
b310ffff 1182 if ( ASSETCHAINS_PRIVATE != 0 )
1183 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
e3bc5698 1184
4401b2d7
EL
1185 LOCK2(cs_main, pwalletMain->cs_wallet);
1186
e3bc5698
JG
1187 string strAccount = AccountFromValue(params[0]);
1188 CBitcoinAddress address(params[1].get_str());
1189 if (!address.IsValid())
1333d0d7 1190 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
a372168e 1191 CAmount nAmount = AmountFromValue(params[2]);
e76a3849
WL
1192 if (nAmount <= 0)
1193 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
e3bc5698
JG
1194 int nMinDepth = 1;
1195 if (params.size() > 3)
1196 nMinDepth = params[3].get_int();
1197
1198 CWalletTx wtx;
1199 wtx.strFromAccount = strAccount;
ed21d5bd 1200 if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty())
e3bc5698 1201 wtx.mapValue["comment"] = params[4].get_str();
ed21d5bd 1202 if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty())
e3bc5698
JG
1203 wtx.mapValue["to"] = params[5].get_str();
1204
1205 EnsureWalletIsUnlocked();
1206
1207 // Check funds
a372168e 1208 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
e3bc5698 1209 if (nAmount > nBalance)
738835d7 1210 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
e3bc5698 1211
b62d7030 1212 SendMoney(address.Get(), nAmount, false, wtx,0,0,0);
e3bc5698 1213
805344dc 1214 return wtx.GetHash().GetHex();
e3bc5698
JG
1215}
1216
1217
d014114d 1218UniValue sendmany(const UniValue& params, bool fHelp)
e3bc5698 1219{
b9fb692d 1220 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1221 return NullUniValue;
9d365796 1222
292623ad 1223 if (fHelp || params.size() < 2 || params.size() > 5)
e3bc5698 1224 throw runtime_error(
40a75733 1225 "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
a6099ef3 1226 "\nSend multiple times. Amounts are double-precision floating point numbers."
1227 + HelpRequiringPassphrase() + "\n"
1228 "\nArguments:\n"
3c31eb24 1229 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 1230 "2. \"amounts\" (string, required) A json object with addresses and amounts\n"
1231 " {\n"
1333d0d7 1232 " \"address\":amount (numeric) The " + strprintf("%s",komodo_chainname()) + " address is the key, the numeric amount in " + strprintf("%s",komodo_chainname()) + " is the value\n"
a6099ef3 1233 " ,...\n"
1234 " }\n"
1235 "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
1236 "4. \"comment\" (string, optional) A comment\n"
40a75733 1237 "5. subtractfeefromamount (string, optional) A json array with addresses.\n"
292623ad 1238 " The fee will be equally deducted from the amount of each selected address.\n"
1333d0d7 1239 " Those recipients will receive less " + strprintf("%s",komodo_chainname()) + " than you enter in their corresponding amount field.\n"
40a75733
LD
1240 " If no addresses are specified here, the sender pays the fee.\n"
1241 " [\n"
1242 " \"address\" (string) Subtract fee from this address\n"
292623ad 1243 " ,...\n"
40a75733 1244 " ]\n"
a6099ef3 1245 "\nResult:\n"
1246 "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
b5ef85c7 1247 " the number of addresses.\n"
a6099ef3 1248 "\nExamples:\n"
1249 "\nSend two amounts to two different addresses:\n"
1333d0d7 1250 + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\"") +
a6099ef3 1251 "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
1333d0d7 1252 + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\" 6 \"testing\"") +
292623ad 1253 "\nSend two amounts to two different addresses, subtract fee from amount:\n"
1333d0d7 1254 + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\" 1 \"\" \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"") +
a6099ef3 1255 "\nAs a json rpc call\n"
1333d0d7 1256 + HelpExampleRpc("sendmany", "\"\", \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\", 6, \"testing\"")
a6099ef3 1257 );
b310ffff 1258 if ( ASSETCHAINS_PRIVATE != 0 )
1259 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
e3bc5698 1260
4401b2d7
EL
1261 LOCK2(cs_main, pwalletMain->cs_wallet);
1262
e3bc5698 1263 string strAccount = AccountFromValue(params[0]);
851f58f9 1264 UniValue sendTo = params[1].get_obj();
e3bc5698
JG
1265 int nMinDepth = 1;
1266 if (params.size() > 2)
1267 nMinDepth = params[2].get_int();
1268
1269 CWalletTx wtx;
1270 wtx.strFromAccount = strAccount;
ed21d5bd 1271 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
e3bc5698
JG
1272 wtx.mapValue["comment"] = params[3].get_str();
1273
38fc4b70 1274 UniValue subtractFeeFromAmount(UniValue::VARR);
292623ad 1275 if (params.size() > 4)
40a75733 1276 subtractFeeFromAmount = params[4].get_array();
292623ad 1277
e3bc5698 1278 set<CBitcoinAddress> setAddress;
292623ad 1279 vector<CRecipient> vecSend;
e3bc5698 1280
a372168e 1281 CAmount totalAmount = 0;
ed21d5bd
JG
1282 vector<string> keys = sendTo.getKeys();
1283 BOOST_FOREACH(const string& name_, keys)
e3bc5698 1284 {
ed21d5bd 1285 CBitcoinAddress address(name_);
e3bc5698 1286 if (!address.IsValid())
1333d0d7 1287 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid " + strprintf("%s",komodo_chainname()) + " address: ")+name_);
e3bc5698 1288
9d83c1ad 1289 //if (setAddress.count(address))
1290 // throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
e3bc5698
JG
1291 setAddress.insert(address);
1292
0be990ba 1293 CScript scriptPubKey = GetScriptForDestination(address.Get());
ed21d5bd 1294 CAmount nAmount = AmountFromValue(sendTo[name_]);
e76a3849
WL
1295 if (nAmount <= 0)
1296 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
e3bc5698
JG
1297 totalAmount += nAmount;
1298
292623ad 1299 bool fSubtractFeeFromAmount = false;
cc71666a 1300 for (size_t idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
d014114d 1301 const UniValue& addr = subtractFeeFromAmount[idx];
9756b7bd 1302 if (addr.get_str() == name_)
292623ad 1303 fSubtractFeeFromAmount = true;
9756b7bd 1304 }
292623ad
CL
1305
1306 CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
1307 vecSend.push_back(recipient);
e3bc5698
JG
1308 }
1309
1310 EnsureWalletIsUnlocked();
1311
1312 // Check funds
170d7b7a 1313 CAmount nBalance = pwalletMain->GetBalance();
c83c59f9 1314 //CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
e3bc5698 1315 if (totalAmount > nBalance)
738835d7 1316 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
e3bc5698
JG
1317
1318 // Send
1319 CReserveKey keyChange(pwalletMain);
a372168e 1320 CAmount nFeeRequired = 0;
292623ad 1321 int nChangePosRet = -1;
1f00f4e9 1322 string strFailReason;
292623ad 1323 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
e3bc5698 1324 if (!fCreated)
1f00f4e9 1325 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
e3bc5698 1326 if (!pwalletMain->CommitTransaction(wtx, keyChange))
738835d7 1327 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
e3bc5698 1328
805344dc 1329 return wtx.GetHash().GetHex();
e3bc5698
JG
1330}
1331
723a03d2 1332// Defined in rpcmisc.cpp
d014114d 1333extern CScript _createmultisig_redeemScript(const UniValue& params);
34226be7 1334
d014114d 1335UniValue addmultisigaddress(const UniValue& params, bool fHelp)
34226be7 1336{
b9fb692d 1337 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1338 return NullUniValue;
9d365796 1339
34226be7
GA
1340 if (fHelp || params.size() < 2 || params.size() > 3)
1341 {
a6099ef3 1342 string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
1343 "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
1333d0d7 1344 "Each key is a " + strprintf("%s",komodo_chainname()) + " address or hex-encoded public key.\n"
7b782f5b 1345 "If 'account' is specified (DEPRECATED), assign address to that account.\n"
a6099ef3 1346
1347 "\nArguments:\n"
1348 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
1333d0d7 1349 "2. \"keysobject\" (string, required) A json array of " + strprintf("%s",komodo_chainname()) + " addresses or hex-encoded public keys\n"
a6099ef3 1350 " [\n"
1333d0d7 1351 " \"address\" (string) " + strprintf("%s",komodo_chainname()) + " address or hex-encoded public key\n"
a6099ef3 1352 " ...,\n"
1353 " ]\n"
3c31eb24 1354 "3. \"account\" (string, optional) DEPRECATED. If provided, MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 1355
1356 "\nResult:\n"
1333d0d7 1357 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) A " + strprintf("%s",komodo_chainname()) + " address associated with the keys.\n"
a6099ef3 1358
1359 "\nExamples:\n"
1360 "\nAdd a multisig address from 2 addresses\n"
1333d0d7 1361 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"") +
a6099ef3 1362 "\nAs json rpc call\n"
1333d0d7 1363 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"")
a6099ef3 1364 ;
34226be7
GA
1365 throw runtime_error(msg);
1366 }
1367
4401b2d7
EL
1368 LOCK2(cs_main, pwalletMain->cs_wallet);
1369
34226be7
GA
1370 string strAccount;
1371 if (params.size() > 2)
1372 strAccount = AccountFromValue(params[2]);
e3bc5698
JG
1373
1374 // Construct using pay-to-script-hash:
787ee0c9 1375 CScript inner = _createmultisig_redeemScript(params);
066e2a14 1376 CScriptID innerID(inner);
e3bc5698
JG
1377 pwalletMain->AddCScript(inner);
1378
a41d5fe0 1379 pwalletMain->SetAddressBook(innerID, strAccount, "send");
e3bc5698
JG
1380 return CBitcoinAddress(innerID).ToString();
1381}
1382
1383
1384struct tallyitem
1385{
a372168e 1386 CAmount nAmount;
e3bc5698 1387 int nConf;
62c9b115 1388 vector<uint256> txids;
0fa2f889 1389 bool fIsWatchonly;
e3bc5698
JG
1390 tallyitem()
1391 {
1392 nAmount = 0;
1393 nConf = std::numeric_limits<int>::max();
0fa2f889 1394 fIsWatchonly = false;
e3bc5698
JG
1395 }
1396};
1397
d014114d 1398UniValue ListReceived(const UniValue& params, bool fByAccounts)
e3bc5698
JG
1399{
1400 // Minimum confirmations
1401 int nMinDepth = 1;
1402 if (params.size() > 0)
1403 nMinDepth = params[0].get_int();
1404
1405 // Whether to include empty accounts
1406 bool fIncludeEmpty = false;
1407 if (params.size() > 1)
1408 fIncludeEmpty = params[1].get_bool();
1409
a3e192a3 1410 isminefilter filter = ISMINE_SPENDABLE;
0fa2f889
J
1411 if(params.size() > 2)
1412 if(params[2].get_bool())
a3e192a3 1413 filter = filter | ISMINE_WATCH_ONLY;
0fa2f889 1414
e3bc5698
JG
1415 // Tally
1416 map<CBitcoinAddress, tallyitem> mapTally;
1417 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1418 {
1419 const CWalletTx& wtx = (*it).second;
1420
75a4d512 1421 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
1422 continue;
1423
1424 int nDepth = wtx.GetDepthInMainChain();
1425 if (nDepth < nMinDepth)
1426 continue;
1427
1428 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1429 {
1430 CTxDestination address;
0fa2f889
J
1431 if (!ExtractDestination(txout.scriptPubKey, address))
1432 continue;
1433
1434 isminefilter mine = IsMine(*pwalletMain, address);
f28707a8 1435 if(!(mine & filter))
e3bc5698
JG
1436 continue;
1437
1438 tallyitem& item = mapTally[address];
47658758 1439 item.nAmount += txout.nValue; // komodo_interest?
e3bc5698 1440 item.nConf = min(item.nConf, nDepth);
805344dc 1441 item.txids.push_back(wtx.GetHash());
a3e192a3 1442 if (mine & ISMINE_WATCH_ONLY)
0fa2f889 1443 item.fIsWatchonly = true;
e3bc5698
JG
1444 }
1445 }
1446
1447 // Reply
38fc4b70 1448 UniValue ret(UniValue::VARR);
e3bc5698 1449 map<string, tallyitem> mapAccountTally;
61885513 1450 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
e3bc5698
JG
1451 {
1452 const CBitcoinAddress& address = item.first;
61885513 1453 const string& strAccount = item.second.name;
e3bc5698
JG
1454 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1455 if (it == mapTally.end() && !fIncludeEmpty)
1456 continue;
1457
a372168e 1458 CAmount nAmount = 0;
e3bc5698 1459 int nConf = std::numeric_limits<int>::max();
0fa2f889 1460 bool fIsWatchonly = false;
e3bc5698
JG
1461 if (it != mapTally.end())
1462 {
1463 nAmount = (*it).second.nAmount;
1464 nConf = (*it).second.nConf;
0fa2f889 1465 fIsWatchonly = (*it).second.fIsWatchonly;
e3bc5698
JG
1466 }
1467
1468 if (fByAccounts)
1469 {
1470 tallyitem& item = mapAccountTally[strAccount];
1471 item.nAmount += nAmount;
1472 item.nConf = min(item.nConf, nConf);
0fa2f889 1473 item.fIsWatchonly = fIsWatchonly;
e3bc5698
JG
1474 }
1475 else
1476 {
38fc4b70 1477 UniValue obj(UniValue::VOBJ);
0fa2f889
J
1478 if(fIsWatchonly)
1479 obj.push_back(Pair("involvesWatchonly", true));
e3bc5698
JG
1480 obj.push_back(Pair("address", address.ToString()));
1481 obj.push_back(Pair("account", strAccount));
1482 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1483 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
38fc4b70 1484 UniValue transactions(UniValue::VARR);
1a204694 1485 if (it != mapTally.end())
62c9b115 1486 {
1a204694
A
1487 BOOST_FOREACH(const uint256& item, (*it).second.txids)
1488 {
1489 transactions.push_back(item.GetHex());
1490 }
62c9b115
A
1491 }
1492 obj.push_back(Pair("txids", transactions));
e3bc5698
JG
1493 ret.push_back(obj);
1494 }
1495 }
1496
1497 if (fByAccounts)
1498 {
1499 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1500 {
a372168e 1501 CAmount nAmount = (*it).second.nAmount;
e3bc5698 1502 int nConf = (*it).second.nConf;
38fc4b70 1503 UniValue obj(UniValue::VOBJ);
0fa2f889
J
1504 if((*it).second.fIsWatchonly)
1505 obj.push_back(Pair("involvesWatchonly", true));
e3bc5698
JG
1506 obj.push_back(Pair("account", (*it).first));
1507 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1508 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1509 ret.push_back(obj);
1510 }
1511 }
1512
1513 return ret;
1514}
1515
d014114d 1516UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
e3bc5698 1517{
b9fb692d 1518 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1519 return NullUniValue;
9d365796 1520
0fa2f889 1521 if (fHelp || params.size() > 3)
e3bc5698 1522 throw runtime_error(
0fa2f889 1523 "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
a6099ef3 1524 "\nList balances by receiving address.\n"
1525 "\nArguments:\n"
1526 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
5617267c 1527 "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n"
0fa2f889 1528 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
a6099ef3 1529
1530 "\nResult:\n"
1531 "[\n"
1532 " {\n"
8f6860a0 1533 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
a6099ef3 1534 " \"address\" : \"receivingaddress\", (string) The receiving address\n"
7b782f5b 1535 " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
1333d0d7 1536 " \"amount\" : x.xxx, (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received by the address\n"
a6099ef3 1537 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1538 " }\n"
1539 " ,...\n"
1540 "]\n"
1541
1542 "\nExamples:\n"
1543 + HelpExampleCli("listreceivedbyaddress", "")
1544 + HelpExampleCli("listreceivedbyaddress", "6 true")
0fa2f889 1545 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
a6099ef3 1546 );
e3bc5698 1547
4401b2d7
EL
1548 LOCK2(cs_main, pwalletMain->cs_wallet);
1549
e3bc5698
JG
1550 return ListReceived(params, false);
1551}
1552
d014114d 1553UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
e3bc5698 1554{
b9fb692d 1555 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1556 return NullUniValue;
9d365796 1557
0fa2f889 1558 if (fHelp || params.size() > 3)
e3bc5698 1559 throw runtime_error(
0fa2f889 1560 "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
7b782f5b 1561 "\nDEPRECATED. List balances by account.\n"
a6099ef3 1562 "\nArguments:\n"
1563 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1564 "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
0fa2f889 1565 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
a6099ef3 1566
1567 "\nResult:\n"
1568 "[\n"
1569 " {\n"
8f6860a0 1570 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
a6099ef3 1571 " \"account\" : \"accountname\", (string) The account name of the receiving account\n"
1572 " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
1573 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1574 " }\n"
1575 " ,...\n"
1576 "]\n"
1577
1578 "\nExamples:\n"
1579 + HelpExampleCli("listreceivedbyaccount", "")
1580 + HelpExampleCli("listreceivedbyaccount", "6 true")
0fa2f889 1581 + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
a6099ef3 1582 );
e3bc5698 1583
4401b2d7
EL
1584 LOCK2(cs_main, pwalletMain->cs_wallet);
1585
e3bc5698
JG
1586 return ListReceived(params, true);
1587}
1588
851f58f9 1589static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
cc6cfab3
LD
1590{
1591 CBitcoinAddress addr;
1592 if (addr.Set(dest))
1593 entry.push_back(Pair("address", addr.ToString()));
1594}
1595
d014114d 1596void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
e3bc5698 1597{
a372168e 1598 CAmount nFee;
e3bc5698 1599 string strSentAccount;
1b4568cb
CL
1600 list<COutputEntry> listReceived;
1601 list<COutputEntry> listSent;
e3bc5698 1602
d7d5d23b 1603 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
e3bc5698
JG
1604
1605 bool fAllAccounts = (strAccount == string("*"));
a3e192a3 1606 bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
e3bc5698 1607
e3bc5698
JG
1608 // Sent
1609 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1610 {
1b4568cb 1611 BOOST_FOREACH(const COutputEntry& s, listSent)
e3bc5698 1612 {
38fc4b70 1613 UniValue entry(UniValue::VOBJ);
1b4568cb 1614 if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
952877e0 1615 entry.push_back(Pair("involvesWatchonly", true));
e3bc5698 1616 entry.push_back(Pair("account", strSentAccount));
1b4568cb 1617 MaybePushAddress(entry, s.destination);
b96f6a77 1618 entry.push_back(Pair("category", "send"));
1b4568cb
CL
1619 entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
1620 entry.push_back(Pair("vout", s.vout));
e3bc5698
JG
1621 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1622 if (fLong)
1623 WalletTxToJSON(wtx, entry);
9d365796 1624 #ifdef __APPLE__
1625 entry.push_back(Pair("size", (uint64_t)static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1626 #else
f32cade8 1627 entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
9d365796 1628 #endif
e3bc5698
JG
1629 ret.push_back(entry);
1630 }
1631 }
1632
1633 // Received
1634 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1635 {
1b4568cb 1636 BOOST_FOREACH(const COutputEntry& r, listReceived)
e3bc5698
JG
1637 {
1638 string account;
1b4568cb
CL
1639 if (pwalletMain->mapAddressBook.count(r.destination))
1640 account = pwalletMain->mapAddressBook[r.destination].name;
e3bc5698
JG
1641 if (fAllAccounts || (account == strAccount))
1642 {
38fc4b70 1643 UniValue entry(UniValue::VOBJ);
1b4568cb 1644 if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
952877e0 1645 entry.push_back(Pair("involvesWatchonly", true));
e3bc5698 1646 entry.push_back(Pair("account", account));
1b4568cb 1647 MaybePushAddress(entry, r.destination);
e07c8e91
LD
1648 if (wtx.IsCoinBase())
1649 {
1650 if (wtx.GetDepthInMainChain() < 1)
1651 entry.push_back(Pair("category", "orphan"));
1652 else if (wtx.GetBlocksToMaturity() > 0)
1653 entry.push_back(Pair("category", "immature"));
1654 else
1655 entry.push_back(Pair("category", "generate"));
1656 }
1657 else
2b72d46f 1658 {
b96f6a77 1659 entry.push_back(Pair("category", "receive"));
2b72d46f 1660 }
1b4568cb
CL
1661 entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
1662 entry.push_back(Pair("vout", r.vout));
e3bc5698
JG
1663 if (fLong)
1664 WalletTxToJSON(wtx, entry);
9d365796 1665 #ifdef __APPLE__
1666 entry.push_back(Pair("size", (uint64_t)static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1667 #else
1668 entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1669 #endif
e3bc5698
JG
1670 ret.push_back(entry);
1671 }
1672 }
1673 }
1674}
1675
d014114d 1676void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret)
e3bc5698
JG
1677{
1678 bool fAllAccounts = (strAccount == string("*"));
1679
1680 if (fAllAccounts || acentry.strAccount == strAccount)
1681 {
38fc4b70 1682 UniValue entry(UniValue::VOBJ);
e3bc5698
JG
1683 entry.push_back(Pair("account", acentry.strAccount));
1684 entry.push_back(Pair("category", "move"));
d56e30ca 1685 entry.push_back(Pair("time", acentry.nTime));
e3bc5698
JG
1686 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1687 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1688 entry.push_back(Pair("comment", acentry.strComment));
1689 ret.push_back(entry);
1690 }
1691}
1692
d014114d 1693UniValue listtransactions(const UniValue& params, bool fHelp)
e3bc5698 1694{
b9fb692d 1695 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1696 return NullUniValue;
9d365796 1697
d7d5d23b 1698 if (fHelp || params.size() > 4)
e3bc5698 1699 throw runtime_error(
d7d5d23b 1700 "listtransactions ( \"account\" count from includeWatchonly)\n"
a6099ef3 1701 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
1702 "\nArguments:\n"
7b782f5b 1703 "1. \"account\" (string, optional) DEPRECATED. The account name. Should be \"*\".\n"
a6099ef3 1704 "2. count (numeric, optional, default=10) The number of transactions to return\n"
1705 "3. from (numeric, optional, default=0) The number of transactions to skip\n"
d7d5d23b 1706 "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
a6099ef3 1707 "\nResult:\n"
1708 "[\n"
1709 " {\n"
7b782f5b 1710 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n"
a6099ef3 1711 " It will be \"\" for the default account.\n"
1333d0d7 1712 " \"address\":\"" + strprintf("%s",komodo_chainname()) + "_address\", (string) The " + strprintf("%s",komodo_chainname()) + " address of the transaction. Not present for \n"
a6099ef3 1713 " move transactions (category = move).\n"
1714 " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
1715 " transaction between accounts, and not associated with an address,\n"
1716 " transaction id or block. 'send' and 'receive' transactions are \n"
1717 " associated with an address, transaction id and block details\n"
1333d0d7 1718 " \"amount\": x.xxx, (numeric) The amount in " + strprintf("%s",komodo_chainname()) + ". This is negative for the 'send' category, and for the\n"
a6099ef3 1719 " 'move' category for moves outbound. It is positive for the 'receive' category,\n"
1720 " and for the 'move' category for inbound funds.\n"
1b4568cb 1721 " \"vout\" : n, (numeric) the vout value\n"
1333d0d7 1722 " \"fee\": x.xxx, (numeric) The amount of the fee in " + strprintf("%s",komodo_chainname()) + ". This is negative and only available for the \n"
a6099ef3 1723 " 'send' category of transactions.\n"
1724 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
1725 " 'receive' category of transactions.\n"
1726 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
1727 " category of transactions.\n"
1728 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
1729 " category of transactions.\n"
b5ef85c7 1730 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
a6099ef3 1731 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1732 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
1733 " for 'send' and 'receive' category of transactions.\n"
1734 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1735 " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
1736 " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
1737 " negative amounts).\n"
f32cade8 1738 " \"size\": n, (numeric) Transaction size in bytes\n"
a6099ef3 1739 " }\n"
1740 "]\n"
1741
1742 "\nExamples:\n"
1743 "\nList the most recent 10 transactions in the systems\n"
1744 + HelpExampleCli("listtransactions", "") +
7b782f5b
LD
1745 "\nList transactions 100 to 120\n"
1746 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
a6099ef3 1747 "\nAs a json rpc call\n"
7b782f5b 1748 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
a6099ef3 1749 );
e3bc5698 1750
4401b2d7
EL
1751 LOCK2(cs_main, pwalletMain->cs_wallet);
1752
e3bc5698
JG
1753 string strAccount = "*";
1754 if (params.size() > 0)
1755 strAccount = params[0].get_str();
1756 int nCount = 10;
1757 if (params.size() > 1)
1758 nCount = params[1].get_int();
1759 int nFrom = 0;
1760 if (params.size() > 2)
1761 nFrom = params[2].get_int();
a3e192a3 1762 isminefilter filter = ISMINE_SPENDABLE;
a5c6c5d6
J
1763 if(params.size() > 3)
1764 if(params[3].get_bool())
a3e192a3 1765 filter = filter | ISMINE_WATCH_ONLY;
e3bc5698
JG
1766
1767 if (nCount < 0)
738835d7 1768 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
e3bc5698 1769 if (nFrom < 0)
738835d7 1770 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
e3bc5698 1771
38fc4b70 1772 UniValue ret(UniValue::VARR);
e3bc5698 1773
ddb709e9
LD
1774 std::list<CAccountingEntry> acentries;
1775 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
e3bc5698
JG
1776
1777 // iterate backwards until we have nCount items to return:
c3f95ef1 1778 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
e3bc5698
JG
1779 {
1780 CWalletTx *const pwtx = (*it).second.first;
1781 if (pwtx != 0)
d7d5d23b 1782 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
e3bc5698
JG
1783 CAccountingEntry *const pacentry = (*it).second.second;
1784 if (pacentry != 0)
1785 AcentryToJSON(*pacentry, strAccount, ret);
1786
1787 if ((int)ret.size() >= (nCount+nFrom)) break;
1788 }
1789 // ret is newest to oldest
1790
1791 if (nFrom > (int)ret.size())
1792 nFrom = ret.size();
1793 if ((nFrom + nCount) > (int)ret.size())
1794 nCount = ret.size() - nFrom;
ed21d5bd
JG
1795
1796 vector<UniValue> arrTmp = ret.getValues();
1797
1798 vector<UniValue>::iterator first = arrTmp.begin();
e3bc5698 1799 std::advance(first, nFrom);
ed21d5bd 1800 vector<UniValue>::iterator last = arrTmp.begin();
e3bc5698
JG
1801 std::advance(last, nFrom+nCount);
1802
ed21d5bd
JG
1803 if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
1804 if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
e3bc5698 1805
ed21d5bd 1806 std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
e3bc5698 1807
ed21d5bd 1808 ret.clear();
38fc4b70 1809 ret.setArray();
ed21d5bd 1810 ret.push_backV(arrTmp);
e3bc5698
JG
1811
1812 return ret;
1813}
1814
d014114d 1815UniValue listaccounts(const UniValue& params, bool fHelp)
e3bc5698 1816{
b9fb692d 1817 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1818 return NullUniValue;
9d365796 1819
83f3543f 1820 if (fHelp || params.size() > 2)
e3bc5698 1821 throw runtime_error(
83f3543f 1822 "listaccounts ( minconf includeWatchonly)\n"
7b782f5b 1823 "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
a6099ef3 1824 "\nArguments:\n"
5617267c 1825 "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
83f3543f 1826 "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
a6099ef3 1827 "\nResult:\n"
1828 "{ (json object where keys are account names, and values are numeric balances\n"
1829 " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
1830 " ...\n"
1831 "}\n"
1832 "\nExamples:\n"
1833 "\nList account balances where there at least 1 confirmation\n"
1834 + HelpExampleCli("listaccounts", "") +
1835 "\nList account balances including zero confirmation transactions\n"
1836 + HelpExampleCli("listaccounts", "0") +
1837 "\nList account balances for 6 or more confirmations\n"
1838 + HelpExampleCli("listaccounts", "6") +
1839 "\nAs json rpc call\n"
1840 + HelpExampleRpc("listaccounts", "6")
1841 );
e3bc5698 1842
4401b2d7
EL
1843 LOCK2(cs_main, pwalletMain->cs_wallet);
1844
e3bc5698
JG
1845 int nMinDepth = 1;
1846 if (params.size() > 0)
1847 nMinDepth = params[0].get_int();
a3e192a3 1848 isminefilter includeWatchonly = ISMINE_SPENDABLE;
a5c6c5d6
J
1849 if(params.size() > 1)
1850 if(params[1].get_bool())
a3e192a3 1851 includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
e3bc5698 1852
a372168e 1853 map<string, CAmount> mapAccountBalances;
61885513 1854 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
83f3543f 1855 if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
61885513 1856 mapAccountBalances[entry.second.name] = 0;
e3bc5698
JG
1857 }
1858
1859 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1860 {
1861 const CWalletTx& wtx = (*it).second;
a372168e 1862 CAmount nFee;
e3bc5698 1863 string strSentAccount;
1b4568cb
CL
1864 list<COutputEntry> listReceived;
1865 list<COutputEntry> listSent;
93a18a36
GA
1866 int nDepth = wtx.GetDepthInMainChain();
1867 if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
731b89b8 1868 continue;
83f3543f 1869 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
e3bc5698 1870 mapAccountBalances[strSentAccount] -= nFee;
1b4568cb
CL
1871 BOOST_FOREACH(const COutputEntry& s, listSent)
1872 mapAccountBalances[strSentAccount] -= s.amount;
93a18a36 1873 if (nDepth >= nMinDepth)
e3bc5698 1874 {
1b4568cb
CL
1875 BOOST_FOREACH(const COutputEntry& r, listReceived)
1876 if (pwalletMain->mapAddressBook.count(r.destination))
1877 mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
e3bc5698 1878 else
1b4568cb 1879 mapAccountBalances[""] += r.amount;
e3bc5698
JG
1880 }
1881 }
1882
1883 list<CAccountingEntry> acentries;
1884 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1885 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1886 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1887
38fc4b70 1888 UniValue ret(UniValue::VOBJ);
a372168e 1889 BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
e3bc5698
JG
1890 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1891 }
1892 return ret;
1893}
1894
d014114d 1895UniValue listsinceblock(const UniValue& params, bool fHelp)
e3bc5698 1896{
b9fb692d 1897 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1898 return NullUniValue;
9d365796 1899
e3bc5698
JG
1900 if (fHelp)
1901 throw runtime_error(
d7d5d23b 1902 "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
a6099ef3 1903 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
1904 "\nArguments:\n"
1905 "1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
1906 "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
d7d5d23b 1907 "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
a6099ef3 1908 "\nResult:\n"
1909 "{\n"
1910 " \"transactions\": [\n"
7b782f5b 1911 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
1333d0d7 1912 " \"address\":\"" + strprintf("%s",komodo_chainname()) + "_address\", (string) The " + strprintf("%s",komodo_chainname()) + " address of the transaction. Not present for move transactions (category = move).\n"
a6099ef3 1913 " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
1333d0d7 1914 " \"amount\": x.xxx, (numeric) The amount in " + strprintf("%s",komodo_chainname()) + ". This is negative for the 'send' category, and for the 'move' category for moves \n"
a6099ef3 1915 " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
1b4568cb 1916 " \"vout\" : n, (numeric) the vout value\n"
1333d0d7 1917 " \"fee\": x.xxx, (numeric) The amount of the fee in " + strprintf("%s",komodo_chainname()) + ". This is negative and only available for the 'send' category of transactions.\n"
a6099ef3 1918 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
1919 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1920 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1921 " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
b5ef85c7 1922 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
a6099ef3 1923 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
1924 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
1925 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1926 " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
1927 " ],\n"
1928 " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
1929 "}\n"
1930 "\nExamples:\n"
1931 + HelpExampleCli("listsinceblock", "")
1932 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1933 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1934 );
e3bc5698 1935
4401b2d7
EL
1936 LOCK2(cs_main, pwalletMain->cs_wallet);
1937
e3bc5698
JG
1938 CBlockIndex *pindex = NULL;
1939 int target_confirms = 1;
a3e192a3 1940 isminefilter filter = ISMINE_SPENDABLE;
e3bc5698
JG
1941
1942 if (params.size() > 0)
1943 {
4f152496 1944 uint256 blockId;
e3bc5698
JG
1945
1946 blockId.SetHex(params[0].get_str());
145d5be8 1947 BlockMap::iterator it = mapBlockIndex.find(blockId);
e4daecda
PW
1948 if (it != mapBlockIndex.end())
1949 pindex = it->second;
e3bc5698
JG
1950 }
1951
1952 if (params.size() > 1)
1953 {
1954 target_confirms = params[1].get_int();
1955
1956 if (target_confirms < 1)
738835d7 1957 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
e3bc5698
JG
1958 }
1959
a5c6c5d6
J
1960 if(params.size() > 2)
1961 if(params[2].get_bool())
a3e192a3 1962 filter = filter | ISMINE_WATCH_ONLY;
a5c6c5d6 1963
4c6d41b8 1964 int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
e3bc5698 1965
38fc4b70 1966 UniValue transactions(UniValue::VARR);
e3bc5698
JG
1967
1968 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1969 {
1970 CWalletTx tx = (*it).second;
1971
1972 if (depth == -1 || tx.GetDepthInMainChain() < depth)
d7d5d23b 1973 ListTransactions(tx, "*", 0, true, transactions, filter);
e3bc5698
JG
1974 }
1975
4c6d41b8 1976 CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
4f152496 1977 uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
e3bc5698 1978
38fc4b70 1979 UniValue ret(UniValue::VOBJ);
e3bc5698
JG
1980 ret.push_back(Pair("transactions", transactions));
1981 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1982
1983 return ret;
1984}
1985
d014114d 1986UniValue gettransaction(const UniValue& params, bool fHelp)
e3bc5698 1987{
b9fb692d 1988 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1989 return NullUniValue;
9d365796 1990
f87ba3df 1991 if (fHelp || params.size() < 1 || params.size() > 2)
e3bc5698 1992 throw runtime_error(
57e1716d 1993 "gettransaction \"txid\" ( includeWatchonly )\n"
a6099ef3 1994 "\nGet detailed information about in-wallet transaction <txid>\n"
1995 "\nArguments:\n"
1996 "1. \"txid\" (string, required) The transaction id\n"
f87ba3df 1997 "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
a6099ef3 1998 "\nResult:\n"
1999 "{\n"
1333d0d7 2000 " \"amount\" : x.xxx, (numeric) The transaction amount in " + strprintf("%s",komodo_chainname()) + "\n"
a6099ef3 2001 " \"confirmations\" : n, (numeric) The number of confirmations\n"
2002 " \"blockhash\" : \"hash\", (string) The block hash\n"
2003 " \"blockindex\" : xx, (numeric) The block index\n"
2004 " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
b5ef85c7 2005 " \"txid\" : \"transactionid\", (string) The transaction id.\n"
a6099ef3 2006 " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
2007 " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
2008 " \"details\" : [\n"
2009 " {\n"
7b782f5b 2010 " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
1333d0d7 2011 " \"address\" : \"" + strprintf("%s",komodo_chainname()) + "_address\", (string) The " + strprintf("%s",komodo_chainname()) + " address involved in the transaction\n"
a6099ef3 2012 " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
1333d0d7 2013 " \"amount\" : x.xxx (numeric) The amount in " + strprintf("%s",komodo_chainname()) + "\n"
1b4568cb 2014 " \"vout\" : n, (numeric) the vout value\n"
a6099ef3 2015 " }\n"
2016 " ,...\n"
3a1c20b7 2017 " ],\n"
f7cfb52d
S
2018 " \"vjoinsplit\" : [\n"
2019 " {\n"
2020 " \"anchor\" : \"treestateref\", (string) Merkle root of note commitment tree\n"
2021 " \"nullifiers\" : [ string, ... ] (string) Nullifiers of input notes\n"
2022 " \"commitments\" : [ string, ... ] (string) Note commitments for note outputs\n"
2023 " \"macs\" : [ string, ... ] (string) Message authentication tags\n"
2024 " \"vpub_old\" : x.xxx (numeric) The amount removed from the transparent value pool\n"
2025 " \"vpub_new\" : x.xxx, (numeric) The amount added to the transparent value pool\n"
2026 " }\n"
2027 " ,...\n"
2028 " ],\n"
3a1c20b7 2029 " \"hex\" : \"data\" (string) Raw data for transaction\n"
a6099ef3 2030 "}\n"
2031
ab45ddb5 2032 "\nExamples:\n"
a6099ef3 2033 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
57e1716d 2034 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
a6099ef3 2035 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
2036 );
e3bc5698 2037
4401b2d7
EL
2038 LOCK2(cs_main, pwalletMain->cs_wallet);
2039
e3bc5698
JG
2040 uint256 hash;
2041 hash.SetHex(params[0].get_str());
2042
a3e192a3 2043 isminefilter filter = ISMINE_SPENDABLE;
f87ba3df
J
2044 if(params.size() > 1)
2045 if(params[1].get_bool())
a3e192a3 2046 filter = filter | ISMINE_WATCH_ONLY;
f87ba3df 2047
38fc4b70 2048 UniValue entry(UniValue::VOBJ);
e3bc5698 2049 if (!pwalletMain->mapWallet.count(hash))
738835d7 2050 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
e3bc5698
JG
2051 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
2052
ccca27a7 2053 CAmount nCredit = wtx.GetCredit(filter);
a372168e
MF
2054 CAmount nDebit = wtx.GetDebit(filter);
2055 CAmount nNet = nCredit - nDebit;
2056 CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
e3bc5698
JG
2057
2058 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
80dda36a 2059 if (wtx.IsFromMe(filter))
e3bc5698
JG
2060 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
2061
2062 WalletTxToJSON(wtx, entry);
2063
38fc4b70 2064 UniValue details(UniValue::VARR);
f87ba3df 2065 ListTransactions(wtx, "*", 0, false, details, filter);
e3bc5698
JG
2066 entry.push_back(Pair("details", details));
2067
ae775b5b 2068 string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
3a1c20b7
WL
2069 entry.push_back(Pair("hex", strHex));
2070
e3bc5698
JG
2071 return entry;
2072}
2073
2074
d014114d 2075UniValue backupwallet(const UniValue& params, bool fHelp)
e3bc5698 2076{
b9fb692d 2077 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2078 return NullUniValue;
9d365796 2079
e3bc5698
JG
2080 if (fHelp || params.size() != 1)
2081 throw runtime_error(
a6099ef3 2082 "backupwallet \"destination\"\n"
9064d73b 2083 "\nSafely copies wallet.dat to destination filename\n"
a6099ef3 2084 "\nArguments:\n"
9064d73b
S
2085 "1. \"destination\" (string, required) The destination filename, saved in the directory set by -exportdir option.\n"
2086 "\nResult:\n"
2087 "\"path\" (string) The full path of the destination file\n"
a6099ef3 2088 "\nExamples:\n"
9064d73b
S
2089 + HelpExampleCli("backupwallet", "\"backupdata\"")
2090 + HelpExampleRpc("backupwallet", "\"backupdata\"")
a6099ef3 2091 );
e3bc5698 2092
4401b2d7
EL
2093 LOCK2(cs_main, pwalletMain->cs_wallet);
2094
9064d73b
S
2095 boost::filesystem::path exportdir;
2096 try {
2097 exportdir = GetExportDir();
2098 } catch (const std::runtime_error& e) {
2099 throw JSONRPCError(RPC_INTERNAL_ERROR, e.what());
2100 }
2101 if (exportdir.empty()) {
2102 throw JSONRPCError(RPC_WALLET_ERROR, "Cannot backup wallet until the -exportdir option has been set");
2103 }
2104 std::string unclean = params[0].get_str();
2105 std::string clean = SanitizeFilename(unclean);
2106 if (clean.compare(unclean) != 0) {
2107 throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Filename is invalid as only alphanumeric characters are allowed. Try '%s' instead.", clean));
2108 }
2109 boost::filesystem::path exportfilepath = exportdir / clean;
2110
2111 if (!BackupWallet(*pwalletMain, exportfilepath.string()))
ad525e9c 2112 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
e3bc5698 2113
9064d73b 2114 return exportfilepath.string();
e3bc5698
JG
2115}
2116
2117
d014114d 2118UniValue keypoolrefill(const UniValue& params, bool fHelp)
e3bc5698 2119{
b9fb692d 2120 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2121 return NullUniValue;
9d365796 2122
36bd46f1 2123 if (fHelp || params.size() > 1)
e3bc5698 2124 throw runtime_error(
a6099ef3 2125 "keypoolrefill ( newsize )\n"
2126 "\nFills the keypool."
2127 + HelpRequiringPassphrase() + "\n"
2128 "\nArguments\n"
2129 "1. newsize (numeric, optional, default=100) The new keypool size\n"
2130 "\nExamples:\n"
2131 + HelpExampleCli("keypoolrefill", "")
2132 + HelpExampleRpc("keypoolrefill", "")
2133 );
e3bc5698 2134
4401b2d7
EL
2135 LOCK2(cs_main, pwalletMain->cs_wallet);
2136
f914c7a1
PK
2137 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
2138 unsigned int kpSize = 0;
36bd46f1
JG
2139 if (params.size() > 0) {
2140 if (params[0].get_int() < 0)
f914c7a1
PK
2141 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
2142 kpSize = (unsigned int)params[0].get_int();
36bd46f1
JG
2143 }
2144
e3bc5698 2145 EnsureWalletIsUnlocked();
36bd46f1 2146 pwalletMain->TopUpKeyPool(kpSize);
e3bc5698 2147
36bd46f1 2148 if (pwalletMain->GetKeyPoolSize() < kpSize)
738835d7 2149 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
e3bc5698 2150
ed21d5bd 2151 return NullUniValue;
e3bc5698
JG
2152}
2153
2154
92f2c1fe 2155static void LockWallet(CWallet* pWallet)
e3bc5698 2156{
92f2c1fe
GA
2157 LOCK(cs_nWalletUnlockTime);
2158 nWalletUnlockTime = 0;
2159 pWallet->Lock();
e3bc5698
JG
2160}
2161
d014114d 2162UniValue walletpassphrase(const UniValue& params, bool fHelp)
e3bc5698 2163{
b9fb692d 2164 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2165 return NullUniValue;
9d365796 2166
e3bc5698
JG
2167 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
2168 throw runtime_error(
a6099ef3 2169 "walletpassphrase \"passphrase\" timeout\n"
2170 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
1333d0d7 2171 "This is needed prior to performing transactions related to private keys such as sending " + strprintf("%s",komodo_chainname()) + "\n"
a6099ef3 2172 "\nArguments:\n"
2173 "1. \"passphrase\" (string, required) The wallet passphrase\n"
2174 "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
6c0db81c
WL
2175 "\nNote:\n"
2176 "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
2177 "time that overrides the old one.\n"
a6099ef3 2178 "\nExamples:\n"
2179 "\nunlock the wallet for 60 seconds\n"
2180 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
2181 "\nLock the wallet again (before 60 seconds)\n"
2182 + HelpExampleCli("walletlock", "") +
2183 "\nAs json rpc call\n"
2184 + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
2185 );
2186
4401b2d7
EL
2187 LOCK2(cs_main, pwalletMain->cs_wallet);
2188
e3bc5698
JG
2189 if (fHelp)
2190 return true;
2191 if (!pwalletMain->IsCrypted())
738835d7 2192 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
e3bc5698 2193
e3bc5698
JG
2194 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
2195 SecureString strWalletPass;
2196 strWalletPass.reserve(100);
2197 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2198 // Alternately, find a way to make params[0] mlock()'d to begin with.
2199 strWalletPass = params[0].get_str().c_str();
2200
2201 if (strWalletPass.length() > 0)
2202 {
2203 if (!pwalletMain->Unlock(strWalletPass))
738835d7 2204 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
e3bc5698
JG
2205 }
2206 else
2207 throw runtime_error(
2208 "walletpassphrase <passphrase> <timeout>\n"
2209 "Stores the wallet decryption key in memory for <timeout> seconds.");
2210
6e263a5f 2211 // No need to check return values, because the wallet was unlocked above
1a62587e 2212 pwalletMain->UpdateNullifierNoteMap();
92f2c1fe
GA
2213 pwalletMain->TopUpKeyPool();
2214
51ed9ec9 2215 int64_t nSleepTime = params[1].get_int64();
92f2c1fe
GA
2216 LOCK(cs_nWalletUnlockTime);
2217 nWalletUnlockTime = GetTime() + nSleepTime;
2218 RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
e3bc5698 2219
ed21d5bd 2220 return NullUniValue;
e3bc5698
JG
2221}
2222
2223
d014114d 2224UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
e3bc5698 2225{
b9fb692d 2226 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2227 return NullUniValue;
9d365796 2228
e3bc5698
JG
2229 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
2230 throw runtime_error(
a6099ef3 2231 "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
2232 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
2233 "\nArguments:\n"
2234 "1. \"oldpassphrase\" (string) The current passphrase\n"
2235 "2. \"newpassphrase\" (string) The new passphrase\n"
2236 "\nExamples:\n"
2237 + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
2238 + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
2239 );
2240
4401b2d7
EL
2241 LOCK2(cs_main, pwalletMain->cs_wallet);
2242
e3bc5698
JG
2243 if (fHelp)
2244 return true;
2245 if (!pwalletMain->IsCrypted())
738835d7 2246 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
e3bc5698
JG
2247
2248 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
2249 // Alternately, find a way to make params[0] mlock()'d to begin with.
2250 SecureString strOldWalletPass;
2251 strOldWalletPass.reserve(100);
2252 strOldWalletPass = params[0].get_str().c_str();
2253
2254 SecureString strNewWalletPass;
2255 strNewWalletPass.reserve(100);
2256 strNewWalletPass = params[1].get_str().c_str();
2257
2258 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
2259 throw runtime_error(
2260 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
2261 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
2262
2263 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
738835d7 2264 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
e3bc5698 2265
ed21d5bd 2266 return NullUniValue;
e3bc5698
JG
2267}
2268
2269
d014114d 2270UniValue walletlock(const UniValue& params, bool fHelp)
e3bc5698 2271{
b9fb692d 2272 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2273 return NullUniValue;
9d365796 2274
e3bc5698
JG
2275 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
2276 throw runtime_error(
2277 "walletlock\n"
a6099ef3 2278 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
e3bc5698 2279 "After calling this method, you will need to call walletpassphrase again\n"
a6099ef3 2280 "before being able to call any methods which require the wallet to be unlocked.\n"
2281 "\nExamples:\n"
2282 "\nSet the passphrase for 2 minutes to perform a transaction\n"
2283 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
2284 "\nPerform a send (requires passphrase set)\n"
1333d0d7 2285 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 1.0") +
a6099ef3 2286 "\nClear the passphrase since we are done before 2 minutes is up\n"
2287 + HelpExampleCli("walletlock", "") +
2288 "\nAs json rpc call\n"
2289 + HelpExampleRpc("walletlock", "")
2290 );
2291
4401b2d7
EL
2292 LOCK2(cs_main, pwalletMain->cs_wallet);
2293
e3bc5698
JG
2294 if (fHelp)
2295 return true;
2296 if (!pwalletMain->IsCrypted())
738835d7 2297 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
e3bc5698
JG
2298
2299 {
2300 LOCK(cs_nWalletUnlockTime);
2301 pwalletMain->Lock();
2302 nWalletUnlockTime = 0;
2303 }
2304
ed21d5bd 2305 return NullUniValue;
e3bc5698
JG
2306}
2307
2308
d014114d 2309UniValue encryptwallet(const UniValue& params, bool fHelp)
e3bc5698 2310{
b9fb692d 2311 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2312 return NullUniValue;
62c0aa9e 2313
b8eb3775 2314 auto fEnableWalletEncryption = fExperimentalMode && GetBoolArg("-developerencryptwallet", false);
62c0aa9e
JG
2315
2316 std::string strWalletEncryptionDisabledMsg = "";
2317 if (!fEnableWalletEncryption) {
1532cb75 2318 strWalletEncryptionDisabledMsg = "\nWARNING: Wallet encryption is DISABLED. This call always fails.\n";
62c0aa9e
JG
2319 }
2320
e3bc5698
JG
2321 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
2322 throw runtime_error(
a6099ef3 2323 "encryptwallet \"passphrase\"\n"
62c0aa9e 2324 + strWalletEncryptionDisabledMsg +
a6099ef3 2325 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
2326 "After this, any calls that interact with private keys such as sending or signing \n"
2327 "will require the passphrase to be set prior the making these calls.\n"
2328 "Use the walletpassphrase call for this, and then walletlock call.\n"
2329 "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
2330 "Note that this will shutdown the server.\n"
2331 "\nArguments:\n"
2332 "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
2333 "\nExamples:\n"
2334 "\nEncrypt you wallet\n"
2335 + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
1333d0d7 2336 "\nNow set the passphrase to use the wallet, such as for signing or sending " + strprintf("%s",komodo_chainname()) + "\n"
a6099ef3 2337 + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
2338 "\nNow we can so something like sign\n"
1333d0d7 2339 + HelpExampleCli("signmessage", "\"" + strprintf("%s",komodo_chainname()) + "_address\" \"test message\"") +
a6099ef3 2340 "\nNow lock the wallet again by removing the passphrase\n"
2341 + HelpExampleCli("walletlock", "") +
2342 "\nAs a json rpc call\n"
2343 + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
2344 );
2345
4401b2d7
EL
2346 LOCK2(cs_main, pwalletMain->cs_wallet);
2347
e3bc5698
JG
2348 if (fHelp)
2349 return true;
62c0aa9e 2350 if (!fEnableWalletEncryption) {
1532cb75 2351 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet encryption is disabled.");
62c0aa9e 2352 }
e3bc5698 2353 if (pwalletMain->IsCrypted())
738835d7 2354 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
e3bc5698
JG
2355
2356 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2357 // Alternately, find a way to make params[0] mlock()'d to begin with.
2358 SecureString strWalletPass;
2359 strWalletPass.reserve(100);
2360 strWalletPass = params[0].get_str().c_str();
2361
2362 if (strWalletPass.length() < 1)
2363 throw runtime_error(
2364 "encryptwallet <passphrase>\n"
2365 "Encrypts the wallet with <passphrase>.");
2366
2367 if (!pwalletMain->EncryptWallet(strWalletPass))
738835d7 2368 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
e3bc5698
JG
2369
2370 // BDB seems to have a bad habit of writing old data into
2371 // slack space in .dat files; that is bad if the old data is
331544bc 2372 // unencrypted private keys. So:
e3bc5698 2373 StartShutdown();
2e500f50 2374 return "wallet encrypted; Komodo server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
e3bc5698
JG
2375}
2376
d014114d 2377UniValue lockunspent(const UniValue& params, bool fHelp)
fdbb537d 2378{
b9fb692d 2379 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2380 return NullUniValue;
9d365796 2381
fdbb537d
JG
2382 if (fHelp || params.size() < 1 || params.size() > 2)
2383 throw runtime_error(
a6099ef3 2384 "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
2385 "\nUpdates list of temporarily unspendable outputs.\n"
90fd8737 2386 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
1333d0d7 2387 "A locked transaction output will not be chosen by automatic coin selection, when spending " + strprintf("%s",komodo_chainname()) + ".\n"
a6099ef3 2388 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2389 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
2390 "Also see the listunspent call\n"
2391 "\nArguments:\n"
2392 "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
2393 "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
2394 " [ (json array of json objects)\n"
2395 " {\n"
2396 " \"txid\":\"id\", (string) The transaction id\n"
2397 " \"vout\": n (numeric) The output number\n"
2398 " }\n"
2399 " ,...\n"
2400 " ]\n"
2401
2402 "\nResult:\n"
2403 "true|false (boolean) Whether the command was successful or not\n"
2404
2405 "\nExamples:\n"
2406 "\nList the unspent transactions\n"
2407 + HelpExampleCli("listunspent", "") +
2408 "\nLock an unspent transaction\n"
2409 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2410 "\nList the locked transactions\n"
2411 + HelpExampleCli("listlockunspent", "") +
2412 "\nUnlock the transaction again\n"
2413 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2414 "\nAs a json rpc call\n"
2415 + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
2416 );
fdbb537d 2417
4401b2d7
EL
2418 LOCK2(cs_main, pwalletMain->cs_wallet);
2419
fdbb537d 2420 if (params.size() == 1)
ed21d5bd 2421 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL));
fdbb537d 2422 else
ed21d5bd 2423 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
fdbb537d
JG
2424
2425 bool fUnlock = params[0].get_bool();
2426
2427 if (params.size() == 1) {
2428 if (fUnlock)
2429 pwalletMain->UnlockAllCoins();
2430 return true;
2431 }
2432
851f58f9 2433 UniValue outputs = params[1].get_array();
cc71666a 2434 for (size_t idx = 0; idx < outputs.size(); idx++) {
ed21d5bd
JG
2435 const UniValue& output = outputs[idx];
2436 if (!output.isObject())
15117692 2437 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
d014114d 2438 const UniValue& o = output.get_obj();
fdbb537d 2439
ed21d5bd 2440 RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM));
fdbb537d
JG
2441
2442 string txid = find_value(o, "txid").get_str();
2443 if (!IsHex(txid))
15117692 2444 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
fdbb537d
JG
2445
2446 int nOutput = find_value(o, "vout").get_int();
2447 if (nOutput < 0)
15117692 2448 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
fdbb537d 2449
34cdc411 2450 COutPoint outpt(uint256S(txid), nOutput);
fdbb537d
JG
2451
2452 if (fUnlock)
2453 pwalletMain->UnlockCoin(outpt);
2454 else
2455 pwalletMain->LockCoin(outpt);
2456 }
2457
2458 return true;
2459}
2460
d014114d 2461UniValue listlockunspent(const UniValue& params, bool fHelp)
fdbb537d 2462{
b9fb692d 2463 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2464 return NullUniValue;
9d365796 2465
fdbb537d
JG
2466 if (fHelp || params.size() > 0)
2467 throw runtime_error(
2468 "listlockunspent\n"
a6099ef3 2469 "\nReturns list of temporarily unspendable outputs.\n"
2470 "See the lockunspent call to lock and unlock transactions for spending.\n"
2471 "\nResult:\n"
2472 "[\n"
2473 " {\n"
2474 " \"txid\" : \"transactionid\", (string) The transaction id locked\n"
2475 " \"vout\" : n (numeric) The vout value\n"
2476 " }\n"
2477 " ,...\n"
2478 "]\n"
2479 "\nExamples:\n"
2480 "\nList the unspent transactions\n"
2481 + HelpExampleCli("listunspent", "") +
2482 "\nLock an unspent transaction\n"
2483 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2484 "\nList the locked transactions\n"
2485 + HelpExampleCli("listlockunspent", "") +
2486 "\nUnlock the transaction again\n"
2487 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2488 "\nAs a json rpc call\n"
2489 + HelpExampleRpc("listlockunspent", "")
2490 );
fdbb537d 2491
4401b2d7
EL
2492 LOCK2(cs_main, pwalletMain->cs_wallet);
2493
fdbb537d
JG
2494 vector<COutPoint> vOutpts;
2495 pwalletMain->ListLockedCoins(vOutpts);
2496
38fc4b70 2497 UniValue ret(UniValue::VARR);
fdbb537d
JG
2498
2499 BOOST_FOREACH(COutPoint &outpt, vOutpts) {
38fc4b70 2500 UniValue o(UniValue::VOBJ);
fdbb537d
JG
2501
2502 o.push_back(Pair("txid", outpt.hash.GetHex()));
2503 o.push_back(Pair("vout", (int)outpt.n));
2504 ret.push_back(o);
2505 }
2506
2507 return ret;
2508}
2509
d014114d 2510UniValue settxfee(const UniValue& params, bool fHelp)
a943bde6 2511{
b9fb692d 2512 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2513 return NullUniValue;
9d365796 2514
a943bde6
WL
2515 if (fHelp || params.size() < 1 || params.size() > 1)
2516 throw runtime_error(
2517 "settxfee amount\n"
6943cb9b 2518 "\nSet the transaction fee per kB.\n"
a943bde6 2519 "\nArguments:\n"
1333d0d7 2520 "1. amount (numeric, required) The transaction fee in " + strprintf("%s",komodo_chainname()) + "/kB rounded to the nearest 0.00000001\n"
a943bde6
WL
2521 "\nResult\n"
2522 "true|false (boolean) Returns true if successful\n"
2523 "\nExamples:\n"
2524 + HelpExampleCli("settxfee", "0.00001")
2525 + HelpExampleRpc("settxfee", "0.00001")
2526 );
2527
4401b2d7
EL
2528 LOCK2(cs_main, pwalletMain->cs_wallet);
2529
a943bde6 2530 // Amount
e76a3849 2531 CAmount nAmount = AmountFromValue(params[0]);
a943bde6 2532
c6cb21d1 2533 payTxFee = CFeeRate(nAmount, 1000);
a943bde6
WL
2534 return true;
2535}
2536
d014114d 2537UniValue getwalletinfo(const UniValue& params, bool fHelp)
a00ebb51 2538{
b9fb692d 2539 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2540 return NullUniValue;
9d365796 2541
a00ebb51
DN
2542 if (fHelp || params.size() != 0)
2543 throw runtime_error(
2544 "getwalletinfo\n"
2545 "Returns an object containing various wallet state info.\n"
2546 "\nResult:\n"
2547 "{\n"
2548 " \"walletversion\": xxxxx, (numeric) the wallet version\n"
1333d0d7 2549 " \"balance\": xxxxxxx, (numeric) the total confirmed balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
2550 " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
2551 " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
a00ebb51
DN
2552 " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
2553 " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
2554 " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
2555 " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
f37f614e 2556 " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in KMD/KB\n"
a00ebb51
DN
2557 "}\n"
2558 "\nExamples:\n"
2559 + HelpExampleCli("getwalletinfo", "")
2560 + HelpExampleRpc("getwalletinfo", "")
2561 );
2562
4401b2d7
EL
2563 LOCK2(cs_main, pwalletMain->cs_wallet);
2564
38fc4b70 2565 UniValue obj(UniValue::VOBJ);
a00ebb51
DN
2566 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
2567 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
8024d67d
GM
2568 obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
2569 obj.push_back(Pair("immature_balance", ValueFromAmount(pwalletMain->GetImmatureBalance())));
a00ebb51 2570 obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size()));
d56e30ca 2571 obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
a00ebb51
DN
2572 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
2573 if (pwalletMain->IsCrypted())
d56e30ca 2574 obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
6699b425 2575 obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
a00ebb51
DN
2576 return obj;
2577}
0f5954c4 2578
d014114d 2579UniValue resendwallettransactions(const UniValue& params, bool fHelp)
0f5954c4 2580{
b9fb692d 2581 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2582 return NullUniValue;
9d365796 2583
0f5954c4
GA
2584 if (fHelp || params.size() != 0)
2585 throw runtime_error(
2586 "resendwallettransactions\n"
2587 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
2588 "Intended only for testing; the wallet code periodically re-broadcasts\n"
2589 "automatically.\n"
2590 "Returns array of transaction ids that were re-broadcast.\n"
2591 );
2592
2593 LOCK2(cs_main, pwalletMain->cs_wallet);
2594
2595 std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
38fc4b70 2596 UniValue result(UniValue::VARR);
0f5954c4
GA
2597 BOOST_FOREACH(const uint256& txid, txids)
2598 {
2599 result.push_back(txid.ToString());
2600 }
2601 return result;
2602}
0b9dc9c8 2603
d014114d 2604UniValue listunspent(const UniValue& params, bool fHelp)
0b9dc9c8
JS
2605{
2606 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2607 return NullUniValue;
9d365796 2608
0b9dc9c8 2609 if (fHelp || params.size() > 3)
ea9e82df
JS
2610 throw runtime_error(
2611 "listunspent ( minconf maxconf [\"address\",...] )\n"
2612 "\nReturns array of unspent transaction outputs\n"
2613 "with between minconf and maxconf (inclusive) confirmations.\n"
2614 "Optionally filter to only include txouts paid to specified addresses.\n"
2615 "Results are an array of Objects, each of which has:\n"
2616 "{txid, vout, scriptPubKey, amount, confirmations}\n"
2617 "\nArguments:\n"
2618 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
2619 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
1333d0d7 2620 "3. \"addresses\" (string) A json array of " + strprintf("%s",komodo_chainname()) + " addresses to filter\n"
ea9e82df 2621 " [\n"
1333d0d7 2622 " \"address\" (string) " + strprintf("%s",komodo_chainname()) + " address\n"
ea9e82df
JS
2623 " ,...\n"
2624 " ]\n"
2625 "\nResult\n"
2626 "[ (array of json object)\n"
2627 " {\n"
2628 " \"txid\" : \"txid\", (string) the transaction id \n"
2629 " \"vout\" : n, (numeric) the vout value\n"
d77a0ac4 2630 " \"generated\" : true|false (boolean) true if txout is a coinbase transaction output\n"
1333d0d7 2631 " \"address\" : \"address\", (string) the " + strprintf("%s",komodo_chainname()) + " address\n"
ea9e82df
JS
2632 " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
2633 " \"scriptPubKey\" : \"key\", (string) the script key\n"
1333d0d7 2634 " \"amount\" : x.xxx, (numeric) the transaction amount in " + strprintf("%s",komodo_chainname()) + "\n"
ea9e82df
JS
2635 " \"confirmations\" : n (numeric) The number of confirmations\n"
2636 " }\n"
2637 " ,...\n"
2638 "]\n"
2639
2640 "\nExamples\n"
2641 + HelpExampleCli("listunspent", "")
1333d0d7 2642 + HelpExampleCli("listunspent", "6 9999999 \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"")
2643 + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"")
ea9e82df
JS
2644 );
2645
9756b7bd 2646 RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
ea9e82df 2647
0b9dc9c8
JS
2648 int nMinDepth = 1;
2649 if (params.size() > 0)
ea9e82df
JS
2650 nMinDepth = params[0].get_int();
2651
0b9dc9c8
JS
2652 int nMaxDepth = 9999999;
2653 if (params.size() > 1)
ea9e82df
JS
2654 nMaxDepth = params[1].get_int();
2655
0b9dc9c8
JS
2656 set<CBitcoinAddress> setAddress;
2657 if (params.size() > 2) {
851f58f9 2658 UniValue inputs = params[2].get_array();
cc71666a 2659 for (size_t idx = 0; idx < inputs.size(); idx++) {
d014114d 2660 const UniValue& input = inputs[idx];
0b9dc9c8
JS
2661 CBitcoinAddress address(input.get_str());
2662 if (!address.IsValid())
1333d0d7 2663 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid " + strprintf("%s",komodo_chainname()) + " address: ")+input.get_str());
0b9dc9c8 2664 if (setAddress.count(address))
ea9e82df
JS
2665 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
2666 setAddress.insert(address);
0b9dc9c8
JS
2667 }
2668 }
ea9e82df 2669
38fc4b70 2670 UniValue results(UniValue::VARR);
0b9dc9c8
JS
2671 vector<COutput> vecOutputs;
2672 assert(pwalletMain != NULL);
2673 LOCK2(cs_main, pwalletMain->cs_wallet);
219953ce 2674 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
0b9dc9c8
JS
2675 BOOST_FOREACH(const COutput& out, vecOutputs) {
2676 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
ea9e82df
JS
2677 continue;
2678
0b9dc9c8
JS
2679 if (setAddress.size()) {
2680 CTxDestination address;
2681 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
ea9e82df
JS
2682 continue;
2683
0b9dc9c8 2684 if (!setAddress.count(address))
ea9e82df 2685 continue;
0b9dc9c8 2686 }
ea9e82df 2687
0b9dc9c8
JS
2688 CAmount nValue = out.tx->vout[out.i].nValue;
2689 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
38fc4b70 2690 UniValue entry(UniValue::VOBJ);
805344dc 2691 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
0b9dc9c8 2692 entry.push_back(Pair("vout", out.i));
d77a0ac4 2693 entry.push_back(Pair("generated", out.tx->IsCoinBase()));
0b9dc9c8
JS
2694 CTxDestination address;
2695 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
2696 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
2697 if (pwalletMain->mapAddressBook.count(address))
ea9e82df 2698 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
0b9dc9c8
JS
2699 }
2700 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
2701 if (pk.IsPayToScriptHash()) {
2702 CTxDestination address;
2703 if (ExtractDestination(pk, address)) {
8b08d953 2704 const CScriptID& hash = boost::get<CScriptID>(address);
0b9dc9c8
JS
2705 CScript redeemScript;
2706 if (pwalletMain->GetCScript(hash, redeemScript))
ea9e82df 2707 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
0b9dc9c8
JS
2708 }
2709 }
2710 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
fdbf481f 2711 if ( out.tx->nLockTime != 0 )
e42867d1 2712 {
fdbf481f 2713 BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
0fec0cc4 2714 CBlockIndex *tipindex,*pindex = it->second;
e7876b36 2715 uint64_t interest; uint32_t locktime; int32_t txheight;
86131275 2716 if ( pindex != 0 && (tipindex= chainActive.LastTip()) != 0 )
fdbf481f 2717 {
ae3f3fea 2718 interest = komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight);
2719 //interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime);
fdbf481f 2720 entry.push_back(Pair("interest",ValueFromAmount(interest)));
e7876b36 2721 }
86131275 2722 //fprintf(stderr,"nValue %.8f pindex.%p tipindex.%p locktime.%u txheight.%d pindexht.%d\n",(double)nValue/COIN,pindex,chainActive.LastTip(),locktime,txheight,pindex->nHeight);
e42867d1 2723 }
0b9dc9c8
JS
2724 entry.push_back(Pair("confirmations",out.nDepth));
2725 entry.push_back(Pair("spendable", out.fSpendable));
2726 results.push_back(entry);
2727 }
ea9e82df 2728
0b9dc9c8 2729 return results;
c9fd9078 2730}
730790f7 2731
da16b12e 2732uint64_t komodo_interestsum()
09e3cf94 2733{
6fd79871 2734#ifdef ENABLE_WALLET
7714b7f1 2735 if ( GetBoolArg("-disablewallet", false) == 0 )
09e3cf94 2736 {
7714b7f1 2737 uint64_t interest,sum = 0; int32_t txheight; uint32_t locktime;
2738 vector<COutput> vecOutputs;
2739 assert(pwalletMain != NULL);
2740 LOCK2(cs_main, pwalletMain->cs_wallet);
2741 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2742 BOOST_FOREACH(const COutput& out,vecOutputs)
09e3cf94 2743 {
7714b7f1 2744 CAmount nValue = out.tx->vout[out.i].nValue;
2745 if ( out.tx->nLockTime != 0 && out.fSpendable != 0 )
09e3cf94 2746 {
7714b7f1 2747 BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
2748 CBlockIndex *tipindex,*pindex = it->second;
86131275 2749 if ( pindex != 0 && (tipindex= chainActive.LastTip()) != 0 )
7714b7f1 2750 {
2751 interest = komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight);
2752 //interest = komodo_interest(pindex->nHeight,nValue,out.tx->nLockTime,tipindex->nTime);
2753 sum += interest;
2754 }
09e3cf94 2755 }
2756 }
7714b7f1 2757 KOMODO_INTERESTSUM = sum;
2758 KOMODO_WALLETBALANCE = pwalletMain->GetBalance();
2759 return(sum);
09e3cf94 2760 }
6fd79871 2761#endif
7714b7f1 2762 return(0);
09e3cf94 2763}
2764
3d8013a0
MC
2765UniValue fundrawtransaction(const UniValue& params, bool fHelp)
2766{
2767 if (!EnsureWalletIsAvailable(fHelp))
2768 return NullUniValue;
2769
2770 if (fHelp || params.size() != 1)
2771 throw runtime_error(
2772 "fundrawtransaction \"hexstring\"\n"
2773 "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
2774 "This will not modify existing inputs, and will add one change output to the outputs.\n"
2775 "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
2776 "The inputs added will not be signed, use signrawtransaction for that.\n"
2777 "\nArguments:\n"
2778 "1. \"hexstring\" (string, required) The hex string of the raw transaction\n"
2779 "\nResult:\n"
2780 "{\n"
2781 " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
2782 " \"fee\": n, (numeric) The fee added to the transaction\n"
2783 " \"changepos\": n (numeric) The position of the added change output, or -1\n"
2784 "}\n"
2785 "\"hex\" \n"
2786 "\nExamples:\n"
2787 "\nCreate a transaction with no inputs\n"
2788 + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
2789 "\nAdd sufficient unsigned inputs to meet the output value\n"
2790 + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
2791 "\nSign the transaction\n"
2792 + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
2793 "\nSend the transaction\n"
2794 + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
2795 );
2796
2797 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
2798
2799 // parse hex string from parameter
2800 CTransaction origTx;
2801 if (!DecodeHexTx(origTx, params[0].get_str()))
2802 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2803
2804 CMutableTransaction tx(origTx);
2805 CAmount nFee;
2806 string strFailReason;
2807 int nChangePos = -1;
2808 if(!pwalletMain->FundTransaction(tx, nFee, nChangePos, strFailReason))
2809 throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
2810
2811 UniValue result(UniValue::VOBJ);
2812 result.push_back(Pair("hex", EncodeHexTx(tx)));
2813 result.push_back(Pair("changepos", nChangePos));
2814 result.push_back(Pair("fee", ValueFromAmount(nFee)));
2815
2816 return result;
2817}
2818
0d37ae3a 2819UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp)
1737627c
SB
2820{
2821 if (fHelp) {
2822 throw runtime_error(
2823 "zcsamplejoinsplit\n"
2824 "\n"
2825 "Perform a joinsplit and return the JSDescription.\n"
2826 );
2827 }
2828
2829 LOCK(cs_main);
2830
2831 uint256 pubKeyHash;
2832 uint256 anchor = ZCIncrementalMerkleTree().root();
2833 JSDescription samplejoinsplit(*pzcashParams,
2834 pubKeyHash,
2835 anchor,
2836 {JSInput(), JSInput()},
2837 {JSOutput(), JSOutput()},
2838 0,
2839 0);
2840
2841 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2842 ss << samplejoinsplit;
2843
2844 return HexStr(ss.begin(), ss.end());
2845}
2846
0d37ae3a 2847UniValue zc_benchmark(const UniValue& params, bool fHelp)
6962bb3d
TH
2848{
2849 if (!EnsureWalletIsAvailable(fHelp)) {
0d37ae3a 2850 return NullUniValue;
6962bb3d
TH
2851 }
2852
2853 if (fHelp || params.size() < 2) {
2854 throw runtime_error(
2855 "zcbenchmark benchmarktype samplecount\n"
2856 "\n"
2857 "Runs a benchmark of the selected type samplecount times,\n"
2858 "returning the running times of each sample.\n"
2859 "\n"
2860 "Output: [\n"
2861 " {\n"
2862 " \"runningtime\": runningtime\n"
2863 " },\n"
2864 " {\n"
2865 " \"runningtime\": runningtime\n"
2866 " }\n"
2867 " ...\n"
2868 "]\n"
2869 );
2870 }
2871
2872 LOCK(cs_main);
2873
2874 std::string benchmarktype = params[0].get_str();
2875 int samplecount = params[1].get_int();
2876
2877 if (samplecount <= 0) {
2878 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount");
2879 }
2880
2881 std::vector<double> sample_times;
2882
1737627c 2883 JSDescription samplejoinsplit;
2fbbde59
SB
2884
2885 if (benchmarktype == "verifyjoinsplit") {
1737627c
SB
2886 CDataStream ss(ParseHexV(params[2].get_str(), "js"), SER_NETWORK, PROTOCOL_VERSION);
2887 ss >> samplejoinsplit;
2fbbde59
SB
2888 }
2889
6962bb3d
TH
2890 for (int i = 0; i < samplecount; i++) {
2891 if (benchmarktype == "sleep") {
2892 sample_times.push_back(benchmark_sleep());
2893 } else if (benchmarktype == "parameterloading") {
2894 sample_times.push_back(benchmark_parameter_loading());
2895 } else if (benchmarktype == "createjoinsplit") {
4082dcb1
JG
2896 if (params.size() < 3) {
2897 sample_times.push_back(benchmark_create_joinsplit());
2898 } else {
2899 int nThreads = params[2].get_int();
2900 std::vector<double> vals = benchmark_create_joinsplit_threaded(nThreads);
2901 // Divide by nThreads^2 to get average seconds per JoinSplit because
2902 // we are running one JoinSplit per thread.
2903 sample_times.push_back(std::accumulate(vals.begin(), vals.end(), 0.0) / (nThreads*nThreads));
2904 }
6962bb3d 2905 } else if (benchmarktype == "verifyjoinsplit") {
1737627c 2906 sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
2cc0a252 2907#ifdef ENABLE_MINING
bf8def97 2908 } else if (benchmarktype == "solveequihash") {
f7478de6 2909 if (params.size() < 3) {
9e52ca32 2910 sample_times.push_back(benchmark_solve_equihash());
f7478de6
JG
2911 } else {
2912 int nThreads = params[2].get_int();
9e52ca32
JG
2913 std::vector<double> vals = benchmark_solve_equihash_threaded(nThreads);
2914 sample_times.insert(sample_times.end(), vals.begin(), vals.end());
f7478de6 2915 }
2cc0a252 2916#endif
bf8def97 2917 } else if (benchmarktype == "verifyequihash") {
a1cd1a27 2918 sample_times.push_back(benchmark_verify_equihash());
f5edc37f 2919 } else if (benchmarktype == "validatelargetx") {
818b94f9
JG
2920 // Number of inputs in the spending transaction that we will simulate
2921 int nInputs = 555;
2922 if (params.size() >= 3) {
2923 nInputs = params[2].get_int();
2924 }
2925 sample_times.push_back(benchmark_large_tx(nInputs));
0fbab55b 2926 } else if (benchmarktype == "trydecryptnotes") {
88b7f3c2
JG
2927 int nAddrs = params[2].get_int();
2928 sample_times.push_back(benchmark_try_decrypt_notes(nAddrs));
0bb3d40f
JG
2929 } else if (benchmarktype == "incnotewitnesses") {
2930 int nTxs = params[2].get_int();
2931 sample_times.push_back(benchmark_increment_note_witnesses(nTxs));
c66c731a
JG
2932 } else if (benchmarktype == "connectblockslow") {
2933 if (Params().NetworkIDString() != "regtest") {
2934 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2935 }
2936 sample_times.push_back(benchmark_connectblock_slow());
a76174b7
JG
2937 } else if (benchmarktype == "sendtoaddress") {
2938 if (Params().NetworkIDString() != "regtest") {
2939 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2940 }
2941 auto amount = AmountFromValue(params[2]);
2942 sample_times.push_back(benchmark_sendtoaddress(amount));
2e8aefdc
AG
2943 } else if (benchmarktype == "loadwallet") {
2944 if (Params().NetworkIDString() != "regtest") {
2945 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2946 }
2947 sample_times.push_back(benchmark_loadwallet());
99dd50c3
JG
2948 } else if (benchmarktype == "listunspent") {
2949 sample_times.push_back(benchmark_listunspent());
6962bb3d
TH
2950 } else {
2951 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
2952 }
2953 }
2954
0d37ae3a 2955 UniValue results(UniValue::VARR);
9e52ca32 2956 for (auto time : sample_times) {
0d37ae3a 2957 UniValue result(UniValue::VOBJ);
9e52ca32 2958 result.push_back(Pair("runningtime", time));
6962bb3d
TH
2959 results.push_back(result);
2960 }
2961
2962 return results;
2963}
2964
0d37ae3a 2965UniValue zc_raw_receive(const UniValue& params, bool fHelp)
a8ac403d 2966{
f15b9549 2967 if (!EnsureWalletIsAvailable(fHelp)) {
0d37ae3a 2968 return NullUniValue;
f15b9549
NW
2969 }
2970
2971 if (fHelp || params.size() != 2) {
2972 throw runtime_error(
eae37941 2973 "zcrawreceive zcsecretkey encryptednote\n"
f15b9549 2974 "\n"
ca0ec80b 2975 "DEPRECATED. Decrypts encryptednote and checks if the coin commitments\n"
f15b9549
NW
2976 "are in the blockchain as indicated by the \"exists\" result.\n"
2977 "\n"
2978 "Output: {\n"
2979 " \"amount\": value,\n"
4bc00dc1 2980 " \"note\": noteplaintext,\n"
f15b9549
NW
2981 " \"exists\": exists\n"
2982 "}\n"
2983 );
2984 }
2985
0d37ae3a 2986 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR));
f15b9549 2987
a8ac403d
SB
2988 LOCK(cs_main);
2989
0d6864e4
SB
2990 CZCSpendingKey spendingkey(params[0].get_str());
2991 SpendingKey k = spendingkey.Get();
a8ac403d 2992
6c36a9fe
SB
2993 uint256 epk;
2994 unsigned char nonce;
2995 ZCNoteEncryption::Ciphertext ct;
2dc35992 2996 uint256 h_sig;
6c36a9fe
SB
2997
2998 {
4bc00dc1 2999 CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
6c36a9fe
SB
3000 try {
3001 ssData >> nonce;
3002 ssData >> epk;
3003 ssData >> ct;
2dc35992 3004 ssData >> h_sig;
6c36a9fe
SB
3005 } catch(const std::exception &) {
3006 throw runtime_error(
4bc00dc1 3007 "encrypted_note could not be decoded"
6c36a9fe
SB
3008 );
3009 }
3010 }
3011
642a1caf 3012 ZCNoteDecryption decryptor(k.receiving_key());
a8ac403d 3013
2dc35992
SB
3014 NotePlaintext npt = NotePlaintext::decrypt(
3015 decryptor,
3016 ct,
3017 epk,
3018 h_sig,
3019 nonce
3020 );
3021 PaymentAddress payment_addr = k.address();
3022 Note decrypted_note = npt.note(payment_addr);
a8ac403d
SB
3023
3024 assert(pwalletMain != NULL);
2dc35992 3025 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
a8ac403d 3026 uint256 anchor;
2dc35992 3027 uint256 commitment = decrypted_note.cm();
4bc00dc1 3028 pwalletMain->WitnessNoteCommitment(
2dc35992
SB
3029 {commitment},
3030 witnesses,
3031 anchor
3032 );
a8ac403d
SB
3033
3034 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2dc35992 3035 ss << npt;
a8ac403d 3036
0d37ae3a 3037 UniValue result(UniValue::VOBJ);
2dc35992 3038 result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value)));
4bc00dc1 3039 result.push_back(Pair("note", HexStr(ss.begin(), ss.end())));
2dc35992 3040 result.push_back(Pair("exists", (bool) witnesses[0]));
a8ac403d
SB
3041 return result;
3042}
3043
2dc35992
SB
3044
3045
0d37ae3a 3046UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
730790f7 3047{
f15b9549 3048 if (!EnsureWalletIsAvailable(fHelp)) {
0d37ae3a 3049 return NullUniValue;
f15b9549
NW
3050 }
3051
3052 if (fHelp || params.size() != 5) {
3053 throw runtime_error(
eae37941 3054 "zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
4bc00dc1 3055 " inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
f15b9549
NW
3056 " outputs: a JSON object mapping {zcaddr: value, ...}\n"
3057 "\n"
ca0ec80b 3058 "DEPRECATED. Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
f15b9549
NW
3059 "Outputs are confidential between sender/receiver. The vpub_old and\n"
3060 "vpub_new values are globally public and move transparent value into\n"
3061 "or out of the confidential value store, respectively.\n"
3062 "\n"
3063 "Note: The caller is responsible for delivering the output enc1 and\n"
3064 "enc2 to the appropriate recipients, as well as signing rawtxout and\n"
3065 "ensuring it is mined. (A future RPC call will deliver the confidential\n"
3066 "payments in-band on the blockchain.)\n"
3067 "\n"
3068 "Output: {\n"
4bc00dc1
DH
3069 " \"encryptednote1\": enc1,\n"
3070 " \"encryptednote2\": enc2,\n"
f15b9549
NW
3071 " \"rawtxn\": rawtxout\n"
3072 "}\n"
3073 );
3074 }
3075
a8ac403d 3076 LOCK(cs_main);
730790f7
SB
3077
3078 CTransaction tx;
3079 if (!DecodeHexTx(tx, params[0].get_str()))
3080 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
3081
0d37ae3a
JG
3082 UniValue inputs = params[1].get_obj();
3083 UniValue outputs = params[2].get_obj();
730790f7
SB
3084
3085 CAmount vpub_old(0);
3086 CAmount vpub_new(0);
3087
3088 if (params[3].get_real() != 0.0)
3089 vpub_old = AmountFromValue(params[3]);
3090
3091 if (params[4].get_real() != 0.0)
3092 vpub_new = AmountFromValue(params[4]);
3093
b7e4abd6
SB
3094 std::vector<JSInput> vjsin;
3095 std::vector<JSOutput> vjsout;
2dc35992
SB
3096 std::vector<Note> notes;
3097 std::vector<SpendingKey> keys;
3098 std::vector<uint256> commitments;
a8ac403d 3099
0d37ae3a
JG
3100 for (const string& name_ : inputs.getKeys()) {
3101 CZCSpendingKey spendingkey(inputs[name_].get_str());
0d6864e4 3102 SpendingKey k = spendingkey.Get();
a8ac403d 3103
2dc35992 3104 keys.push_back(k);
a8ac403d 3105
2dc35992 3106 NotePlaintext npt;
a8ac403d 3107
2dc35992 3108 {
0d37ae3a 3109 CDataStream ssData(ParseHexV(name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
2dc35992 3110 ssData >> npt;
a8ac403d
SB
3111 }
3112
2dc35992
SB
3113 PaymentAddress addr = k.address();
3114 Note note = npt.note(addr);
3115 notes.push_back(note);
3116 commitments.push_back(note.cm());
3117 }
3118
3119 uint256 anchor;
3120 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
4bc00dc1 3121 pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
2dc35992
SB
3122
3123 assert(witnesses.size() == notes.size());
3124 assert(notes.size() == keys.size());
3125
3126 {
3127 for (size_t i = 0; i < witnesses.size(); i++) {
3128 if (!witnesses[i]) {
3129 throw runtime_error(
b7e4abd6 3130 "joinsplit input could not be found in tree"
2dc35992
SB
3131 );
3132 }
3133
b7e4abd6 3134 vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
2dc35992 3135 }
730790f7 3136 }
730790f7 3137
b7e4abd6
SB
3138 while (vjsin.size() < ZC_NUM_JS_INPUTS) {
3139 vjsin.push_back(JSInput());
a8ac403d 3140 }
730790f7 3141
0d37ae3a
JG
3142 for (const string& name_ : outputs.getKeys()) {
3143 CZCPaymentAddress pubaddr(name_);
e104fcdd 3144 PaymentAddress addrTo = pubaddr.Get();
0d37ae3a 3145 CAmount nAmount = AmountFromValue(outputs[name_]);
730790f7 3146
b7e4abd6 3147 vjsout.push_back(JSOutput(addrTo, nAmount));
730790f7
SB
3148 }
3149
b7e4abd6
SB
3150 while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
3151 vjsout.push_back(JSOutput());
730790f7
SB
3152 }
3153
3154 // TODO
b7e4abd6
SB
3155 if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
3156 throw runtime_error("unsupported joinsplit input/output counts");
730790f7
SB
3157 }
3158
320f2cc7
SB
3159 uint256 joinSplitPubKey;
3160 unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
3161 crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
6aae9d1a
TH
3162
3163 CMutableTransaction mtx(tx);
3164 mtx.nVersion = 2;
3165 mtx.joinSplitPubKey = joinSplitPubKey;
3166
22de1602
SB
3167 JSDescription jsdesc(*pzcashParams,
3168 joinSplitPubKey,
3169 anchor,
3170 {vjsin[0], vjsin[1]},
3171 {vjsout[0], vjsout[1]},
3172 vpub_old,
3173 vpub_new);
320f2cc7 3174
bc59f537
SB
3175 {
3176 auto verifier = libzcash::ProofVerifier::Strict();
3177 assert(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey));
3178 }
730790f7 3179
22de1602 3180 mtx.vjoinsplit.push_back(jsdesc);
730790f7 3181
6aae9d1a
TH
3182 // Empty output script.
3183 CScript scriptCode;
3184 CTransaction signTx(mtx);
be126699
JG
3185 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
3186 uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
6aae9d1a
TH
3187
3188 // Add the signature
320f2cc7
SB
3189 assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
3190 dataToBeSigned.begin(), 32,
3191 joinSplitPrivKey
3192 ) == 0);
3193
3194 // Sanity check
3195 assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
3196 dataToBeSigned.begin(), 32,
3197 mtx.joinSplitPubKey.begin()
3198 ) == 0);
6aae9d1a 3199
730790f7
SB
3200 CTransaction rawTx(mtx);
3201
3202 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
3203 ss << rawTx;
3204
4bc00dc1
DH
3205 std::string encryptedNote1;
3206 std::string encryptedNote2;
6c36a9fe
SB
3207 {
3208 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
3209 ss2 << ((unsigned char) 0x00);
22de1602
SB
3210 ss2 << jsdesc.ephemeralKey;
3211 ss2 << jsdesc.ciphertexts[0];
3212 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
6c36a9fe 3213
4bc00dc1 3214 encryptedNote1 = HexStr(ss2.begin(), ss2.end());
6c36a9fe
SB
3215 }
3216 {
3217 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
3218 ss2 << ((unsigned char) 0x01);
22de1602
SB
3219 ss2 << jsdesc.ephemeralKey;
3220 ss2 << jsdesc.ciphertexts[1];
3221 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
6c36a9fe 3222
4bc00dc1 3223 encryptedNote2 = HexStr(ss2.begin(), ss2.end());
6c36a9fe
SB
3224 }
3225
0d37ae3a 3226 UniValue result(UniValue::VOBJ);
4bc00dc1
DH
3227 result.push_back(Pair("encryptednote1", encryptedNote1));
3228 result.push_back(Pair("encryptednote2", encryptedNote2));
730790f7
SB
3229 result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
3230 return result;
3231}
3232
0d37ae3a 3233UniValue zc_raw_keygen(const UniValue& params, bool fHelp)
730790f7 3234{
f15b9549 3235 if (!EnsureWalletIsAvailable(fHelp)) {
0d37ae3a 3236 return NullUniValue;
f15b9549
NW
3237 }
3238
3239 if (fHelp || params.size() != 0) {
3240 throw runtime_error(
eae37941 3241 "zcrawkeygen\n"
f15b9549 3242 "\n"
ca0ec80b 3243 "DEPRECATED. Generate a zcaddr which can send and receive confidential values.\n"
f15b9549
NW
3244 "\n"
3245 "Output: {\n"
3246 " \"zcaddress\": zcaddr,\n"
3247 " \"zcsecretkey\": zcsecretkey,\n"
7b8d4f87 3248 " \"zcviewingkey\": zcviewingkey,\n"
f15b9549
NW
3249 "}\n"
3250 );
3251 }
3252
2dc35992
SB
3253 auto k = SpendingKey::random();
3254 auto addr = k.address();
3255 auto viewing_key = k.viewing_key();
730790f7 3256
e104fcdd 3257 CZCPaymentAddress pubaddr(addr);
0d6864e4 3258 CZCSpendingKey spendingkey(k);
7b8d4f87 3259 CZCViewingKey viewingkey(viewing_key);
730790f7 3260
0d37ae3a 3261 UniValue result(UniValue::VOBJ);
e104fcdd 3262 result.push_back(Pair("zcaddress", pubaddr.ToString()));
0d6864e4 3263 result.push_back(Pair("zcsecretkey", spendingkey.ToString()));
7b8d4f87 3264 result.push_back(Pair("zcviewingkey", viewingkey.ToString()));
730790f7 3265 return result;
f15b9549 3266}
c1c45943
S
3267
3268
0d37ae3a 3269UniValue z_getnewaddress(const UniValue& params, bool fHelp)
c1c45943
S
3270{
3271 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3272 return NullUniValue;
c1c45943 3273
49e591eb 3274 if (fHelp || params.size() > 0)
c1c45943
S
3275 throw runtime_error(
3276 "z_getnewaddress\n"
3277 "\nReturns a new zaddr for receiving payments.\n"
3278 "\nArguments:\n"
3279 "\nResult:\n"
1333d0d7 3280 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) The new zaddr\n"
c1c45943
S
3281 "\nExamples:\n"
3282 + HelpExampleCli("z_getnewaddress", "")
3283 + HelpExampleRpc("z_getnewaddress", "")
3284 );
3285
3286 LOCK2(cs_main, pwalletMain->cs_wallet);
3287
73699cea
S
3288 EnsureWalletIsUnlocked();
3289
c1c45943
S
3290 CZCPaymentAddress pubaddr = pwalletMain->GenerateNewZKey();
3291 std::string result = pubaddr.ToString();
3292 return result;
3293}
3294
e709997f 3295
0d37ae3a 3296UniValue z_listaddresses(const UniValue& params, bool fHelp)
e709997f
S
3297{
3298 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3299 return NullUniValue;
e709997f
S
3300
3301 if (fHelp || params.size() > 1)
3302 throw runtime_error(
44e37656 3303 "z_listaddresses ( includeWatchonly )\n"
e709997f
S
3304 "\nReturns the list of zaddr belonging to the wallet.\n"
3305 "\nArguments:\n"
44e37656 3306 "1. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n"
e709997f
S
3307 "\nResult:\n"
3308 "[ (json array of string)\n"
3309 " \"zaddr\" (string) a zaddr belonging to the wallet\n"
3310 " ,...\n"
3311 "]\n"
3312 "\nExamples:\n"
3313 + HelpExampleCli("z_listaddresses", "")
3314 + HelpExampleRpc("z_listaddresses", "")
3315 );
3316
3317 LOCK2(cs_main, pwalletMain->cs_wallet);
3318
44e37656
JG
3319 bool fIncludeWatchonly = false;
3320 if (params.size() > 0) {
3321 fIncludeWatchonly = params[0].get_bool();
3322 }
3323
0d37ae3a 3324 UniValue ret(UniValue::VARR);
e709997f
S
3325 std::set<libzcash::PaymentAddress> addresses;
3326 pwalletMain->GetPaymentAddresses(addresses);
3327 for (auto addr : addresses ) {
44e37656
JG
3328 if (fIncludeWatchonly || pwalletMain->HaveSpendingKey(addr)) {
3329 ret.push_back(CZCPaymentAddress(addr).ToString());
3330 }
e709997f
S
3331 }
3332 return ret;
3333}
3334
44e37656 3335CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ignoreUnspendable=true) {
a0a3334c
S
3336 set<CBitcoinAddress> setAddress;
3337 vector<COutput> vecOutputs;
9d365796 3338 CAmount balance = 0;
3339
a0a3334c
S
3340 if (transparentAddress.length() > 0) {
3341 CBitcoinAddress taddr = CBitcoinAddress(transparentAddress);
3342 if (!taddr.IsValid()) {
3343 throw std::runtime_error("invalid transparent address");
3344 }
3345 setAddress.insert(taddr);
3346 }
9d365796 3347
a0a3334c
S
3348 LOCK2(cs_main, pwalletMain->cs_wallet);
3349
3350 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
3351
3352 BOOST_FOREACH(const COutput& out, vecOutputs) {
3353 if (out.nDepth < minDepth) {
3354 continue;
3355 }
3356
44e37656
JG
3357 if (ignoreUnspendable && !out.fSpendable) {
3358 continue;
3359 }
3360
a0a3334c
S
3361 if (setAddress.size()) {
3362 CTxDestination address;
3363 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3364 continue;
3365 }
3366
3367 if (!setAddress.count(address)) {
3368 continue;
3369 }
3370 }
9d365796 3371
47658758 3372 CAmount nValue = out.tx->vout[out.i].nValue; // komodo_interest
a0a3334c
S
3373 balance += nValue;
3374 }
3375 return balance;
3376}
3377
44e37656 3378CAmount getBalanceZaddr(std::string address, int minDepth = 1, bool ignoreUnspendable=true) {
a0a3334c 3379 CAmount balance = 0;
a9743bc8 3380 std::vector<CNotePlaintextEntry> entries;
a0a3334c 3381 LOCK2(cs_main, pwalletMain->cs_wallet);
44e37656 3382 pwalletMain->GetFilteredNotes(entries, address, minDepth, true, ignoreUnspendable);
a9743bc8
S
3383 for (auto & entry : entries) {
3384 balance += CAmount(entry.plaintext.value);
a0a3334c 3385 }
a0a3334c
S
3386 return balance;
3387}
3388
3389
0d37ae3a 3390UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
6c41028f
S
3391{
3392 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3393 return NullUniValue;
6c41028f
S
3394
3395 if (fHelp || params.size()==0 || params.size() >2)
3396 throw runtime_error(
3397 "z_listreceivedbyaddress \"address\" ( minconf )\n"
3398 "\nReturn a list of amounts received by a zaddr belonging to the node’s wallet.\n"
3399 "\nArguments:\n"
3400 "1. \"address\" (string) The private address.\n"
3401 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3402 "\nResult:\n"
3403 "{\n"
3404 " \"txid\": xxxxx, (string) the transaction id\n"
3405 " \"amount\": xxxxx, (numeric) the amount of value in the note\n"
3406 " \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
3407 "}\n"
337a99a2
JG
3408 "\nExamples:\n"
3409 + HelpExampleCli("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3410 + HelpExampleRpc("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
6c41028f
S
3411 );
3412
3413 LOCK2(cs_main, pwalletMain->cs_wallet);
3414
3415 int nMinDepth = 1;
3416 if (params.size() > 1) {
3417 nMinDepth = params[1].get_int();
3418 }
3419 if (nMinDepth < 0) {
3420 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3421 }
9d365796 3422
6c41028f
S
3423 // Check that the from address is valid.
3424 auto fromaddress = params[0].get_str();
3425
3426 libzcash::PaymentAddress zaddr;
3427 CZCPaymentAddress address(fromaddress);
3428 try {
3429 zaddr = address.Get();
fce72608 3430 } catch (const std::runtime_error&) {
6c41028f
S
3431 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
3432 }
3433
44e37656
JG
3434 if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) {
3435 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
6c41028f 3436 }
9d365796 3437
3438
0d37ae3a 3439 UniValue result(UniValue::VARR);
6c41028f 3440 std::vector<CNotePlaintextEntry> entries;
44e37656 3441 pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false, false);
6c41028f 3442 for (CNotePlaintextEntry & entry : entries) {
0d37ae3a 3443 UniValue obj(UniValue::VOBJ);
6c41028f
S
3444 obj.push_back(Pair("txid",entry.jsop.hash.ToString()));
3445 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value))));
3446 std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end());
3447 obj.push_back(Pair("memo", HexStr(data)));
3448 result.push_back(obj);
3449 }
3450 return result;
3451}
3452
3453
0d37ae3a 3454UniValue z_getbalance(const UniValue& params, bool fHelp)
a0a3334c
S
3455{
3456 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3457 return NullUniValue;
a0a3334c
S
3458
3459 if (fHelp || params.size()==0 || params.size() >2)
3460 throw runtime_error(
3461 "z_getbalance \"address\" ( minconf )\n"
3462 "\nReturns the balance of a taddr or zaddr belonging to the node’s wallet.\n"
2bbfe6c4
JG
3463 "\nCAUTION: If address is a watch-only zaddr, the returned balance may be larger than the actual balance,"
3464 "\nbecause spends cannot be detected with incoming viewing keys.\n"
a0a3334c
S
3465 "\nArguments:\n"
3466 "1. \"address\" (string) The selected address. It may be a transparent or private address.\n"
3467 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3468 "\nResult:\n"
f37f614e 3469 "amount (numeric) The total amount in KMD received for this address.\n"
a0a3334c
S
3470 "\nExamples:\n"
3471 "\nThe total amount received by address \"myaddress\"\n"
3472 + HelpExampleCli("z_getbalance", "\"myaddress\"") +
3473 "\nThe total amount received by address \"myaddress\" at least 5 blocks confirmed\n"
3474 + HelpExampleCli("z_getbalance", "\"myaddress\" 5") +
3475 "\nAs a json rpc call\n"
3476 + HelpExampleRpc("z_getbalance", "\"myaddress\", 5")
3477 );
3478
3479 LOCK2(cs_main, pwalletMain->cs_wallet);
3480
3481 int nMinDepth = 1;
3482 if (params.size() > 1) {
3483 nMinDepth = params[1].get_int();
3484 }
12448b64
S
3485 if (nMinDepth < 0) {
3486 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3487 }
9d365796 3488
a0a3334c
S
3489 // Check that the from address is valid.
3490 auto fromaddress = params[0].get_str();
3491 bool fromTaddr = false;
3492 CBitcoinAddress taddr(fromaddress);
3493 fromTaddr = taddr.IsValid();
3494 libzcash::PaymentAddress zaddr;
3495 if (!fromTaddr) {
3496 CZCPaymentAddress address(fromaddress);
3497 try {
3498 zaddr = address.Get();
fce72608 3499 } catch (const std::runtime_error&) {
a0a3334c
S
3500 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3501 }
44e37656
JG
3502 if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) {
3503 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
12448b64 3504 }
a0a3334c
S
3505 }
3506
3507 CAmount nBalance = 0;
3508 if (fromTaddr) {
44e37656 3509 nBalance = getBalanceTaddr(fromaddress, nMinDepth, false);
a0a3334c 3510 } else {
44e37656 3511 nBalance = getBalanceZaddr(fromaddress, nMinDepth, false);
a0a3334c
S
3512 }
3513
3514 return ValueFromAmount(nBalance);
3515}
3516
3517
0d37ae3a 3518UniValue z_gettotalbalance(const UniValue& params, bool fHelp)
a0a3334c
S
3519{
3520 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3521 return NullUniValue;
a0a3334c 3522
44e37656 3523 if (fHelp || params.size() > 2)
a0a3334c 3524 throw runtime_error(
44e37656 3525 "z_gettotalbalance ( minconf includeWatchonly )\n"
a0a3334c 3526 "\nReturn the total value of funds stored in the node’s wallet.\n"
2bbfe6c4
JG
3527 "\nCAUTION: If the wallet contains watch-only zaddrs, the returned private balance may be larger than the actual balance,"
3528 "\nbecause spends cannot be detected with incoming viewing keys.\n"
a0a3334c
S
3529 "\nArguments:\n"
3530 "1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
44e37656 3531 "2. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress' and 'z_importviewingkey')\n"
a0a3334c
S
3532 "\nResult:\n"
3533 "{\n"
3534 " \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
3535 " \"private\": xxxxx, (numeric) the total balance of private funds\n"
3536 " \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n"
3537 "}\n"
3538 "\nExamples:\n"
3539 "\nThe total amount in the wallet\n"
3540 + HelpExampleCli("z_gettotalbalance", "") +
3541 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3542 + HelpExampleCli("z_gettotalbalance", "5") +
3543 "\nAs a json rpc call\n"
3544 + HelpExampleRpc("z_gettotalbalance", "5")
3545 );
3546
3547 LOCK2(cs_main, pwalletMain->cs_wallet);
3548
3549 int nMinDepth = 1;
44e37656 3550 if (params.size() > 0) {
a0a3334c
S
3551 nMinDepth = params[0].get_int();
3552 }
12448b64
S
3553 if (nMinDepth < 0) {
3554 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3555 }
a0a3334c 3556
44e37656
JG
3557 bool fIncludeWatchonly = false;
3558 if (params.size() > 1) {
3559 fIncludeWatchonly = params[1].get_bool();
3560 }
3561
a0a3334c 3562 // getbalance and "getbalance * 1 true" should return the same number
9d365796 3563 // but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
a0a3334c
S
3564 // pwalletMain->GetBalance() does not accept min depth parameter
3565 // so we use our own method to get balance of utxos.
44e37656
JG
3566 CAmount nBalance = getBalanceTaddr("", nMinDepth, !fIncludeWatchonly);
3567 CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth, !fIncludeWatchonly);
da16b12e 3568 uint64_t interest = komodo_interestsum();
a0a3334c 3569 CAmount nTotalBalance = nBalance + nPrivateBalance;
0d37ae3a 3570 UniValue result(UniValue::VOBJ);
f54db399 3571 result.push_back(Pair("transparent", FormatMoney(nBalance)));
945f015d 3572 result.push_back(Pair("interest", FormatMoney(interest)));
f54db399
JG
3573 result.push_back(Pair("private", FormatMoney(nPrivateBalance)));
3574 result.push_back(Pair("total", FormatMoney(nTotalBalance)));
a0a3334c
S
3575 return result;
3576}
3577
0d37ae3a 3578UniValue z_getoperationresult(const UniValue& params, bool fHelp)
c1eae280
S
3579{
3580 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3581 return NullUniValue;
c1eae280
S
3582
3583 if (fHelp || params.size() > 1)
3584 throw runtime_error(
3585 "z_getoperationresult ([\"operationid\", ... ]) \n"
3586 "\nRetrieve the result and status of an operation which has finished, and then remove the operation from memory."
3587 + HelpRequiringPassphrase() + "\n"
3588 "\nArguments:\n"
3589 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3590 "\nResult:\n"
3591 "\" [object, ...]\" (array) A list of JSON objects\n"
337a99a2
JG
3592 "\nExamples:\n"
3593 + HelpExampleCli("z_getoperationresult", "'[\"operationid\", ... ]'")
3594 + HelpExampleRpc("z_getoperationresult", "'[\"operationid\", ... ]'")
c1eae280 3595 );
9d365796 3596
c1eae280
S
3597 // This call will remove finished operations
3598 return z_getoperationstatus_IMPL(params, true);
3599}
fc72c078 3600
0d37ae3a 3601UniValue z_getoperationstatus(const UniValue& params, bool fHelp)
fc72c078
S
3602{
3603 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3604 return NullUniValue;
fc72c078 3605
34f0001c 3606 if (fHelp || params.size() > 1)
fc72c078 3607 throw runtime_error(
34f0001c 3608 "z_getoperationstatus ([\"operationid\", ... ]) \n"
c1eae280 3609 "\nGet operation status and any associated result or error data. The operation will remain in memory."
fc72c078
S
3610 + HelpRequiringPassphrase() + "\n"
3611 "\nArguments:\n"
c1eae280 3612 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
fc72c078 3613 "\nResult:\n"
34f0001c 3614 "\" [object, ...]\" (array) A list of JSON objects\n"
337a99a2
JG
3615 "\nExamples:\n"
3616 + HelpExampleCli("z_getoperationstatus", "'[\"operationid\", ... ]'")
3617 + HelpExampleRpc("z_getoperationstatus", "'[\"operationid\", ... ]'")
fc72c078 3618 );
9d365796 3619
c1eae280
S
3620 // This call is idempotent so we don't want to remove finished operations
3621 return z_getoperationstatus_IMPL(params, false);
3622}
fc72c078 3623
0d37ae3a 3624UniValue z_getoperationstatus_IMPL(const UniValue& params, bool fRemoveFinishedOperations=false)
c1eae280 3625{
fc72c078
S
3626 LOCK2(cs_main, pwalletMain->cs_wallet);
3627
34f0001c
S
3628 std::set<AsyncRPCOperationId> filter;
3629 if (params.size()==1) {
0d37ae3a 3630 UniValue ids = params[0].get_array();
c24109ec 3631 for (const UniValue & v : ids.getValues()) {
34f0001c
S
3632 filter.insert(v.get_str());
3633 }
fc72c078 3634 }
34f0001c 3635 bool useFilter = (filter.size()>0);
fc72c078 3636
0d37ae3a 3637 UniValue ret(UniValue::VARR);
34f0001c
S
3638 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3639 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3640
3641 for (auto id : ids) {
3642 if (useFilter && !filter.count(id))
3643 continue;
9d365796 3644
34f0001c
S
3645 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3646 if (!operation) {
3647 continue;
3648 // It's possible that the operation was removed from the internal queue and map during this loop
3649 // throw JSONRPCError(RPC_INVALID_PARAMETER, "No operation exists for that id.");
3650 }
fc72c078 3651
2f21206c
S
3652 UniValue obj = operation->getStatus();
3653 std::string s = obj["status"].get_str();
c1eae280
S
3654 if (fRemoveFinishedOperations) {
3655 // Caller is only interested in retrieving finished results
2f21206c
S
3656 if ("success"==s || "failed"==s || "cancelled"==s) {
3657 ret.push_back(obj);
c1eae280
S
3658 q->popOperationForId(id);
3659 }
3660 } else {
2f21206c 3661 ret.push_back(obj);
34f0001c 3662 }
fc72c078
S
3663 }
3664
0d37ae3a
JG
3665 std::vector<UniValue> arrTmp = ret.getValues();
3666
2d2f3d18 3667 // sort results chronologically by creation_time
0d37ae3a 3668 std::sort(arrTmp.begin(), arrTmp.end(), [](UniValue a, UniValue b) -> bool {
2d2f3d18
S
3669 const int64_t t1 = find_value(a.get_obj(), "creation_time").get_int64();
3670 const int64_t t2 = find_value(b.get_obj(), "creation_time").get_int64();
3671 return t1 < t2;
3672 });
3673
0d37ae3a
JG
3674 ret.clear();
3675 ret.setArray();
3676 ret.push_backV(arrTmp);
3677
34f0001c 3678 return ret;
fc72c078
S
3679}
3680
3920292b
S
3681
3682// Here we define the maximum number of zaddr outputs that can be included in a transaction.
3683// If input notes are small, we might actually require more than one joinsplit per zaddr output.
3684// For now though, we assume we use one joinsplit per zaddr output (and the second output note is change).
3685// We reduce the result by 1 to ensure there is room for non-joinsplit CTransaction data.
3686#define Z_SENDMANY_MAX_ZADDR_OUTPUTS ((MAX_TX_SIZE / JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)) - 1)
3687
3688// transaction.h comment: spending taddr output requires CTxIn >= 148 bytes and typical taddr txout is 34 bytes
3689#define CTXIN_SPEND_DUST_SIZE 148
3690#define CTXOUT_REGULAR_SIZE 34
3691
0d37ae3a 3692UniValue z_sendmany(const UniValue& params, bool fHelp)
fc72c078
S
3693{
3694 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3695 return NullUniValue;
fc72c078 3696
af53da02 3697 if (fHelp || params.size() < 2 || params.size() > 4)
fc72c078 3698 throw runtime_error(
af53da02 3699 "z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee )\n"
fc72c078 3700 "\nSend multiple times. Amounts are double-precision floating point numbers."
b7d7b2ad 3701 "\nChange from a taddr flows to a new taddr address, while change from zaddr returns to itself."
48f9c65b 3702 "\nWhen sending coinbase UTXOs to a zaddr, change is not allowed. The entire value of the UTXO(s) must be consumed."
3920292b 3703 + strprintf("\nCurrently, the maximum number of zaddr outputs is %d due to transaction size limits.\n", Z_SENDMANY_MAX_ZADDR_OUTPUTS)
fc72c078
S
3704 + HelpRequiringPassphrase() + "\n"
3705 "\nArguments:\n"
3706 "1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from.\n"
3707 "2. \"amounts\" (array, required) An array of json objects representing the amounts to send.\n"
3708 " [{\n"
3709 " \"address\":address (string, required) The address is a taddr or zaddr\n"
f37f614e 3710 " \"amount\":amount (numeric, required) The numeric amount in KMD is the value\n"
fc72c078
S
3711 " \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
3712 " }, ... ]\n"
3713 "3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
af53da02
S
3714 "4. fee (numeric, optional, default="
3715 + strprintf("%s", FormatMoney(ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
fc72c078
S
3716 "\nResult:\n"
3717 "\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
337a99a2 3718 "\nExamples:\n"
1333d0d7 3719 + HelpExampleCli("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" '[{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]'")
3720 + HelpExampleRpc("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", [{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]")
fc72c078
S
3721 );
3722
3723 LOCK2(cs_main, pwalletMain->cs_wallet);
3724
fc72c078
S
3725 // Check that the from address is valid.
3726 auto fromaddress = params[0].get_str();
3727 bool fromTaddr = false;
3728 CBitcoinAddress taddr(fromaddress);
3729 fromTaddr = taddr.IsValid();
3730 libzcash::PaymentAddress zaddr;
3731 if (!fromTaddr) {
3732 CZCPaymentAddress address(fromaddress);
3733 try {
3734 zaddr = address.Get();
fce72608 3735 } catch (const std::runtime_error&) {
fc72c078
S
3736 // invalid
3737 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3738 }
3739 }
3740
dafb8161 3741 // Check that we have the spending key
fc72c078
S
3742 if (!fromTaddr) {
3743 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3744 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3745 }
3746 }
3747
0d37ae3a 3748 UniValue outputs = params[1].get_array();
fc72c078
S
3749
3750 if (outputs.size()==0)
3751 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
3752
3753 // Keep track of addresses to spot duplicates
3754 set<std::string> setAddress;
3755
3756 // Recipients
dafb8161
S
3757 std::vector<SendManyRecipient> taddrRecipients;
3758 std::vector<SendManyRecipient> zaddrRecipients;
af53da02 3759 CAmount nTotalOut = 0;
fc72c078 3760
0d37ae3a
JG
3761 for (const UniValue& o : outputs.getValues()) {
3762 if (!o.isObject())
fc72c078 3763 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
fc72c078 3764
fc72c078 3765 // sanity check, report error if unknown key-value pairs
0d37ae3a
JG
3766 for (const string& name_ : o.getKeys()) {
3767 std::string s = name_;
fc72c078
S
3768 if (s != "address" && s != "amount" && s!="memo")
3769 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown key: ")+s);
3770 }
3771
3772 string address = find_value(o, "address").get_str();
3773 bool isZaddr = false;
3774 CBitcoinAddress taddr(address);
2f151c30 3775 if (!taddr.IsValid())
3776 {
fc72c078
S
3777 try {
3778 CZCPaymentAddress zaddr(address);
3779 zaddr.Get();
3780 isZaddr = true;
fce72608 3781 } catch (const std::runtime_error&) {
fc72c078
S
3782 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
3783 }
3784 }
2f151c30 3785 else if ( ASSETCHAINS_PRIVATE != 0 )
3786 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
fc72c078
S
3787
3788 if (setAddress.count(address))
3789 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address);
3790 setAddress.insert(address);
3791
0d37ae3a 3792 UniValue memoValue = find_value(o, "memo");
fc72c078 3793 string memo;
0d37ae3a 3794 if (!memoValue.isNull()) {
fc72c078
S
3795 memo = memoValue.get_str();
3796 if (!isZaddr) {
c938fb1f 3797 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo cannot be used with a taddr. It can only be used with a zaddr.");
fc72c078
S
3798 } else if (!IsHex(memo)) {
3799 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
3800 }
6114cfe7 3801 if (memo.length() > ZC_MEMO_SIZE*2) {
dafb8161
S
3802 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
3803 }
fc72c078
S
3804 }
3805
0d37ae3a 3806 UniValue av = find_value(o, "amount");
fc72c078
S
3807 CAmount nAmount = AmountFromValue( av );
3808 if (nAmount < 0)
3809 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
3810
dafb8161
S
3811 if (isZaddr) {
3812 zaddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3813 } else {
3814 taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3815 }
af53da02
S
3816
3817 nTotalOut += nAmount;
fc72c078
S
3818 }
3819
3920292b
S
3820 // Check the number of zaddr outputs does not exceed the limit.
3821 if (zaddrRecipients.size() > Z_SENDMANY_MAX_ZADDR_OUTPUTS) {
3822 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, too many zaddr outputs");
3823 }
3824
3825 // As a sanity check, estimate and verify that the size of the transaction will be valid.
3826 // Depending on the input notes, the actual tx size may turn out to be larger and perhaps invalid.
3827 size_t txsize = 0;
3828 CMutableTransaction mtx;
3829 mtx.nVersion = 2;
3830 for (int i = 0; i < zaddrRecipients.size(); i++) {
3831 mtx.vjoinsplit.push_back(JSDescription());
3832 }
3833 CTransaction tx(mtx);
3834 txsize += tx.GetSerializeSize(SER_NETWORK, tx.nVersion);
3835 if (fromTaddr) {
3836 txsize += CTXIN_SPEND_DUST_SIZE;
3837 txsize += CTXOUT_REGULAR_SIZE; // There will probably be taddr change
3838 }
3839 txsize += CTXOUT_REGULAR_SIZE * taddrRecipients.size();
3840 if (txsize > MAX_TX_SIZE) {
3841 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Too many outputs, size of raw transaction would be larger than limit of %d bytes", MAX_TX_SIZE ));
fc72c078
S
3842 }
3843
fc72c078
S
3844 // Minimum confirmations
3845 int nMinDepth = 1;
12448b64 3846 if (params.size() > 2) {
fc72c078 3847 nMinDepth = params[2].get_int();
12448b64
S
3848 }
3849 if (nMinDepth < 0) {
3850 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3851 }
fc72c078 3852
af53da02
S
3853 // Fee in Zatoshis, not currency format)
3854 CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE;
3855 if (params.size() > 3) {
7eccce4e
S
3856 if (params[3].get_real() == 0.0) {
3857 nFee = 0;
3858 } else {
3859 nFee = AmountFromValue( params[3] );
3860 }
3861
af53da02
S
3862 // Check that the user specified fee is sane.
3863 if (nFee > nTotalOut) {
3864 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the sum of outputs %s", FormatMoney(nFee), FormatMoney(nTotalOut)));
3865 }
3866 }
3867
8aa7937d 3868 // Use input parameters as the optional context info to be returned by z_getoperationstatus and z_getoperationresult.
0d37ae3a 3869 UniValue o(UniValue::VOBJ);
8aa7937d
S
3870 o.push_back(Pair("fromaddress", params[0]));
3871 o.push_back(Pair("amounts", params[1]));
3872 o.push_back(Pair("minconf", nMinDepth));
3873 o.push_back(Pair("fee", std::stod(FormatMoney(nFee))));
0d37ae3a 3874 UniValue contextInfo = o;
8aa7937d 3875
072099d7 3876 // Contextual transaction we will build on
9bb37bf0
JG
3877 int nextBlockHeight = chainActive.Height() + 1;
3878 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextBlockHeight);
e6cd2a83
S
3879 bool isShielded = !fromTaddr || zaddrRecipients.size() > 0;
3880 if (contextualTx.nVersion == 1 && isShielded) {
7d2e4b3c 3881 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
072099d7 3882 }
9bb37bf0
JG
3883 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
3884 contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta;
3885 }
072099d7 3886
dafb8161 3887 // Create operation and add to global queue
fc72c078 3888 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
072099d7 3889 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(contextualTx, fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee, contextInfo) );
fc72c078
S
3890 q->addOperation(operation);
3891 AsyncRPCOperationId operationId = operation->getId();
3892 return operationId;
fc72c078 3893}
34f0001c
S
3894
3895
06c19063
S
3896/**
3897When estimating the number of coinbase utxos we can shield in a single transaction:
38981. Joinsplit description is 1802 bytes.
38992. Transaction overhead ~ 100 bytes
39003. Spending a typical P2PKH is >=148 bytes, as defined in CTXIN_SPEND_DUST_SIZE.
39014. Spending a multi-sig P2SH address can vary greatly:
3902 https://github.com/bitcoin/bitcoin/blob/c3ad56f4e0b587d8d763af03d743fdfc2d180c9b/src/main.cpp#L517
3903 In real-world coinbase utxos, we consider a 3-of-3 multisig, where the size is roughly:
3904 (3*(33+1))+3 = 105 byte redeem script
3905 105 + 1 + 3*(73+1) = 328 bytes of scriptSig, rounded up to 400 based on testnet experiments.
3906*/
3907#define CTXIN_SPEND_P2SH_SIZE 400
3908
c5dabd2b
S
3909#define SHIELD_COINBASE_DEFAULT_LIMIT 50
3910
06c19063
S
3911UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
3912{
3913 if (!EnsureWalletIsAvailable(fHelp))
3914 return NullUniValue;
3915
c5dabd2b 3916 if (fHelp || params.size() < 2 || params.size() > 4)
06c19063 3917 throw runtime_error(
c5dabd2b 3918 "z_shieldcoinbase \"fromaddress\" \"tozaddress\" ( fee ) ( limit )\n"
06c19063
S
3919 "\nShield transparent coinbase funds by sending to a shielded zaddr. This is an asynchronous operation and utxos"
3920 "\nselected for shielding will be locked. If there is an error, they are unlocked. The RPC call `listlockunspent`"
c5dabd2b
S
3921 "\ncan be used to return a list of locked utxos. The number of coinbase utxos selected for shielding can be limited"
3922 "\nby the caller. If the limit parameter is set to zero, the -mempooltxinputlimit option will determine the number"
3923 "\nof uxtos. Any limit is constrained by the consensus rule defining a maximum transaction size of "
06c19063
S
3924 + strprintf("%d bytes.", MAX_TX_SIZE)
3925 + HelpRequiringPassphrase() + "\n"
3926 "\nArguments:\n"
3927 "1. \"fromaddress\" (string, required) The address is a taddr or \"*\" for all taddrs belonging to the wallet.\n"
3928 "2. \"toaddress\" (string, required) The address is a zaddr.\n"
3929 "3. fee (numeric, optional, default="
3930 + strprintf("%s", FormatMoney(SHIELD_COINBASE_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
c5dabd2b
S
3931 "4. limit (numeric, optional, default="
3932 + strprintf("%d", SHIELD_COINBASE_DEFAULT_LIMIT) + ") Limit on the maximum number of utxos to shield. Set to 0 to use node option -mempooltxinputlimit.\n"
06c19063
S
3933 "\nResult:\n"
3934 "{\n"
06c19063
S
3935 " \"remainingUTXOs\": xxx (numeric) Number of coinbase utxos still available for shielding.\n"
3936 " \"remainingValue\": xxx (numeric) Value of coinbase utxos still available for shielding.\n"
9eb8089e
JG
3937 " \"shieldingUTXOs\": xxx (numeric) Number of coinbase utxos being shielded.\n"
3938 " \"shieldingValue\": xxx (numeric) Value of coinbase utxos being shielded.\n"
3939 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
06c19063 3940 "}\n"
337a99a2 3941 "\nExamples:\n"
1333d0d7 3942 + HelpExampleCli("z_shieldcoinbase", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3943 + HelpExampleRpc("z_shieldcoinbase", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
06c19063
S
3944 );
3945
3946 LOCK2(cs_main, pwalletMain->cs_wallet);
3947
3948 // Validate the from address
3949 auto fromaddress = params[0].get_str();
3950 bool isFromWildcard = fromaddress == "*";
3951 CBitcoinAddress taddr;
3952 if (!isFromWildcard) {
3953 taddr = CBitcoinAddress(fromaddress);
3954 if (!taddr.IsValid()) {
3955 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or \"*\".");
3956 }
3957 }
3958
3959 // Validate the destination address
3960 auto destaddress = params[1].get_str();
3961 try {
3962 CZCPaymentAddress pa(destaddress);
3963 libzcash::PaymentAddress zaddr = pa.Get();
3964 } catch (const std::runtime_error&) {
3965 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
3966 }
3967
3968 // Convert fee from currency format to zatoshis
3969 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
3970 if (params.size() > 2) {
3971 if (params[2].get_real() == 0.0) {
3972 nFee = 0;
3973 } else {
3974 nFee = AmountFromValue( params[2] );
3975 }
3976 }
3977
c5dabd2b
S
3978 int nLimit = SHIELD_COINBASE_DEFAULT_LIMIT;
3979 if (params.size() > 3) {
3980 nLimit = params[3].get_int();
3981 if (nLimit < 0) {
3982 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of utxos cannot be negative");
3983 }
3984 }
3985
06c19063
S
3986 // Prepare to get coinbase utxos
3987 std::vector<ShieldCoinbaseUTXO> inputs;
3988 CAmount shieldedValue = 0;
3989 CAmount remainingValue = 0;
3990 size_t estimatedTxSize = 2000; // 1802 joinsplit description + tx overhead + wiggle room
7d2e4b3c 3991
3992 #ifdef __LP64__
3993 uint64_t utxoCounter = 0;
3994 #else
06c19063 3995 size_t utxoCounter = 0;
7d2e4b3c 3996 #endif
3997
06c19063 3998 bool maxedOutFlag = false;
c5dabd2b 3999 size_t mempoolLimit = (nLimit != 0) ? nLimit : (size_t)GetArg("-mempooltxinputlimit", 0);
06c19063
S
4000
4001 // Set of addresses to filter utxos by
4002 set<CBitcoinAddress> setAddress = {};
4003 if (!isFromWildcard) {
4004 setAddress.insert(taddr);
4005 }
4006
4007 // Get available utxos
4008 vector<COutput> vecOutputs;
4009 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true);
4010
4011 // Find unspent coinbase utxos and update estimated size
4012 BOOST_FOREACH(const COutput& out, vecOutputs) {
4013 if (!out.fSpendable) {
4014 continue;
4015 }
4016
4017 CTxDestination address;
4018 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
4019 continue;
4020 }
4021 // If taddr is not wildcard "*", filter utxos
4022 if (setAddress.size()>0 && !setAddress.count(address)) {
4023 continue;
4024 }
4025
4026 if (!out.tx->IsCoinBase()) {
4027 continue;
4028 }
4029
4030 utxoCounter++;
4031 CAmount nValue = out.tx->vout[out.i].nValue;
4032
4033 if (!maxedOutFlag) {
4034 CBitcoinAddress ba(address);
4035 size_t increase = (ba.IsScript()) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
4036 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
4037 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
4038 {
4039 maxedOutFlag = true;
4040 } else {
4041 estimatedTxSize += increase;
4042 ShieldCoinbaseUTXO utxo = {out.tx->GetHash(), out.i, nValue};
4043 inputs.push_back(utxo);
4044 shieldedValue += nValue;
4045 }
4046 }
4047
4048 if (maxedOutFlag) {
4049 remainingValue += nValue;
4050 }
4051 }
4052
7d2e4b3c 4053 #ifdef __LP64__
4054 uint64_t numUtxos = inputs.size();
4055 #else
06c19063 4056 size_t numUtxos = inputs.size();
7d2e4b3c 4057 #endif
06c19063
S
4058
4059 if (numUtxos == 0) {
4060 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any coinbase funds to shield.");
4061 }
4062
4063 if (shieldedValue < nFee) {
4064 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
4065 strprintf("Insufficient coinbase funds, have %s, which is less than miners fee %s",
4066 FormatMoney(shieldedValue), FormatMoney(nFee)));
4067 }
4068
4069 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
4070 CAmount netAmount = shieldedValue - nFee;
4071 if (nFee > netAmount) {
4072 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
4073 }
4074
4075 // Keep record of parameters in context object
4076 UniValue contextInfo(UniValue::VOBJ);
4077 contextInfo.push_back(Pair("fromaddress", params[0]));
4078 contextInfo.push_back(Pair("toaddress", params[1]));
4079 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
4080
072099d7 4081 // Contextual transaction we will build on
9bb37bf0 4082 int nextBlockHeight = chainActive.Height() + 1;
072099d7 4083 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
9bb37bf0 4084 Params().GetConsensus(), nextBlockHeight);
072099d7 4085 if (contextualTx.nVersion == 1) {
7d2e4b3c 4086 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
072099d7 4087 }
9bb37bf0
JG
4088 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
4089 contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta;
4090 }
072099d7 4091
06c19063
S
4092 // Create operation and add to global queue
4093 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
072099d7 4094 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(contextualTx, inputs, destaddress, nFee, contextInfo) );
06c19063
S
4095 q->addOperation(operation);
4096 AsyncRPCOperationId operationId = operation->getId();
4097
4098 // Return continuation information
4099 UniValue o(UniValue::VOBJ);
4100 o.push_back(Pair("remainingUTXOs", utxoCounter - numUtxos));
4101 o.push_back(Pair("remainingValue", ValueFromAmount(remainingValue)));
4102 o.push_back(Pair("shieldingUTXOs", numUtxos));
4103 o.push_back(Pair("shieldingValue", ValueFromAmount(shieldedValue)));
4104 o.push_back(Pair("opid", operationId));
4105 return o;
4106}
4107
4108
6e9c7629
JG
4109#define MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT 50
4110#define MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT 10
4111
4112#define JOINSPLIT_SIZE JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)
4113
4114UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
4115{
4116 if (!EnsureWalletIsAvailable(fHelp))
4117 return NullUniValue;
4118
f5446e44 4119 auto fEnableMergeToAddress = true; //fExperimentalMode && GetBoolArg("-zmergetoaddress", false);
553a5c1a
JG
4120 std::string strDisabledMsg = "";
4121 if (!fEnableMergeToAddress) {
4122 strDisabledMsg = "\nWARNING: z_mergetoaddress is DISABLED but can be enabled as an experimental feature.\n";
4123 }
4124
6e9c7629
JG
4125 if (fHelp || params.size() < 2 || params.size() > 6)
4126 throw runtime_error(
4127 "z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n"
553a5c1a 4128 + strDisabledMsg +
6e9c7629
JG
4129 "\nMerge multiple UTXOs and notes into a single UTXO or note. Coinbase UTXOs are ignored; use `z_shieldcoinbase`"
4130 "\nto combine those into a single note."
4131 "\n\nThis is an asynchronous operation, and UTXOs selected for merging will be locked. If there is an error, they"
4132 "\nare unlocked. The RPC call `listlockunspent` can be used to return a list of locked UTXOs."
4133 "\n\nThe number of UTXOs and notes selected for merging can be limited by the caller. If the transparent limit"
4134 "\nparameter is set to zero, the -mempooltxinputlimit option will determine the number of UTXOs. Any limit is"
4135 "\nconstrained by the consensus rule defining a maximum transaction size of "
4136 + strprintf("%d bytes.", MAX_TX_SIZE)
4137 + HelpRequiringPassphrase() + "\n"
4138 "\nArguments:\n"
4139 "1. fromaddresses (string, required) A JSON array with addresses.\n"
4140 " The following special strings are accepted inside the array:\n"
4141 " - \"*\": Merge both UTXOs and notes from all addresses belonging to the wallet.\n"
4142 " - \"ANY_TADDR\": Merge UTXOs from all t-addrs belonging to the wallet.\n"
4143 " - \"ANY_ZADDR\": Merge notes from all z-addrs belonging to the wallet.\n"
4144 " If a special string is given, any given addresses of that type will be ignored.\n"
4145 " [\n"
4146 " \"address\" (string) Can be a t-addr or a z-addr\n"
4147 " ,...\n"
4148 " ]\n"
4149 "2. \"toaddress\" (string, required) The t-addr or z-addr to send the funds to.\n"
4150 "3. fee (numeric, optional, default="
4151 + strprintf("%s", FormatMoney(MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
4152 "4. transparent_limit (numeric, optional, default="
4153 + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT) + ") Limit on the maximum number of UTXOs to merge. Set to 0 to use node option -mempooltxinputlimit.\n"
4154 "4. shielded_limit (numeric, optional, default="
4155 + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT) + ") Limit on the maximum number of notes to merge. Set to 0 to merge as many as will fit in the transaction.\n"
4156 "5. \"memo\" (string, optional) Encoded as hex. When toaddress is a z-addr, this will be stored in the memo field of the new note.\n"
4157 "\nResult:\n"
4158 "{\n"
4159 " \"remainingUTXOs\": xxx (numeric) Number of UTXOs still available for merging.\n"
4160 " \"remainingTransparentValue\": xxx (numeric) Value of UTXOs still available for merging.\n"
4161 " \"remainingNotes\": xxx (numeric) Number of notes still available for merging.\n"
4162 " \"remainingShieldedValue\": xxx (numeric) Value of notes still available for merging.\n"
4163 " \"mergingUTXOs\": xxx (numeric) Number of UTXOs being merged.\n"
4164 " \"mergingTransparentValue\": xxx (numeric) Value of UTXOs being merged.\n"
4165 " \"mergingNotes\": xxx (numeric) Number of notes being merged.\n"
4166 " \"mergingShieldedValue\": xxx (numeric) Value of notes being merged.\n"
4167 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
4168 "}\n"
4169 "\nExamples:\n"
1333d0d7 4170 + HelpExampleCli("z_mergetoaddress", "'[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"]' ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf")
4171 + HelpExampleRpc("z_mergetoaddress", "[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"], \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
6e9c7629
JG
4172 );
4173
553a5c1a
JG
4174 if (!fEnableMergeToAddress) {
4175 throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_mergetoaddress is disabled.");
4176 }
4177
6e9c7629
JG
4178 LOCK2(cs_main, pwalletMain->cs_wallet);
4179
4180 bool useAny = false;
4181 bool useAnyUTXO = false;
4182 bool useAnyNote = false;
4183 std::set<CBitcoinAddress> taddrs = {};
4184 std::set<libzcash::PaymentAddress> zaddrs = {};
4185
4186 UniValue addresses = params[0].get_array();
4187 if (addresses.size()==0)
4188 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, fromaddresses array is empty.");
4189
4190 // Keep track of addresses to spot duplicates
4191 std::set<std::string> setAddress;
4192
4193 // Sources
4194 for (const UniValue& o : addresses.getValues()) {
4195 if (!o.isStr())
4196 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
4197
4198 std::string address = o.get_str();
4199 if (address == "*") {
4200 useAny = true;
4201 } else if (address == "ANY_TADDR") {
4202 useAnyUTXO = true;
4203 } else if (address == "ANY_ZADDR") {
4204 useAnyNote = true;
4205 } else {
4206 CBitcoinAddress taddr(address);
4207 if (taddr.IsValid()) {
4208 // Ignore any listed t-addrs if we are using all of them
4209 if (!(useAny || useAnyUTXO)) {
4210 taddrs.insert(taddr);
4211 }
4212 } else {
4213 try {
4214 CZCPaymentAddress zaddr(address);
4215 // Ignore listed z-addrs if we are using all of them
4216 if (!(useAny || useAnyNote)) {
4217 zaddrs.insert(zaddr.Get());
4218 }
4219 } catch (const std::runtime_error&) {
4220 throw JSONRPCError(
4221 RPC_INVALID_PARAMETER,
4222 string("Invalid parameter, unknown address format: ") + address);
4223 }
4224 }
4225 }
4226
4227 if (setAddress.count(address))
4228 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + address);
4229 setAddress.insert(address);
4230 }
4231
4232 // Validate the destination address
4233 auto destaddress = params[1].get_str();
4234 bool isToZaddr = false;
4235 CBitcoinAddress taddr(destaddress);
4236 if (!taddr.IsValid()) {
4237 try {
4238 CZCPaymentAddress zaddr(destaddress);
4239 zaddr.Get();
4240 isToZaddr = true;
4241 } catch (const std::runtime_error&) {
4242 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
4243 }
4244 }
2f151c30 4245 else if ( ASSETCHAINS_PRIVATE != 0 )
4246 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
6e9c7629
JG
4247
4248 // Convert fee from currency format to zatoshis
4249 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
4250 if (params.size() > 2) {
4251 if (params[2].get_real() == 0.0) {
4252 nFee = 0;
4253 } else {
4254 nFee = AmountFromValue( params[2] );
4255 }
4256 }
4257
4258 int nUTXOLimit = MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT;
4259 if (params.size() > 3) {
4260 nUTXOLimit = params[3].get_int();
4261 if (nUTXOLimit < 0) {
4262 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of UTXOs cannot be negative");
4263 }
4264 }
4265
4266 int nNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT;
4267 if (params.size() > 4) {
4268 nNoteLimit = params[4].get_int();
4269 if (nNoteLimit < 0) {
4270 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of notes cannot be negative");
4271 }
4272 }
4273
4274 std::string memo;
4275 if (params.size() > 5) {
4276 memo = params[5].get_str();
4277 if (!isToZaddr) {
4278 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
4279 } else if (!IsHex(memo)) {
4280 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
4281 }
4282 if (memo.length() > ZC_MEMO_SIZE*2) {
4283 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
4284 }
4285 }
4286
4287 MergeToAddressRecipient recipient(destaddress, memo);
4288
4289 // Prepare to get UTXOs and notes
4290 std::vector<MergeToAddressInputUTXO> utxoInputs;
4291 std::vector<MergeToAddressInputNote> noteInputs;
4292 CAmount mergedUTXOValue = 0;
4293 CAmount mergedNoteValue = 0;
4294 CAmount remainingUTXOValue = 0;
4295 CAmount remainingNoteValue = 0;
7d2e4b3c 4296 #ifdef __LP64__
4297 uint64_t utxoCounter = 0;
4298 uint64_t noteCounter = 0;
4299 #else
6e9c7629
JG
4300 size_t utxoCounter = 0;
4301 size_t noteCounter = 0;
7d2e4b3c 4302 #endif
6e9c7629
JG
4303 bool maxedOutUTXOsFlag = false;
4304 bool maxedOutNotesFlag = false;
4305 size_t mempoolLimit = (nUTXOLimit != 0) ? nUTXOLimit : (size_t)GetArg("-mempooltxinputlimit", 0);
4306
4307 size_t estimatedTxSize = 200; // tx overhead + wiggle room
4308 if (isToZaddr) {
4309 estimatedTxSize += JOINSPLIT_SIZE;
4310 }
4311
4312 if (useAny || useAnyUTXO || taddrs.size() > 0) {
4313 // Get available utxos
4314 vector<COutput> vecOutputs;
4315 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, false);
4316
4317 // Find unspent utxos and update estimated size
4318 for (const COutput& out : vecOutputs) {
4319 if (!out.fSpendable) {
4320 continue;
4321 }
4322
4323 CTxDestination address;
4324 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
4325 continue;
4326 }
4327 // If taddr is not wildcard "*", filter utxos
4328 if (taddrs.size() > 0 && !taddrs.count(address)) {
4329 continue;
4330 }
4331
4332 utxoCounter++;
4333 CAmount nValue = out.tx->vout[out.i].nValue;
4334
4335 if (!maxedOutUTXOsFlag) {
4336 CBitcoinAddress ba(address);
4337 size_t increase = (ba.IsScript()) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
4338 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
4339 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
4340 {
4341 maxedOutUTXOsFlag = true;
4342 } else {
4343 estimatedTxSize += increase;
4344 COutPoint utxo(out.tx->GetHash(), out.i);
4345 utxoInputs.emplace_back(utxo, nValue);
4346 mergedUTXOValue += nValue;
4347 }
4348 }
4349
4350 if (maxedOutUTXOsFlag) {
4351 remainingUTXOValue += nValue;
4352 }
4353 }
4354 }
4355
4356 if (useAny || useAnyNote || zaddrs.size() > 0) {
4357 // Get available notes
4358 std::vector<CNotePlaintextEntry> entries;
4359 pwalletMain->GetFilteredNotes(entries, zaddrs);
4360
4361 // Find unspent notes and update estimated size
4362 for (CNotePlaintextEntry& entry : entries) {
4363 noteCounter++;
4364 CAmount nValue = entry.plaintext.value;
4365
4366 if (!maxedOutNotesFlag) {
4367 // If we haven't added any notes yet and the merge is to a
4368 // z-address, we have already accounted for the first JoinSplit.
4369 size_t increase = (noteInputs.empty() && !isToZaddr) || (noteInputs.size() % 2 == 0) ? JOINSPLIT_SIZE : 0;
4370 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
4371 (nNoteLimit > 0 && noteCounter > nNoteLimit))
4372 {
4373 maxedOutNotesFlag = true;
4374 } else {
4375 estimatedTxSize += increase;
4376 SpendingKey zkey;
4377 pwalletMain->GetSpendingKey(entry.address, zkey);
4378 noteInputs.emplace_back(entry.jsop, entry.plaintext.note(entry.address), nValue, zkey);
4379 mergedNoteValue += nValue;
4380 }
4381 }
4382
4383 if (maxedOutNotesFlag) {
4384 remainingNoteValue += nValue;
4385 }
4386 }
4387 }
4388
7d2e4b3c 4389 #ifdef __LP64__
4390 uint64_t numUtxos = utxoInputs.size(); //ca333
4391 uint64_t numNotes = noteInputs.size();
4392 #else
6e9c7629
JG
4393 size_t numUtxos = utxoInputs.size();
4394 size_t numNotes = noteInputs.size();
7d2e4b3c 4395 #endif
4396
6e9c7629
JG
4397
4398 if (numUtxos == 0 && numNotes == 0) {
4399 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any funds to merge.");
4400 }
4401
4402 // Sanity check: Don't do anything if:
4403 // - We only have one from address
4404 // - It's equal to toaddress
4405 // - The address only contains a single UTXO or note
4406 if (setAddress.size() == 1 && setAddress.count(destaddress) && (numUtxos + numNotes) == 1) {
4407 throw JSONRPCError(RPC_INVALID_PARAMETER, "Destination address is also the only source address, and all its funds are already merged.");
4408 }
4409
4410 CAmount mergedValue = mergedUTXOValue + mergedNoteValue;
4411 if (mergedValue < nFee) {
4412 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
4413 strprintf("Insufficient funds, have %s, which is less than miners fee %s",
4414 FormatMoney(mergedValue), FormatMoney(nFee)));
4415 }
4416
4417 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
4418 CAmount netAmount = mergedValue - nFee;
4419 if (nFee > netAmount) {
4420 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
4421 }
4422
4423 // Keep record of parameters in context object
4424 UniValue contextInfo(UniValue::VOBJ);
4425 contextInfo.push_back(Pair("fromaddresses", params[0]));
4426 contextInfo.push_back(Pair("toaddress", params[1]));
4427 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
4428
4429 // Contextual transaction we will build on
7b92f27e 4430 int nextBlockHeight = chainActive.Height() + 1;
6e9c7629
JG
4431 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
4432 Params().GetConsensus(),
7b92f27e 4433 nextBlockHeight);
6e9c7629
JG
4434 bool isShielded = numNotes > 0 || isToZaddr;
4435 if (contextualTx.nVersion == 1 && isShielded) {
4436 contextualTx.nVersion = 2; // Tx format should support vjoinsplit
4437 }
7b92f27e
JG
4438 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
4439 contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta;
4440 }
6e9c7629
JG
4441
4442 // Create operation and add to global queue
4443 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4444 std::shared_ptr<AsyncRPCOperation> operation(
4445 new AsyncRPCOperation_mergetoaddress(contextualTx, utxoInputs, noteInputs, recipient, nFee, contextInfo) );
4446 q->addOperation(operation);
4447 AsyncRPCOperationId operationId = operation->getId();
4448
4449 // Return continuation information
4450 UniValue o(UniValue::VOBJ);
4451 o.push_back(Pair("remainingUTXOs", utxoCounter - numUtxos));
4452 o.push_back(Pair("remainingTransparentValue", ValueFromAmount(remainingUTXOValue)));
4453 o.push_back(Pair("remainingNotes", noteCounter - numNotes));
4454 o.push_back(Pair("remainingShieldedValue", ValueFromAmount(remainingNoteValue)));
4455 o.push_back(Pair("mergingUTXOs", numUtxos));
4456 o.push_back(Pair("mergingTransparentValue", ValueFromAmount(mergedUTXOValue)));
4457 o.push_back(Pair("mergingNotes", numNotes));
4458 o.push_back(Pair("mergingShieldedValue", ValueFromAmount(mergedNoteValue)));
4459 o.push_back(Pair("opid", operationId));
4460 return o;
4461}
4462
4463
0d37ae3a 4464UniValue z_listoperationids(const UniValue& params, bool fHelp)
34f0001c
S
4465{
4466 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 4467 return NullUniValue;
34f0001c
S
4468
4469 if (fHelp || params.size() > 1)
4470 throw runtime_error(
4471 "z_listoperationids\n"
4472 "\nReturns the list of operation ids currently known to the wallet.\n"
4473 "\nArguments:\n"
c938fb1f 4474 "1. \"status\" (string, optional) Filter result by the operation's state e.g. \"success\".\n"
34f0001c
S
4475 "\nResult:\n"
4476 "[ (json array of string)\n"
4477 " \"operationid\" (string) an operation id belonging to the wallet\n"
4478 " ,...\n"
4479 "]\n"
4480 "\nExamples:\n"
4481 + HelpExampleCli("z_listoperationids", "")
4482 + HelpExampleRpc("z_listoperationids", "")
4483 );
4484
4485 LOCK2(cs_main, pwalletMain->cs_wallet);
4486
4487 std::string filter;
4488 bool useFilter = false;
4489 if (params.size()==1) {
4490 filter = params[0].get_str();
4491 useFilter = true;
4492 }
4493
0d37ae3a 4494 UniValue ret(UniValue::VARR);
34f0001c
S
4495 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4496 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
4497 for (auto id : ids) {
4498 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
4499 if (!operation) {
4500 continue;
4501 }
4502 std::string state = operation->getStateAsString();
4503 if (useFilter && filter.compare(state)!=0)
4504 continue;
4505 ret.push_back(id);
4506 }
4507
4508 return ret;
4509}
4c62ef37 4510
4511
4512#include "script/sign.h"
4513int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
4514extern std::string NOTARY_PUBKEY;
a7fc9554 4515uint32_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);
ac531095 4516int8_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256 txid,int32_t vout);
1273624d 4517int32_t komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n);
4c62ef37 4518
496f1fd2 4519int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33)
4520{
f31815fc 4521 set<CBitcoinAddress> setAddress; uint8_t *script,utxosig[128]; uint256 utxotxid; uint64_t utxovalue; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector<COutput> vecOutputs; uint32_t utxovout,eligible,earliest = 0; CScript best_scriptPubKey; bool fNegative,fOverflow;
15000127 4522 bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr;
4523 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
4524 const CKeyStore& keystore = *pwalletMain;
496f1fd2 4525 assert(pwalletMain != NULL);
4526 LOCK2(cs_main, pwalletMain->cs_wallet);
4527 utxovalue = 0;
4528 memset(&utxotxid,0,sizeof(utxotxid));
4529 memset(&utxovout,0,sizeof(utxovout));
4530 memset(utxosig,0,sizeof(utxosig));
4531 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
4532 BOOST_FOREACH(const COutput& out, vecOutputs)
4533 {
4534 if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth )
4535 continue;
4536 if ( setAddress.size() )
4537 {
4538 CTxDestination address;
4539 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
4540 continue;
4541 if (!setAddress.count(address))
4542 continue;
4543 }
4544 CAmount nValue = out.tx->vout[out.i].nValue;
39fefa6b 4545 if ( nValue != 10000 )
4546 continue;
496f1fd2 4547 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
4548 CTxDestination address;
4549 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
4550 {
4551 //entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
4552 //if (pwalletMain->mapAddressBook.count(address))
4553 // entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
4554 }
4555 script = (uint8_t *)out.tx->vout[out.i].scriptPubKey.data();
4556 if ( out.tx->vout[out.i].scriptPubKey.size() != 35 || script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(notarypub33,script+1,33) != 0 )
c4eb1abb 4557 {
137e08d7 4558 //fprintf(stderr,"scriptsize.%d [0] %02x\n",(int32_t)out.tx->vout[out.i].scriptPubKey.size(),script[0]);
496f1fd2 4559 continue;
c4eb1abb 4560 }
496f1fd2 4561 utxovalue = (uint64_t)nValue;
15000127 4562 //decode_hex((uint8_t *)&utxotxid,32,(char *)out.tx->GetHash().GetHex().c_str());
4563 utxotxid = out.tx->GetHash();
496f1fd2 4564 utxovout = out.i;
ff1ee86e 4565 best_scriptPubKey = out.tx->vout[out.i].scriptPubKey;
15000127 4566 //fprintf(stderr,"check %s/v%d %llu\n",(char *)utxotxid.GetHex().c_str(),utxovout,(long long)utxovalue);
496f1fd2 4567
496f1fd2 4568 txNew.vin.resize(1);
4569 txNew.vout.resize(1);
2ad15573 4570 txfee = utxovalue / 2;
3566cdf6 4571 //for (i=0; i<32; i++)
4572 // ((uint8_t *)&revtxid)[i] = ((uint8_t *)&utxotxid)[31 - i];
4573 txNew.vin[0].prevout.hash = utxotxid; //revtxid;
496f1fd2 4574 txNew.vin[0].prevout.n = utxovout;
221cc791 4575 txNew.vout[0].scriptPubKey = CScript() << ParseHex(CRYPTO777_PUBSECPSTR) << OP_CHECKSIG;
496f1fd2 4576 txNew.vout[0].nValue = utxovalue - txfee;
4577 CTransaction txNewConst(txNew);
4578 signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, utxovalue, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId);
4579 if (!signSuccess)
4580 fprintf(stderr,"notaryvin failed to create signature\n");
4581 else
4582 {
4583 UpdateTransaction(txNew,0,sigdata);
4584 ptr = (uint8_t *)sigdata.scriptSig.data();
4585 siglen = sigdata.scriptSig.size();
4586 for (i=0; i<siglen; i++)
db4b45a6 4587 utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]);
4588 //fprintf(stderr," siglen.%d notaryvin %s/v%d\n",siglen,utxotxid.GetHex().c_str(),utxovout);
ff1ee86e 4589 break;
496f1fd2 4590 }
4591 }
4592 return(siglen);
4593}
4594
ac531095 4595struct komodo_staking
4596{
4597 char address[64];
4598 uint256 txid;
4599 arith_uint256 hashval;
4600 uint64_t nValue;
1273624d 4601 uint32_t segid32,txtime;
ac531095 4602 int32_t vout;
1273624d 4603 CScript scriptPubKey;
ac531095 4604};
4605
1273624d 4606struct 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)
ac531095 4607{
4608 uint256 hash; uint32_t segid32; struct komodo_staking *kp;
4609 segid32 = komodo_stakehash(&hash,address,hashbuf,txid,vout);
1273624d 4610 if ( *numkp >= *maxkp )
4611 {
4612 *maxkp += 1000;
4613 array = (struct komodo_staking *)realloc(array,sizeof(*array) * (*maxkp));
4614 }
4615 kp = &array[(*numkp)++];
4616 memset(kp,0,sizeof(*kp));
ac531095 4617 strcpy(kp->address,address);
4618 kp->txid = txid;
4619 kp->vout = vout;
4620 kp->hashval = UintToArith256(hash);
4621 kp->txtime = txtime;
4622 kp->segid32 = segid32;
4623 kp->nValue = nValue;
4624 kp->scriptPubKey = pk;
4625 return(array);
4626}
4627
4628arith_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)
4629{
4630 int32_t diff; uint64_t coinage; arith_uint256 coinage256,hashval;
4631 diff = (iter + blocktime - kp->txtime - minage);
4632 if ( diff < 0 )
4633 diff = 60;
4634 else if ( diff > 3600*24*30 )
4635 diff = 3600*24*30;
4636 if ( iter > 0 )
4637 diff += segid*2;
4638 coinage = ((uint64_t)kp->nValue/COIN * diff);
0ce374b7 4639 if ( blocktime+iter+segid*2 > prevtime+480 )
4640 coinage *= ((blocktime+iter+segid*2) - (prevtime+400));
4641 //if ( nHeight >= 2500 && blocktime+iter+segid*2 > prevtime+180 )
4642 // coinage *= ((blocktime+iter+segid*2) - (prevtime+60));
ac531095 4643 coinage256 = arith_uint256(coinage+1);
4644 hashval = ratio * (kp->hashval / coinage256);
0ce374b7 4645 //if ( nHeight >= 900 && nHeight < 916 )
4646 // hashval = (hashval / coinage256);
ac531095 4647 return(hashval);
4648}
4649
cca0bdc6 4650uint32_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)
ac531095 4651{
8e1ca1ad 4652 int32_t maxiters = 600; uint256 hash;
ac531095 4653 int32_t segid,iter,diff; uint64_t coinage; arith_uint256 hashval,coinage256;
cca0bdc6 4654 komodo_stakehash(&hash,kp->address,hashbuf,kp->txid,kp->vout);
4655 kp->hashval = UintToArith256(hash);
ac531095 4656 segid = ((nHeight + kp->segid32) & 0x3f);
4657 hashval = _komodo_eligible(kp,ratio,blocktime,maxiters,minage,segid,nHeight,prevtime);
d3ce166f 4658 //for (int i=32; i>=0; i--)
4659 // fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
4660 //fprintf(stderr," b.%u minage.%d segid.%d ht.%d prev.%u\n",blocktime,minage,segid,nHeight,prevtime);
ac531095 4661 if ( hashval <= bnTarget )
4662 {
4663 for (iter=0; iter<maxiters; iter++)
4664 {
4665 if ( blocktime+iter+segid*2 < kp->txtime+minage )
4666 continue;
37d6294d 4667 hashval = _komodo_eligible(kp,ratio,blocktime,iter,minage,segid,nHeight,prevtime);
ac531095 4668 if ( hashval <= bnTarget )
4669 {
1973dfa0 4670 //fprintf(stderr,"winner %.8f blocktime.%u iter.%d segid.%d\n",(double)kp->nValue/COIN,blocktime,iter,segid);
ac531095 4671 blocktime += iter;
4672 blocktime += segid * 2;
4673 return(blocktime);
4674 }
4675 }
4676 }
4677 return(0);
4678}
4679
d231a6a7 4680int32_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)
4c62ef37 4681{
ac531095 4682 static struct komodo_staking *array; static int32_t numkp,maxkp; static uint32_t lasttime;
17839698 4683 set<CBitcoinAddress> setAddress; struct komodo_staking *kp; int32_t winners,segid,minage,nHeight,counter=0,i,m,siglen=0,nMinDepth = 1,nMaxDepth = 99999999; vector<COutput> vecOutputs; uint32_t block_from_future_rejecttime,besttime,eligible,eligible2,earliest = 0; CScript best_scriptPubKey; arith_uint256 mindiff,ratio,bnTarget; CBlockIndex *tipindex,*pindex; CTxDestination address; bool fNegative,fOverflow; uint8_t hashbuf[256]; CTransaction tx; uint256 hashBlock;
357e4ca5 4684 bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
ac531095 4685 mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
4686 ratio = (mindiff / bnTarget);
4c62ef37 4687 assert(pwalletMain != NULL);
b8b06863 4688 LOCK2(cs_main, pwalletMain->cs_wallet);
4c62ef37 4689 *utxovaluep = 0;
4690 memset(utxotxidp,0,sizeof(*utxotxidp));
4691 memset(utxovoutp,0,sizeof(*utxovoutp));
4692 memset(utxosig,0,72);
4693 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
55dd6622 4694 if ( (tipindex= chainActive.Tip()) == 0 )
4695 return(0);
ac531095 4696 nHeight = tipindex->nHeight + 1;
4697 if ( (minage= nHeight*3) > 6000 ) // about 100 blocks
4698 minage = 6000;
4699 komodo_segids(hashbuf,nHeight-101,100);
6e7dcf31 4700 if ( *blocktimep > tipindex->nTime+60 )
4701 *blocktimep = tipindex->nTime+60;
2d481115 4702 //fprintf(stderr,"Start scan of utxo for staking %u ht.%d\n",(uint32_t)time(NULL),nHeight);
1973dfa0 4703 if ( time(NULL) > lasttime+600 )
4c62ef37 4704 {
ac531095 4705 if ( array != 0 )
2e4cc2a2 4706 {
ac531095 4707 free(array);
4708 array = 0;
4709 maxkp = numkp = 0;
817aedba 4710 lasttime = 0;
2e4cc2a2 4711 }
ac531095 4712 BOOST_FOREACH(const COutput& out, vecOutputs)
4c62ef37 4713 {
ac531095 4714 if ( (tipindex= chainActive.Tip()) == 0 || tipindex->nHeight+1 > nHeight )
2e4cc2a2 4715 {
ac531095 4716 fprintf(stderr,"chain tip changed during staking loop t.%u counter.%d\n",(uint32_t)time(NULL),counter);
4717 return(0);
2e4cc2a2 4718 }
ac531095 4719 counter++;
4720 if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth )
2e4cc2a2 4721 {
ac531095 4722 //fprintf(stderr,"komodo_staked invalid depth %d\n",(int32_t)out.nDepth);
4c62ef37 4723 continue;
2e4cc2a2 4724 }
ac531095 4725 CAmount nValue = out.tx->vout[out.i].nValue;
4726 if ( nValue < COIN || !out.fSpendable )
55dd6622 4727 continue;
ac531095 4728 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
4729 if ( ExtractDestination(pk,address) != 0 )
4c62ef37 4730 {
ac531095 4731 if ( IsMine(*pwalletMain,address) == 0 )
4732 continue;
aecf5859 4733 if ( GetTransaction(out.tx->GetHash(),tx,hashBlock,true) != 0 && (pindex= mapBlockIndex[hashBlock]) != 0 )
7b6d6985 4734 {
1273624d 4735 array = komodo_addutxo(array,&numkp,&maxkp,(uint32_t)pindex->nTime,(uint64_t)nValue,out.tx->GetHash(),out.i,(char *)CBitcoinAddress(address).ToString().c_str(),hashbuf,(CScript)pk);
ac531095 4736 }
4737 }
4738 }
4739 lasttime = (uint32_t)time(NULL);
8cbf8d6a 4740 //fprintf(stderr,"finished kp data of utxo for staking %u ht.%d numkp.%d maxkp.%d\n",(uint32_t)time(NULL),nHeight,numkp,maxkp);
ac531095 4741 }
17839698 4742 block_from_future_rejecttime = (uint32_t)GetAdjustedTime() + 57;
2d481115 4743 for (i=winners=0; i<numkp; i++)
ac531095 4744 {
817aedba 4745 if ( (tipindex= chainActive.Tip()) == 0 || tipindex->nHeight+1 > nHeight )
4746 {
4747 fprintf(stderr,"chain tip changed during staking loop t.%u counter.%d\n",(uint32_t)time(NULL),counter);
4748 return(0);
4749 }
ac531095 4750 kp = &array[i];
cca0bdc6 4751 if ( (eligible2= komodo_eligible(bnTarget,ratio,kp,nHeight,*blocktimep,(uint32_t)tipindex->nTime+27,minage,hashbuf)) == 0 )
76df25be 4752 continue;
ecae680b 4753 eligible = komodo_stake(0,bnTarget,nHeight,kp->txid,kp->vout,0,(uint32_t)tipindex->nTime+27,kp->address);
1973dfa0 4754 //fprintf(stderr,"i.%d %u vs %u\n",i,eligible2,eligible);
ac531095 4755 if ( eligible > 0 )
4756 {
4757 besttime = m = 0;
4758 if ( eligible == komodo_stake(1,bnTarget,nHeight,kp->txid,kp->vout,eligible,(uint32_t)tipindex->nTime+27,kp->address) )
4759 {
4760 while ( eligible == komodo_stake(1,bnTarget,nHeight,kp->txid,kp->vout,eligible,(uint32_t)tipindex->nTime+27,kp->address) )
e005f576 4761 {
ac531095 4762 besttime = eligible;
4763 eligible--;
17839698 4764 if ( eligible < block_from_future_rejecttime ) // nothing gained by going earlier
aa2ef3ab 4765 break;
ac531095 4766 m++;
011b0a24 4767 //fprintf(stderr,"m.%d ht.%d validated winning blocktime %u -> %.8f eligible.%u test prior\n",m,nHeight,*blocktimep,(double)kp->nValue/COIN,eligible);
e005f576 4768 }
ac531095 4769 }
4770 else
4771 {
aecf5859 4772 fprintf(stderr,"ht.%d error validating winning blocktime %u -> %.8f eligible.%u test prior\n",nHeight,*blocktimep,(double)kp->nValue/COIN,eligible);
ac531095 4773 continue;
4774 }
4775 eligible = besttime;
2d481115 4776 winners++;
4777 //fprintf(stderr,"ht.%d validated winning [%d] -> %.8f eligible.%u test prior\n",nHeight,(int32_t)(eligible - tipindex->nTime),(double)kp->nValue/COIN,eligible);
aecf5859 4778 if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || kp->nValue < *utxovaluep)) )
ac531095 4779 {
4780 earliest = eligible;
4781 best_scriptPubKey = kp->scriptPubKey; //out.tx->vout[out.i].scriptPubKey;
4782 *utxovaluep = (uint64_t)kp->nValue;
4783 //decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str());
4784 decode_hex((uint8_t *)utxotxidp,32,(char *)kp->txid.GetHex().c_str());
4785 *utxovoutp = kp->vout;
4786 *txtimep = kp->txtime;//(uint32_t)out.tx->nLockTime;
779b7b3a 4787 fprintf(stderr,"ht.%d earliest.%u [%d].%d (%s) nValue %.8f locktime.%u counter.%d winners.%d\n",nHeight,earliest,(int32_t)(earliest - tipindex->nTime),m,kp->address,(double)kp->nValue/COIN,*txtimep,counter,winners);
ac531095 4788 }
4789 } //else fprintf(stderr,"utxo not eligible\n");
4790 } //else fprintf(stderr,"no tipindex\n");
2d481115 4791 if ( numkp < 10000 && array != 0 )
011b0a24 4792 {
4793 free(array);
4794 array = 0;
4795 maxkp = numkp = 0;
817aedba 4796 lasttime = 0;
011b0a24 4797 }
8c218b48 4798 if ( earliest != 0 )
4799 {
4800 bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid;
4801 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
4802 const CKeyStore& keystore = *pwalletMain;
8c218b48 4803 txNew.vin.resize(1);
4804 txNew.vout.resize(1);
4805 txfee = 0;
4806 for (i=0; i<32; i++)
4807 ((uint8_t *)&revtxid)[i] = ((uint8_t *)utxotxidp)[31 - i];
4808 txNew.vin[0].prevout.hash = revtxid;
4809 txNew.vin[0].prevout.n = *utxovoutp;
4d068367 4810 txNew.vout[0].scriptPubKey = best_scriptPubKey;// CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG;
3c3e04c4 4811 txNew.vout[0].nValue = *utxovaluep - txfee;
09cde8ab 4812 txNew.nLockTime = earliest;
8c218b48 4813 CTransaction txNewConst(txNew);
3c3e04c4 4814 signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, *utxovaluep, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId);
8c218b48 4815 if (!signSuccess)
4816 fprintf(stderr,"failed to create signature\n");
4817 else
4c62ef37 4818 {
d231a6a7 4819 UpdateTransaction(txNew,0,sigdata);
8c218b48 4820 ptr = (uint8_t *)sigdata.scriptSig.data();
4821 siglen = sigdata.scriptSig.size();
4822 for (i=0; i<siglen; i++)
4823 utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]);
4824 //fprintf(stderr," siglen.%d\n",siglen);
34bcc309 4825 //fprintf(stderr,"best %u from %u, gap %d lag.%d\n",earliest,*blocktimep,(int32_t)(earliest - *blocktimep),(int32_t)(time(NULL) - *blocktimep));
09cde8ab 4826 *blocktimep = earliest;
4c62ef37 4827 }
2b72340d 4828 } //else fprintf(stderr,"no earliest utxo for staking\n");
8cbf8d6a 4829 //fprintf(stderr,"end scan of utxo for staking t.%u counter.%d numkp.%d winners.%d\n",(uint32_t)time(NULL),counter,numkp,winners);
4c62ef37 4830 return(siglen);
4831}
4f02fc40 4832
5963c84f 4833std::string CreateAsset(uint64_t txfee,uint64_t assetsupply,std::string name,std::string description);
e51e9274 4834std::string AssetTransfer(uint64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,uint64_t total);
5963c84f 4835std::string CreateBuyOffer(uint64_t txfee,uint64_t bidamount,uint256 assetid,uint64_t pricetotal);
437d6328 4836std::string CancelBuyOffer(uint64_t txfee,uint256 assetid,uint256 bidtxid);
5963c84f 4837std::string FillBuyOffer(uint64_t txfee,uint256 assetid,uint256 bidtxid,uint256 filltxid,int32_t fillvout);
1a02fde9 4838
93e02ad9 4839uint256 Parseuint256(char *hexstr)
4840{
7015dab7 4841 uint256 txid; int32_t i; std::vector<unsigned char> txidbytes(ParseHex(hexstr));
93e02ad9 4842 for (i=31; i>=0; i--)
4843 ((uint8_t *)&txid)[31-i] = ((uint8_t *)txidbytes.data())[i];
4844 return(txid);
4845}
4846
1a02fde9 4847UniValue tokencreate(const UniValue& params, bool fHelp)
4848{
4849 UniValue result(UniValue::VOBJ); std::string name,description,hex; uint64_t supply;
4850 if ( fHelp || params.size() > 3 || params.size() < 2 )
9a579b30 4851 throw runtime_error("tokencreate name supply description\n");
246ea3c3 4852 name = params[0].get_str();
1a02fde9 4853 supply = atof(params[1].get_str().c_str()) * COIN;
4854 if ( params.size() == 3 )
4855 description = params[2].get_str();
5963c84f 4856 hex = CreateAsset(0,supply,name,description);
1a02fde9 4857 if ( hex.size() > 0 )
4858 {
4859 result.push_back(Pair("result", "success"));
4860 result.push_back(Pair("hex", hex));
e51e9274 4861 } else result.push_back(Pair("error", "couldnt create transaction"));
246ea3c3 4862 return(result);
1a02fde9 4863}
4864
4865UniValue tokentransfer(const UniValue& params, bool fHelp)
4866{
e51e9274 4867 UniValue result(UniValue::VOBJ); std::string hex; uint64_t amount; uint256 tokenid;
4868 if ( fHelp || params.size() != 3 )
4869 throw runtime_error("tokentransfer tokenid destpubkey amount\n");
4870 tokenid = Parseuint256((char *)params[0].get_str().c_str());
4871 std::vector<unsigned char> pubkey(ParseHex(params[1].get_str().c_str()));
4872 amount = atol(params[2].get_str().c_str());
4873 hex = AssetTransfer(0,tokenid,pubkey,amount);
4874 if ( hex.size() > 0 )
4875 {
4876 result.push_back(Pair("result", "success"));
4877 result.push_back(Pair("hex", hex));
4878 } else result.push_back(Pair("error", "couldnt transfer assets"));
1a02fde9 4879 return(result);
4880}
4881
4882UniValue tokenbid(const UniValue& params, bool fHelp)
4883{
da8aa760 4884 UniValue result(UniValue::VOBJ); uint64_t bidamount,numtokens; std::string hex; double price; uint256 tokenid;
5963c84f 4885 if ( fHelp || params.size() != 3 )
4886 throw runtime_error("tokenbid numtokens tokenid price\n");
4887 numtokens = atoi(params[0].get_str().c_str());
6a530006 4888 tokenid = Parseuint256((char *)params[1].get_str().c_str());
5963c84f 4889 price = atof(params[2].get_str().c_str());
93e02ad9 4890 bidamount = (price * numtokens) * COIN + 0.0000000049999;
5963c84f 4891 hex = CreateBuyOffer(0,bidamount,tokenid,numtokens);
4892 if ( hex.size() > 0 )
4893 {
4894 result.push_back(Pair("result", "success"));
4895 result.push_back(Pair("hex", hex));
e51e9274 4896 } else result.push_back(Pair("error", "couldnt create bid"));
1a02fde9 4897 return(result);
4898}
4899
4900UniValue tokencancelbid(const UniValue& params, bool fHelp)
4901{
437d6328 4902 UniValue result(UniValue::VOBJ); std::string hex; int32_t i; uint256 tokenid,bidtxid;
4903 if ( fHelp || params.size() != 2 )
4904 throw runtime_error("tokencancelbid tokenid bidtxid\n");
4905 tokenid = Parseuint256((char *)params[0].get_str().c_str());
4906 bidtxid = Parseuint256((char *)params[1].get_str().c_str());
4907 hex = CancelBuyOffer(0,tokenid,bidtxid);
cf610814 4908 if ( hex.size() > 0 )
4909 {
4910 result.push_back(Pair("result", "success"));
4911 result.push_back(Pair("hex", hex));
e51e9274 4912 } else result.push_back(Pair("error", "couldnt cancel bid"));
1a02fde9 4913 return(result);
4914}
4915
4916UniValue tokenfillbid(const UniValue& params, bool fHelp)
4917{
09c7f7cc 4918 UniValue result(UniValue::VOBJ); int32_t fillvout; std::string hex; uint256 tokenid,bidtxid,filltxid;
e78fa189 4919 if ( fHelp || params.size() != 4 )
09c7f7cc 4920 throw runtime_error("tokenfillbid tokenid bidtxid filltxid fillvout\n");
4921 tokenid = Parseuint256((char *)params[0].get_str().c_str());
4922 bidtxid = Parseuint256((char *)params[1].get_str().c_str());
4923 filltxid = Parseuint256((char *)params[2].get_str().c_str());
4924 fillvout = atoi(params[3].get_str().c_str());
05858018 4925 hex = FillBuyOffer(0,tokenid,bidtxid,filltxid,fillvout);
09c7f7cc 4926 if ( hex.size() > 0 )
4927 {
4928 result.push_back(Pair("result", "success"));
4929 result.push_back(Pair("hex", hex));
4930 } else result.push_back(Pair("error", "couldnt fill bid"));
1a02fde9 4931 return(result);
4932}
4933
4f02fc40 4934UniValue getbalance64(const UniValue& params, bool fHelp)
4935{
4936 set<CBitcoinAddress> setAddress; vector<COutput> vecOutputs;
5e0b330d 4937 UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR),b(UniValue::VARR); CTxDestination address;
4f02fc40 4938 const CKeyStore& keystore = *pwalletMain;
4939 CAmount nValues[64],nValues2[64],nValue,total,total2; int32_t i,segid;
4940 assert(pwalletMain != NULL);
4941 if (fHelp || params.size() > 0)
4942 throw runtime_error("getbalance64\n");
4943 total = total2 = 0;
4944 memset(nValues,0,sizeof(nValues));
4945 memset(nValues2,0,sizeof(nValues2));
4946 LOCK2(cs_main, pwalletMain->cs_wallet);
4947 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
4948 BOOST_FOREACH(const COutput& out, vecOutputs)
4949 {
4950 nValue = out.tx->vout[out.i].nValue;
5e0b330d 4951 if ( ExtractDestination(out.tx->vout[out.i].scriptPubKey, address) )
4f02fc40 4952 {
ca76a7df 4953 segid = (komodo_segid32((char *)CBitcoinAddress(address).ToString().c_str()) & 0x3f);
4f02fc40 4954 if ( out.nDepth < 100 )
4955 nValues2[segid] += nValue, total2 += nValue;
4956 else nValues[segid] += nValue, total += nValue;
d979952f 4957 //fprintf(stderr,"%s %.8f depth.%d segid.%d\n",(char *)CBitcoinAddress(address).ToString().c_str(),(double)nValue/COIN,(int32_t)out.nDepth,segid);
5e0b330d 4958 } else fprintf(stderr,"no destination\n");
4f02fc40 4959 }
5e0b330d 4960 ret.push_back(Pair("mature",(double)total/COIN));
4f02fc40 4961 ret.push_back(Pair("immature",(double)total2/COIN));
4962 for (i=0; i<64; i++)
4963 {
5e0b330d 4964 a.push_back((uint64_t)nValues[i]);
4965 b.push_back((uint64_t)nValues2[i]);
4f02fc40 4966 }
4967 ret.push_back(Pair("staking", a));
5e0b330d 4968 ret.push_back(Pair("notstaking", b));
4f02fc40 4969 return ret;
4970}
dd94983f 4971
4972
This page took 1.554117 seconds and 4 git commands to generate.