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