]> Git Repo - VerusCoin.git/blame - src/wallet/rpcwallet.cpp
Merge pull request #97 from miketout/dev
[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
bc909a7a 4// file COPYING or https://www.opensource.org/licenses/mit-license.php .
e3bc5698 5
eda37330 6#include "amount.h"
be126699 7#include "consensus/upgrades.h"
ae775b5b 8#include "core_io.h"
e3bc5698 9#include "init.h"
3d31e09c 10#include "key_io.h"
8a893c94 11#include "main.h"
434faf9b 12#include "pbaas/pbaas.h"
51ed9ec9
BD
13#include "net.h"
14#include "netbase.h"
4519a766 15#include "rpc/server.h"
14f888ca 16#include "timedata.h"
36e2141d 17#include "transaction_builder.h"
51ed9ec9 18#include "util.h"
b93173de 19#include "utilmoneystr.h"
51ed9ec9
BD
20#include "wallet.h"
21#include "walletdb.h"
8cb25088 22#include "primitives/transaction.h"
6962bb3d 23#include "zcbenchmarks.h"
6aae9d1a 24#include "script/interpreter.h"
70b4ad2d 25#include "zcash/zip32.h"
51ed9ec9 26
fc72c078
S
27#include "utiltime.h"
28#include "asyncrpcoperation.h"
ed21d5bd 29#include "asyncrpcqueue.h"
6e9c7629 30#include "wallet/asyncrpcoperation_mergetoaddress.h"
6e82d728 31#include "wallet/asyncrpcoperation_saplingmigration.h"
fc72c078 32#include "wallet/asyncrpcoperation_sendmany.h"
06c19063 33#include "wallet/asyncrpcoperation_shieldcoinbase.h"
fc72c078 34
5f63373e 35#include "consensus/upgrades.h"
36
320f2cc7
SB
37#include "sodium.h"
38
51ed9ec9 39#include <stdint.h>
51ed9ec9 40#include <boost/assign/list_of.hpp>
a10a6e2a 41#include <univalue.h>
bcbde86a 42#include <numeric>
02b4ca7e 43#include <algorithm>
8e0ff2b7 44
e3bc5698
JG
45using namespace std;
46
2dc35992
SB
47using namespace libzcash;
48
1333d0d7 49extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
672414d7 50extern int32_t VERUS_MIN_STAKEAGE;
eec85c43
JG
51const std::string ADDR_TYPE_SPROUT = "sprout";
52const std::string ADDR_TYPE_SAPLING = "sapling";
53
0d37ae3a 54extern UniValue TxJoinSplitToJSON(const CTransaction& tx);
2f151c30 55extern uint8_t ASSETCHAINS_PRIVATE;
890e708b 56uint32_t komodo_segid32(char *coinaddr);
f7cfb52d 57
51ed9ec9 58int64_t nWalletUnlockTime;
e3bc5698 59static CCriticalSection cs_nWalletUnlockTime;
8e0ff2b7 60std::string CCerror;
e3bc5698 61
c1eae280 62// Private method:
0d37ae3a 63UniValue z_getoperationstatus_IMPL(const UniValue&, bool);
c1eae280 64
82004353
JDL
65#define PLAN_NAME_MAX 8
66#define VALID_PLAN_NAME(x) (strlen(x) <= PLAN_NAME_MAX)
67
bdab0cf5 68std::string HelpRequiringPassphrase()
e3bc5698 69{
b0730874 70 return pwalletMain && pwalletMain->IsCrypted()
a6099ef3 71 ? "\nRequires wallet passphrase to be set with walletpassphrase call."
e3bc5698
JG
72 : "";
73}
74
b9fb692d
JS
75bool EnsureWalletIsAvailable(bool avoidException)
76{
77 if (!pwalletMain)
78 {
79 if (!avoidException)
80 throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
81 else
82 return false;
83 }
84 return true;
85}
86
bdab0cf5 87void EnsureWalletIsUnlocked()
e3bc5698
JG
88{
89 if (pwalletMain->IsLocked())
738835d7 90 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
e3bc5698
JG
91}
92
c60397dd 93uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight);
15bcd69e 94
d014114d 95void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
e3bc5698 96{
cbe3042f 97 //int32_t i,n,txheight; uint32_t locktime; uint64_t interest = 0;
98 int confirms = wtx.GetDepthInMainChain();
e3bc5698 99 entry.push_back(Pair("confirmations", confirms));
e07c8e91
LD
100 if (wtx.IsCoinBase())
101 entry.push_back(Pair("generated", true));
2b72d46f 102 if (confirms > 0)
e3bc5698
JG
103 {
104 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
105 entry.push_back(Pair("blockindex", wtx.nIndex));
209377a7 106 entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
9bb37bf0 107 entry.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight));
e3bc5698 108 }
805344dc 109 uint256 hash = wtx.GetHash();
731b89b8 110 entry.push_back(Pair("txid", hash.GetHex()));
38fc4b70 111 UniValue conflicts(UniValue::VARR);
731b89b8
GA
112 BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
113 conflicts.push_back(conflict.GetHex());
114 entry.push_back(Pair("walletconflicts", conflicts));
d56e30ca 115 entry.push_back(Pair("time", wtx.GetTxTime()));
4b61a6a4 116 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
e3bc5698
JG
117 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
118 entry.push_back(Pair(item.first, item.second));
f7cfb52d
S
119
120 entry.push_back(Pair("vjoinsplit", TxJoinSplitToJSON(wtx)));
e3bc5698
JG
121}
122
d014114d 123string AccountFromValue(const UniValue& value)
e3bc5698
JG
124{
125 string strAccount = value.get_str();
8b6a0cb8 126 //if (strAccount != "")
127 // throw JSONRPCError(RPC_WALLET_ACCOUNTS_UNSUPPORTED, "Accounts are unsupported");
e3bc5698
JG
128 return strAccount;
129}
130
fd2fd9a7
AL
131char *komodo_chainname()
132{
133 return(ASSETCHAINS_SYMBOL[0] == 0 ? (char *)"KMD" : ASSETCHAINS_SYMBOL);
1333d0d7 134}
135
d014114d 136UniValue getnewaddress(const UniValue& params, bool fHelp)
e3bc5698 137{
b9fb692d 138 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 139 return NullUniValue;
9d365796 140
e3bc5698
JG
141 if (fHelp || params.size() > 1)
142 throw runtime_error(
a6099ef3 143 "getnewaddress ( \"account\" )\n"
1333d0d7 144 "\nReturns a new " + strprintf("%s",komodo_chainname()) + " address for receiving payments.\n"
a6099ef3 145 "\nArguments:\n"
3c31eb24 146 "1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 147 "\nResult:\n"
1333d0d7 148 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) The new " + strprintf("%s",komodo_chainname()) + " address\n"
a6099ef3 149 "\nExamples:\n"
150 + HelpExampleCli("getnewaddress", "")
7b782f5b 151 + HelpExampleRpc("getnewaddress", "")
a6099ef3 152 );
e3bc5698 153
4401b2d7
EL
154 LOCK2(cs_main, pwalletMain->cs_wallet);
155
e3bc5698
JG
156 // Parse the account first so we don't generate a key if there's an error
157 string strAccount;
158 if (params.size() > 0)
159 strAccount = AccountFromValue(params[0]);
160
161 if (!pwalletMain->IsLocked())
162 pwalletMain->TopUpKeyPool();
163
164 // Generate a new key that is added to wallet
165 CPubKey newKey;
71ac5052 166 if (!pwalletMain->GetKeyFromPool(newKey))
738835d7 167 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e3bc5698
JG
168 CKeyID keyID = newKey.GetID();
169
a41d5fe0 170 pwalletMain->SetAddressBook(keyID, strAccount, "receive");
e3bc5698 171
07444da1 172 return EncodeDestination(keyID);
e3bc5698
JG
173}
174
175
07444da1 176CTxDestination GetAccountAddress(std::string strAccount, bool bForceNew=false)
e3bc5698
JG
177{
178 CWalletDB walletdb(pwalletMain->strWalletFile);
179
180 CAccount account;
181 walletdb.ReadAccount(strAccount, account);
182
183 bool bKeyUsed = false;
184
185 // Check if the current key has been used
186 if (account.vchPubKey.IsValid())
187 {
0be990ba 188 CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
e3bc5698
JG
189 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
190 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
191 ++it)
192 {
193 const CWalletTx& wtx = (*it).second;
194 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
195 if (txout.scriptPubKey == scriptPubKey)
196 bKeyUsed = true;
197 }
198 }
199
200 // Generate a new key
201 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
202 {
71ac5052 203 if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
738835d7 204 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e3bc5698 205
a41d5fe0 206 pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
e3bc5698
JG
207 walletdb.WriteAccount(strAccount, account);
208 }
209
07444da1 210 return account.vchPubKey.GetID();
e3bc5698
JG
211}
212
d014114d 213UniValue getaccountaddress(const UniValue& params, bool fHelp)
e3bc5698 214{
b9fb692d 215 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 216 return NullUniValue;
9d365796 217
e3bc5698
JG
218 if (fHelp || params.size() != 1)
219 throw runtime_error(
a6099ef3 220 "getaccountaddress \"account\"\n"
1333d0d7 221 "\nDEPRECATED. Returns the current " + strprintf("%s",komodo_chainname()) + " address for receiving payments to this account.\n"
a6099ef3 222 "\nArguments:\n"
3c31eb24 223 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 224 "\nResult:\n"
1333d0d7 225 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) The account " + strprintf("%s",komodo_chainname()) + " address\n"
a6099ef3 226 "\nExamples:\n"
227 + HelpExampleCli("getaccountaddress", "")
228 + HelpExampleCli("getaccountaddress", "\"\"")
229 + HelpExampleCli("getaccountaddress", "\"myaccount\"")
230 + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
231 );
e3bc5698 232
4401b2d7
EL
233 LOCK2(cs_main, pwalletMain->cs_wallet);
234
e3bc5698
JG
235 // Parse the account first so we don't generate a key if there's an error
236 string strAccount = AccountFromValue(params[0]);
237
d014114d 238 UniValue ret(UniValue::VSTR);
e3bc5698 239
07444da1 240 ret = EncodeDestination(GetAccountAddress(strAccount));
e3bc5698
JG
241 return ret;
242}
243
244
d014114d 245UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
e5e9904c 246{
b9fb692d 247 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 248 return NullUniValue;
9d365796 249
e5e9904c
JG
250 if (fHelp || params.size() > 1)
251 throw runtime_error(
252 "getrawchangeaddress\n"
1333d0d7 253 "\nReturns a new " + strprintf("%s",komodo_chainname()) + " address, for receiving change.\n"
a6099ef3 254 "This is for use with raw transactions, NOT normal use.\n"
255 "\nResult:\n"
256 "\"address\" (string) The address\n"
257 "\nExamples:\n"
258 + HelpExampleCli("getrawchangeaddress", "")
259 + HelpExampleRpc("getrawchangeaddress", "")
260 );
e5e9904c 261
4401b2d7
EL
262 LOCK2(cs_main, pwalletMain->cs_wallet);
263
e5e9904c
JG
264 if (!pwalletMain->IsLocked())
265 pwalletMain->TopUpKeyPool();
266
267 CReserveKey reservekey(pwalletMain);
268 CPubKey vchPubKey;
269 if (!reservekey.GetReservedKey(vchPubKey))
6c37f7fd 270 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e5e9904c
JG
271
272 reservekey.KeepKey();
273
274 CKeyID keyID = vchPubKey.GetID();
275
07444da1 276 return EncodeDestination(keyID);
e5e9904c
JG
277}
278
e3bc5698 279
d014114d 280UniValue setaccount(const UniValue& params, bool fHelp)
e3bc5698 281{
b9fb692d 282 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 283 return NullUniValue;
9d365796 284
e3bc5698
JG
285 if (fHelp || params.size() < 1 || params.size() > 2)
286 throw runtime_error(
1333d0d7 287 "setaccount \"" + strprintf("%s",komodo_chainname()) + "_address\" \"account\"\n"
7b782f5b 288 "\nDEPRECATED. Sets the account associated with the given address.\n"
a6099ef3 289 "\nArguments:\n"
1333d0d7 290 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to be associated with an account.\n"
3c31eb24 291 "2. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 292 "\nExamples:\n"
1333d0d7 293 + HelpExampleCli("setaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"tabby\"")
294 + HelpExampleRpc("setaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"tabby\"")
a6099ef3 295 );
e3bc5698 296
4401b2d7
EL
297 LOCK2(cs_main, pwalletMain->cs_wallet);
298
07444da1
PW
299 CTxDestination dest = DecodeDestination(params[0].get_str());
300 if (!IsValidDestination(dest)) {
5ae5090d 301 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Verus address");
07444da1 302 }
e3bc5698 303
e3bc5698
JG
304 string strAccount;
305 if (params.size() > 1)
306 strAccount = AccountFromValue(params[1]);
307
31d6390f 308 // Only add the account if the address is yours.
07444da1 309 if (IsMine(*pwalletMain, dest)) {
31d6390f 310 // Detect when changing the account of an address that is the 'unused current key' of another account:
07444da1
PW
311 if (pwalletMain->mapAddressBook.count(dest)) {
312 std::string strOldAccount = pwalletMain->mapAddressBook[dest].name;
313 if (dest == GetAccountAddress(strOldAccount)) {
31d6390f 314 GetAccountAddress(strOldAccount, true);
07444da1 315 }
31d6390f 316 }
07444da1 317 pwalletMain->SetAddressBook(dest, strAccount, "receive");
e3bc5698 318 }
31d6390f
ES
319 else
320 throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
e3bc5698 321
ed21d5bd 322 return NullUniValue;
e3bc5698
JG
323}
324
325
d014114d 326UniValue getaccount(const UniValue& params, bool fHelp)
e3bc5698 327{
b9fb692d 328 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 329 return NullUniValue;
9d365796 330
e3bc5698
JG
331 if (fHelp || params.size() != 1)
332 throw runtime_error(
1333d0d7 333 "getaccount \"" + strprintf("%s",komodo_chainname()) + "_address\"\n"
7b782f5b 334 "\nDEPRECATED. Returns the account associated with the given address.\n"
a6099ef3 335 "\nArguments:\n"
1333d0d7 336 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address for account lookup.\n"
a6099ef3 337 "\nResult:\n"
338 "\"accountname\" (string) the account address\n"
339 "\nExamples:\n"
1333d0d7 340 + HelpExampleCli("getaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"")
341 + HelpExampleRpc("getaccount", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"")
a6099ef3 342 );
e3bc5698 343
4401b2d7
EL
344 LOCK2(cs_main, pwalletMain->cs_wallet);
345
07444da1
PW
346 CTxDestination dest = DecodeDestination(params[0].get_str());
347 if (!IsValidDestination(dest)) {
5ae5090d 348 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Verus address");
07444da1 349 }
e3bc5698 350
07444da1
PW
351 std::string strAccount;
352 std::map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(dest);
353 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty()) {
61885513 354 strAccount = (*mi).second.name;
07444da1 355 }
e3bc5698
JG
356 return strAccount;
357}
358
359
d014114d 360UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
e3bc5698 361{
b9fb692d 362 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 363 return NullUniValue;
9d365796 364
e3bc5698
JG
365 if (fHelp || params.size() != 1)
366 throw runtime_error(
a6099ef3 367 "getaddressesbyaccount \"account\"\n"
7b782f5b 368 "\nDEPRECATED. Returns the list of addresses for the given account.\n"
a6099ef3 369 "\nArguments:\n"
3c31eb24 370 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
a6099ef3 371 "\nResult:\n"
372 "[ (json array of string)\n"
1333d0d7 373 " \"" + strprintf("%s",komodo_chainname()) + "_address\" (string) a " + strprintf("%s",komodo_chainname()) + " address associated with the given account\n"
a6099ef3 374 " ,...\n"
375 "]\n"
376 "\nExamples:\n"
377 + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
378 + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
379 );
e3bc5698 380
4401b2d7
EL
381 LOCK2(cs_main, pwalletMain->cs_wallet);
382
e3bc5698
JG
383 string strAccount = AccountFromValue(params[0]);
384
385 // Find all addresses that have the given account
38fc4b70 386 UniValue ret(UniValue::VARR);
07444da1
PW
387 for (const std::pair<CTxDestination, CAddressBookData>& item : pwalletMain->mapAddressBook) {
388 const CTxDestination& dest = item.first;
389 const std::string& strName = item.second.name;
390 if (strName == strAccount) {
391 ret.push_back(EncodeDestination(dest));
392 }
e3bc5698
JG
393 }
394 return ret;
395}
396
9415da7f 397static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew,uint8_t *opretbuf,int32_t opretlen,long int opretValue)
b93173de 398{
25cf6f3d
PK
399 CAmount curBalance = pwalletMain->GetBalance();
400
b93173de
PJ
401 // Check amount
402 if (nValue <= 0)
4be639ea 403 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
b93173de 404
25cf6f3d 405 if (nValue > curBalance)
b93173de
PJ
406 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
407
58c4c0bb 408 // Parse Zcash address
b93173de
PJ
409 CScript scriptPubKey = GetScriptForDestination(address);
410
411 // Create and send the transaction
412 CReserveKey reservekey(pwalletMain);
413 CAmount nFeeRequired;
25cf6f3d 414 std::string strError;
292623ad
CL
415 vector<CRecipient> vecSend;
416 int nChangePosRet = -1;
417 CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
418 vecSend.push_back(recipient);
b62d7030 419 if ( opretlen > 0 && opretbuf != 0 )
420 {
421 CScript opretpubkey; int32_t i; uint8_t *ptr;
422 opretpubkey.resize(opretlen);
b62d7030 423 for (i=0; i<opretlen; i++)
4aa2c64e 424 {
9feb4b9e 425 opretpubkey[i] = opretbuf[i];
1919e9de 426 //printf("%02x",ptr[i]);
4aa2c64e 427 }
1919e9de 428 //printf(" opretbuf[%d]\n",opretlen);
b62d7030 429 CRecipient opret = { opretpubkey, opretValue, false };
430 vecSend.push_back(opret);
431 }
292623ad
CL
432 if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
433 if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
434 strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired));
435 throw JSONRPCError(RPC_WALLET_ERROR, strError);
b93173de
PJ
436 }
437 if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
438 throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
b93173de
PJ
439}
440
d014114d 441UniValue sendtoaddress(const UniValue& params, bool fHelp)
e3bc5698 442{
b9fb692d 443 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 444 return NullUniValue;
9d365796 445
292623ad 446 if (fHelp || params.size() < 2 || params.size() > 5)
e3bc5698 447 throw runtime_error(
1333d0d7 448 "sendtoaddress \"" + strprintf("%s",komodo_chainname()) + "_address\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
e743678d 449 "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
a6099ef3 450 + HelpRequiringPassphrase() +
451 "\nArguments:\n"
1333d0d7 452 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to send to.\n"
453 "2. \"amount\" (numeric, required) The amount in " + strprintf("%s",komodo_chainname()) + " to send. eg 0.1\n"
a6099ef3 454 "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
455 " This is not part of the transaction, just kept in your wallet.\n"
456 "4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
457 " to which you're sending the transaction. This is not part of the \n"
458 " transaction, just kept in your wallet.\n"
292623ad 459 "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
1333d0d7 460 " The recipient will receive less " + strprintf("%s",komodo_chainname()) + " than you enter in the amount field.\n"
a6099ef3 461 "\nResult:\n"
b5ef85c7 462 "\"transactionid\" (string) The transaction id.\n"
a6099ef3 463 "\nExamples:\n"
1333d0d7 464 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.1")
465 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.1 \"donation\" \"seans outpost\"")
466 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.1 \"\" \"\" true")
467 + HelpExampleRpc("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", 0.1, \"donation\", \"seans outpost\"")
a6099ef3 468 );
e3bc5698 469
2f151c30 470 if ( ASSETCHAINS_PRIVATE != 0 && AmountFromValue(params[1]) > 0 )
471 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
472
4401b2d7
EL
473 LOCK2(cs_main, pwalletMain->cs_wallet);
474
40c59fea 475 CTxDestination dest = ValidateDestination(params[0].get_str());
476
07444da1 477 if (!IsValidDestination(dest)) {
5ae5090d 478 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Verus address");
07444da1 479 }
e3bc5698
JG
480
481 // Amount
a372168e 482 CAmount nAmount = AmountFromValue(params[1]);
e76a3849
WL
483 if (nAmount <= 0)
484 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
e3bc5698
JG
485
486 // Wallet comments
487 CWalletTx wtx;
ed21d5bd 488 if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty())
e3bc5698 489 wtx.mapValue["comment"] = params[2].get_str();
ed21d5bd 490 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
e3bc5698
JG
491 wtx.mapValue["to"] = params[3].get_str();
492
292623ad
CL
493 bool fSubtractFeeFromAmount = false;
494 if (params.size() > 4)
495 fSubtractFeeFromAmount = params[4].get_bool();
496
f914c7a1 497 EnsureWalletIsUnlocked();
e3bc5698 498
9feb4b9e 499 SendMoney(dest, nAmount, fSubtractFeeFromAmount, wtx,0,0,0);
e3bc5698 500
805344dc 501 return wtx.GetHash().GetHex();
e3bc5698 502}
9feb4b9e 503
bdc72415 504#include "komodo_defs.h"
e3bc5698 505
64449ba8 506#define KOMODO_KVPROTECTED 1
638ac3ba 507#define KOMODO_KVBINARY 2
508#define KOMODO_KVDURATION 1440
ab6e81ec 509#define IGUANA_MAXSCRIPTSIZE 10001
0bda6249 510uint64_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 511int32_t komodo_opreturnscript(uint8_t *script,uint8_t type,uint8_t *opret,int32_t opretlen);
9415da7f 512#define CRYPTO777_KMDADDR "RXL3YXG2ceaB6C5hfJcN4fvmLH2C34knhA"
598ee06a 513extern int32_t KOMODO_PAX;
94d3d09d 514extern uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE;
beb9352f 515int32_t komodo_is_issuer();
19cb746d 516int32_t iguana_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp);
48a3cd18 517int32_t komodo_isrealtime(int32_t *kmdheightp);
aa114a60 518int32_t pax_fiatstatus(uint64_t *available,uint64_t *deposited,uint64_t *issued,uint64_t *withdrawn,uint64_t *approved,uint64_t *redeemed,char *base);
6b5cfbb4 519int32_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 520int32_t komodo_kvcmp(uint8_t *refvalue,uint16_t refvaluesize,uint8_t *value,uint16_t valuesize);
6b5cfbb4 521uint64_t komodo_kvfee(uint32_t flags,int32_t opretlen,int32_t keylen);
522uint256 komodo_kvsig(uint8_t *buf,int32_t len,uint256 privkey);
523int32_t komodo_kvduration(uint32_t flags);
524uint256 komodo_kvprivkey(uint256 *pubkeyp,char *passphrase);
7112e5a7 525int32_t komodo_kvsigverify(uint8_t *buf,int32_t len,uint256 _pubkey,uint256 sig);
d7d27bb3 526
14f3daa6 527UniValue kvupdate(const UniValue& params, bool fHelp)
ab6e81ec 528{
684d42a2 529 static uint256 zeroes;
14f3daa6 530 CWalletTx wtx; UniValue ret(UniValue::VOBJ);
01801559 531 uint8_t keyvalue[IGUANA_MAXSCRIPTSIZE*8],opretbuf[IGUANA_MAXSCRIPTSIZE*8]; int32_t i,coresize,haveprivkey,duration,opretlen,height; uint16_t keylen=0,valuesize=0,refvaluesize=0; uint8_t *key,*value=0; uint32_t flags,tmpflags,n; struct komodo_kv *ptr; uint64_t fee; uint256 privkey,pubkey,refpubkey,sig;
2987e650 532 if (fHelp || params.size() < 3 )
38e9a59c
A
533 throw runtime_error(
534 "kvupdate key \"value\" days passphrase\n"
535 "\nStore a key value. This feature is only available for asset chains.\n"
536 "\nArguments:\n"
537 "1. key (string, required) key\n"
538 "2. \"value\" (string, required) value\n"
539 "3. days (numeric, required) amount of days(1440 blocks/day) before the key expires. Minimum 1 day\n"
540 "4. passphrase (string, optional) passphrase required to update this key\n"
541 "\nResult:\n"
542 "{\n"
543 " \"coin\": \"xxxxx\", (string) chain the key is stored on\n"
544 " \"height\": xxxxx, (numeric) height the key was stored at\n"
6f3db929
A
545 " \"expiration\": xxxxx, (numeric) height the key will expire\n"
546 " \"flags\": x, (string) amount of days the key will be stored \n"
547 " \"key\": \"xxxxx\", (numeric) stored key\n"
38e9a59c 548 " \"keylen\": xxxxx, (numeric) length of the key\n"
6f3db929
A
549 " \"value\": \"xxxxx\" (numeric) stored value\n"
550 " \"valuesize\": xxxxx, (string) length of the stored value\n"
38e9a59c 551 " \"fee\": xxxxx (string) transaction fee paid to store the key\n"
6f3db929 552 " \"txid\": \"xxxxx\" (string) transaction id\n"
38e9a59c
A
553 "}\n"
554 "\nExamples:\n"
555 + HelpExampleCli("kvupdate", "examplekey \"examplevalue\" 2 examplepassphrase")
556 + HelpExampleRpc("kvupdate", "examplekey \"examplevalue\" 2 examplepassphrase")
557 );
ab6e81ec 558 if (!EnsureWalletIsAvailable(fHelp))
559 return 0;
3e71f585 560 if ( ASSETCHAINS_SYMBOL[0] == 0 )
561 return(0);
ad2c025a 562 haveprivkey = 0;
563 memset(&sig,0,sizeof(sig));
564 memset(&privkey,0,sizeof(privkey));
3bd13500 565 memset(&refpubkey,0,sizeof(refpubkey));
ad2c025a 566 memset(&pubkey,0,sizeof(pubkey));
c929bc3e 567 if ( (n= (int32_t)params.size()) >= 3 )
3b4652ca 568 {
1919e9de 569 flags = atoi(params[2].get_str().c_str());
ebeae1eb 570 //printf("flags.%d (%s) n.%d\n",flags,params[2].get_str().c_str(),n);
3b4652ca 571 } else flags = 0;
c929bc3e 572 if ( n >= 4 )
66dc0c54 573 privkey = komodo_kvprivkey(&pubkey,(char *)(n >= 4 ? params[3].get_str().c_str() : "password"));
574 haveprivkey = 1;
575 flags |= 1;
ebeae1eb 576 /*for (i=0; i<32; i++)
66dc0c54 577 printf("%02x",((uint8_t *)&privkey)[i]);
578 printf(" priv, ");
579 for (i=0; i<32; i++)
580 printf("%02x",((uint8_t *)&pubkey)[i]);
581 printf(" pubkey, privkey derived from (%s)\n",(char *)params[3].get_str().c_str());
ebeae1eb 582 */
ab6e81ec 583 LOCK2(cs_main, pwalletMain->cs_wallet);
584 if ( (keylen= (int32_t)strlen(params[0].get_str().c_str())) > 0 )
585 {
586 key = (uint8_t *)params[0].get_str().c_str();
c929bc3e 587 if ( n >= 2 && params[1].get_str().c_str() != 0 )
51ff33a4 588 {
589 value = (uint8_t *)params[1].get_str().c_str();
590 valuesize = (int32_t)strlen(params[1].get_str().c_str());
591 }
6b5cfbb4 592 memcpy(keyvalue,key,keylen);
4b729ec5 593 if ( (refvaluesize= komodo_kvsearch(&refpubkey,chainActive.LastTip()->GetHeight(),&tmpflags,&height,&keyvalue[keylen],key,keylen)) >= 0 )
05cbbacf 594 {
6b5cfbb4 595 if ( (tmpflags & KOMODO_KVPROTECTED) != 0 )
596 {
ebeae1eb 597 if ( memcmp(&refpubkey,&pubkey,sizeof(refpubkey)) != 0 )
6b5cfbb4 598 {
599 ret.push_back(Pair("error",(char *)"cant modify write once key without passphrase"));
600 return ret;
601 }
6b5cfbb4 602 }
55791792 603 if ( keylen+refvaluesize <= sizeof(keyvalue) )
e2843ac1 604 {
55791792 605 sig = komodo_kvsig(keyvalue,keylen+refvaluesize,privkey);
e2843ac1 606 if ( komodo_kvsigverify(keyvalue,keylen+refvaluesize,refpubkey,sig) < 0 )
ebeae1eb 607 {
608 ret.push_back(Pair("error",(char *)"error verifying sig, passphrase is probably wrong"));
e2843ac1 609 printf("VERIFY ERROR\n");
ebeae1eb 610 return ret;
611 } // else printf("verified immediately\n");
e2843ac1 612 }
05cbbacf 613 }
ebeae1eb 614 //for (i=0; i<32; i++)
615 // printf("%02x",((uint8_t *)&sig)[i]);
616 //printf(" sig for keylen.%d + valuesize.%d\n",keylen,refvaluesize);
ab6e81ec 617 ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)));
4b729ec5 618 height = chainActive.LastTip()->GetHeight();
6b5cfbb4 619 if ( memcmp(&zeroes,&refpubkey,sizeof(refpubkey)) != 0 )
620 ret.push_back(Pair("owner",refpubkey.GetHex()));
368da363 621 ret.push_back(Pair("height", (int64_t)height));
6b5cfbb4 622 duration = komodo_kvduration(flags); //((flags >> 2) + 1) * KOMODO_KVDURATION;
a6b182bd 623 ret.push_back(Pair("expiration", (int64_t)(height+duration)));
05cbbacf 624 ret.push_back(Pair("flags",(int64_t)flags));
ab6e81ec 625 ret.push_back(Pair("key",params[0].get_str()));
05cbbacf 626 ret.push_back(Pair("keylen",(int64_t)keylen));
c929bc3e 627 if ( n >= 2 && params[1].get_str().c_str() != 0 )
ab6e81ec 628 {
b9ecd81f 629 ret.push_back(Pair("value",params[1].get_str()));
630 ret.push_back(Pair("valuesize",valuesize));
ab6e81ec 631 }
632 iguana_rwnum(1,&keyvalue[0],sizeof(keylen),&keylen);
633 iguana_rwnum(1,&keyvalue[2],sizeof(valuesize),&valuesize);
368da363 634 iguana_rwnum(1,&keyvalue[4],sizeof(height),&height);
1919e9de 635 iguana_rwnum(1,&keyvalue[8],sizeof(flags),&flags);
636 memcpy(&keyvalue[12],key,keylen);
ab6e81ec 637 if ( value != 0 )
1919e9de 638 memcpy(&keyvalue[12 + keylen],value,valuesize);
6b5cfbb4 639 coresize = (int32_t)(sizeof(flags)+sizeof(height)+sizeof(uint16_t)*2+keylen+valuesize);
640 if ( haveprivkey != 0 )
641 {
642 for (i=0; i<32; i++)
643 keyvalue[12 + keylen + valuesize + i] = ((uint8_t *)&pubkey)[i];
644 coresize += 32;
645 if ( refvaluesize >=0 )
646 {
647 for (i=0; i<32; i++)
648 keyvalue[12 + keylen + valuesize + 32 + i] = ((uint8_t *)&sig)[i];
649 coresize += 32;
650 }
651 }
652 if ( (opretlen= komodo_opreturnscript(opretbuf,'K',keyvalue,coresize)) == 40 )
0b748e97 653 opretlen++;
1919e9de 654 //for (i=0; i<opretlen; i++)
655 // printf("%02x",opretbuf[i]);
656 //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 657 EnsureWalletIsUnlocked();
6b5cfbb4 658 fee = komodo_kvfee(flags,opretlen,keylen);
a6b182bd 659 ret.push_back(Pair("fee",(double)fee/COIN));
ab6e81ec 660 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
661 if (!destaddress.IsValid())
662 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
6685bab2 663 SendMoney(destaddress.Get(),10000,false,wtx,opretbuf,opretlen,fee);
a42fa6cf 664 ret.push_back(Pair("txid",wtx.GetHash().GetHex()));
1919e9de 665 } else ret.push_back(Pair("error",(char *)"null key"));
ab6e81ec 666 return ret;
667}
668
14f3daa6 669UniValue paxdeposit(const UniValue& params, bool fHelp)
c929bc3e 670{
671 uint64_t available,deposited,issued,withdrawn,approved,redeemed,seed,komodoshis = 0; int32_t height; char destaddr[64]; uint8_t i,pubkey37[33];
672 bool fSubtractFeeFromAmount = false;
43430608 673 if ( KOMODO_PAX == 0 )
e9d73912 674 {
b92d9db1 675 throw runtime_error("paxdeposit disabled without -pax");
e9d73912 676 }
c929bc3e 677 if ( komodo_is_issuer() != 0 )
678 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "paxdeposit only from KMD");
679 if (!EnsureWalletIsAvailable(fHelp))
4e5be259 680 throw runtime_error("paxdeposit needs wallet"); //return Value::null;
c929bc3e 681 if (fHelp || params.size() != 3)
682 throw runtime_error("paxdeposit address fiatoshis base");
683 LOCK2(cs_main, pwalletMain->cs_wallet);
684 CBitcoinAddress address(params[0].get_str());
685 if (!address.IsValid())
686 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
82fd1939 687 int64_t fiatoshis = atof(params[1].get_str().c_str()) * COIN;
c929bc3e 688 std::string base = params[2].get_str();
689 std::string dest;
4b729ec5 690 height = chainActive.LastTip()->GetHeight();
82fd1939 691 if ( pax_fiatstatus(&available,&deposited,&issued,&withdrawn,&approved,&redeemed,(char *)base.c_str()) != 0 || available < fiatoshis )
ea73ef00 692 {
f79f75be 693 fprintf(stderr,"available %llu vs fiatoshis %llu\n",(long long)available,(long long)fiatoshis);
82fd1939 694 throw runtime_error("paxdeposit not enough available inventory");
ea73ef00 695 }
c929bc3e 696 komodoshis = PAX_fiatdest(&seed,0,destaddr,pubkey37,(char *)params[0].get_str().c_str(),height,(char *)base.c_str(),fiatoshis);
697 dest.append(destaddr);
698 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
699 if (!destaddress.IsValid())
700 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
701 for (i=0; i<33; i++)
702 fprintf(stderr,"%02x",pubkey37[i]);
703 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);
704 EnsureWalletIsUnlocked();
705 CWalletTx wtx;
706 uint8_t opretbuf[64]; int32_t opretlen; uint64_t fee = komodoshis / 1000;
707 if ( fee < 10000 )
708 fee = 10000;
709 iguana_rwnum(1,&pubkey37[33],sizeof(height),&height);
710 opretlen = komodo_opreturnscript(opretbuf,'D',pubkey37,37);
711 SendMoney(address.Get(),fee,fSubtractFeeFromAmount,wtx,opretbuf,opretlen,komodoshis);
712 return wtx.GetHash().GetHex();
713}
714
14f3daa6 715UniValue paxwithdraw(const UniValue& params, bool fHelp)
c929bc3e 716{
717 CWalletTx wtx; std::string dest; int32_t kmdheight; uint64_t seed,komodoshis = 0; char destaddr[64]; uint8_t i,pubkey37[37]; bool fSubtractFeeFromAmount = false;
718 if ( ASSETCHAINS_SYMBOL[0] == 0 )
719 return(0);
720 if (!EnsureWalletIsAvailable(fHelp))
721 return 0;
16c7bf6b 722 throw runtime_error("paxwithdraw deprecated");
c929bc3e 723 if (fHelp || params.size() != 2)
724 throw runtime_error("paxwithdraw address fiatamount");
725 if ( komodo_isrealtime(&kmdheight) == 0 )
726 return(0);
727 LOCK2(cs_main, pwalletMain->cs_wallet);
728 CBitcoinAddress address(params[0].get_str());
729 if (!address.IsValid())
730 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
731 int64_t fiatoshis = atof(params[1].get_str().c_str()) * COIN;
732 komodoshis = PAX_fiatdest(&seed,1,destaddr,pubkey37,(char *)params[0].get_str().c_str(),kmdheight,ASSETCHAINS_SYMBOL,fiatoshis);
733 dest.append(destaddr);
734 CBitcoinAddress destaddress(CRYPTO777_KMDADDR);
735 if (!destaddress.IsValid())
736 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid dest Bitcoin address");
737 for (i=0; i<33; i++)
738 printf("%02x",pubkey37[i]);
739 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);
740 EnsureWalletIsUnlocked();
741 uint8_t opretbuf[64]; int32_t opretlen; uint64_t fee = fiatoshis / 1000;
742 if ( fee < 10000 )
743 fee = 10000;
744 iguana_rwnum(1,&pubkey37[33],sizeof(kmdheight),&kmdheight);
745 opretlen = komodo_opreturnscript(opretbuf,'W',pubkey37,37);
746 SendMoney(destaddress.Get(),fee,fSubtractFeeFromAmount,wtx,opretbuf,opretlen,fiatoshis);
747 return wtx.GetHash().GetHex();
748}
749
d014114d 750UniValue listaddressgroupings(const UniValue& params, bool fHelp)
22dfd735 751{
b9fb692d 752 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 753 return NullUniValue;
9d365796 754
22dfd735 755 if (fHelp)
b1093efa
GM
756 throw runtime_error(
757 "listaddressgroupings\n"
a6099ef3 758 "\nLists groups of addresses which have had their common ownership\n"
b1093efa 759 "made public by common use as inputs or as the resulting change\n"
a6099ef3 760 "in past transactions\n"
761 "\nResult:\n"
762 "[\n"
763 " [\n"
764 " [\n"
1333d0d7 765 " \"" + strprintf("%s",komodo_chainname()) + " address\", (string) The " + strprintf("%s",komodo_chainname()) + " address\n"
766 " amount, (numeric) The amount in " + strprintf("%s",komodo_chainname()) + "\n"
7b782f5b 767 " \"account\" (string, optional) The account (DEPRECATED)\n"
a6099ef3 768 " ]\n"
769 " ,...\n"
770 " ]\n"
771 " ,...\n"
772 "]\n"
773 "\nExamples:\n"
774 + HelpExampleCli("listaddressgroupings", "")
775 + HelpExampleRpc("listaddressgroupings", "")
776 );
22dfd735 777
4401b2d7
EL
778 LOCK2(cs_main, pwalletMain->cs_wallet);
779
38fc4b70 780 UniValue jsonGroupings(UniValue::VARR);
07444da1
PW
781 std::map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
782 for (const std::set<CTxDestination>& grouping : pwalletMain->GetAddressGroupings()) {
38fc4b70 783 UniValue jsonGrouping(UniValue::VARR);
07444da1 784 for (const CTxDestination& address : grouping)
22dfd735 785 {
38fc4b70 786 UniValue addressInfo(UniValue::VARR);
07444da1 787 addressInfo.push_back(EncodeDestination(address));
22dfd735 788 addressInfo.push_back(ValueFromAmount(balances[address]));
789 {
07444da1
PW
790 if (pwalletMain->mapAddressBook.find(address) != pwalletMain->mapAddressBook.end()) {
791 addressInfo.push_back(pwalletMain->mapAddressBook.find(address)->second.name);
792 }
22dfd735 793 }
794 jsonGrouping.push_back(addressInfo);
795 }
796 jsonGroupings.push_back(jsonGrouping);
797 }
798 return jsonGroupings;
799}
800
c8c684e9 801CIdentitySignature::ESignatureVerification CIdentitySignature::AddSignature(const CIdentity &signingID,
802 const std::vector<uint160> &vdxfCodes,
803 const std::vector<uint256> &statements,
804 const uint160 &systemID,
805 uint32_t height,
806 const std::string &prefixString,
807 const uint256 &msgHash,
808 const CKeyStore *pWallet)
809{
810 if (blockHeight != height)
811 {
812 return SIGNATURE_INVALID;
813 }
814
815 uint160 sID = signingID.GetID();
816 std::set<uint160> signatureIDs;
817 std::set<uint160> idKeys;
818 for (auto &oneKey : signingID.primaryAddresses)
819 {
820 if (oneKey.which() != COptCCParams::ADDRTYPE_PK && oneKey.which() != COptCCParams::ADDRTYPE_PKH)
821 {
822 return SIGNATURE_INVALID;
823 }
824 idKeys.insert(GetDestinationID(oneKey));
825 }
826
827 uint256 signatureHash = IdentitySignatureHash(vdxfCodes, statements, systemID, height, sID, prefixString, msgHash);
828
829 for (auto &oneSig : signatures)
830 {
831 CPubKey pubkey;
832 if (pubkey.RecoverCompact(signatureHash, oneSig))
833 {
834 uint160 pkID = pubkey.GetID();
835 // wrong signature means this is wrong
836 if (!idKeys.count(pkID))
837 {
838 return SIGNATURE_INVALID;
839 }
840 signatureIDs.insert(pkID);
841 }
842 }
843
844 for (auto &oneAddr : signingID.primaryAddresses)
845 {
846 CKeyID addrID = GetDestinationID(oneAddr);
847 if (signatureIDs.count(addrID))
848 {
849 continue;
850 }
851 CKey signingKey;
852 std::vector<unsigned char> newSig;
853 if (pWallet->GetKey(addrID, signingKey) && signingKey.SignCompact(signatureHash, newSig))
854 {
855 signatures.insert(newSig);
856 signatureIDs.insert(addrID);
857 }
858 }
859
860 if (signatureIDs.size() >= signingID.minSigs)
861 {
862 return SIGNATURE_COMPLETE;
863 }
864 else if (signatureIDs.size())
865 {
866 return SIGNATURE_PARTIAL;
867 }
868 else
869 {
870 return SIGNATURE_INVALID;
871 }
872}
873
874CIdentitySignature::ESignatureVerification CIdentitySignature::NewSignature(const CIdentity &signingID,
875 const std::vector<uint160> &vdxfCodes,
876 const std::vector<uint256> &statements,
877 const uint160 &systemID,
878 uint32_t height,
879 const std::string &prefixString,
880 const uint256 &msgHash,
881 const CKeyStore *pWallet)
882{
883 signatures.clear();
884 blockHeight = height;
885 return AddSignature(signingID, vdxfCodes, statements, systemID, height, prefixString, msgHash, pWallet);
886}
887
02b4ca7e 888std::string SignMessageHash(const CIdentity &identity, const uint256 &_msgHash, const std::string &signatureStr, uint32_t blockHeight)
7bc7344c 889{
890 int numSigs = 0;
891
892 CIdentitySignature signature;
893 bool fInvalid = false;
894
02b4ca7e 895 CHashWriterSHA256 ss(SER_GETHASH, PROTOCOL_VERSION);
896
897 ss << verusDataSignaturePrefix;
56fe75cb 898 ss << ConnectedChains.ThisChain().GetID();
02b4ca7e 899 ss << blockHeight;
900 ss << identity.GetID();
901 ss << _msgHash;
902
903 uint256 msgHash = ss.GetHash();
904
7bc7344c 905 // get the signature, a hex string, which is deserialized into an instance of the ID signature class
906 std::vector<unsigned char> sigVec;
907 try
908 {
909 sigVec = DecodeBase64(signatureStr.c_str(), &fInvalid);
910 if (fInvalid)
911 {
912 sigVec.clear();
913 }
914
915 if (sigVec.size())
916 {
917 signature = CIdentitySignature(sigVec);
918 }
919 }
920 catch(const std::exception& e)
921 {
922 std::cerr << e.what() << '\n';
923 sigVec.clear();
924 signature = CIdentitySignature();
925 }
926
6f679e45 927 signature.blockHeight = blockHeight;
7bc7344c 928
929 std::set<uint160> signatureKeyIDs;
6f679e45 930 std::map<uint160, std::vector<unsigned char>> signatureMap;
7bc7344c 931
932 for (auto &oneSig : signature.signatures)
933 {
934 CPubKey pubkey;
6f679e45 935 if (pubkey.RecoverCompact(msgHash, oneSig))
7bc7344c 936 {
937 uint160 pkID = pubkey.GetID();
6f679e45 938 signatureKeyIDs.insert(pkID);
939 signatureMap[pkID] = oneSig;
7bc7344c 940 }
941 }
942
7bc7344c 943 std::set<CKeyID> keysToTry;
944
945 // remove all valid addresses and count
946 for (auto &oneAddr : identity.primaryAddresses)
947 {
948 if (!(oneAddr.which() == COptCCParams::ADDRTYPE_PK || oneAddr.which() == COptCCParams::ADDRTYPE_PKH))
949 {
950 numSigs = 0;
951 break;
952 }
953 uint160 addrID = GetDestinationID(oneAddr);
954
955 if (signatureKeyIDs.count(addrID))
956 {
957 numSigs++;
958 signatureKeyIDs.erase(addrID);
959 if (!signatureKeyIDs.size())
960 {
961 break;
962 }
963 }
964 else
965 {
966 keysToTry.insert(addrID);
967 }
968 }
969
970 // if there are obsolete signatures, remove them
971 for (auto &oneSigID : signatureKeyIDs)
972 {
6f679e45 973 signatureMap.erase(oneSigID);
7bc7344c 974 }
975
976 int numSigsAdded = 0;
977 for (auto &oneKeyID : keysToTry)
978 {
979 CKey key;
980 if (pwalletMain->GetKey(oneKeyID, key)) {
981 vector<unsigned char> vchSig;
982 if (!key.SignCompact(msgHash, vchSig))
983 {
984 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Signing failed");
985 }
6f679e45 986 signatureMap[oneKeyID] = vchSig;
7bc7344c 987 numSigsAdded++;
988 numSigs++;
989 }
990 }
991
992 if (numSigs < identity.minSigs && !numSigsAdded)
993 {
994 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No private key available for additional signing");
995 }
996
6f679e45 997 // reset signatures from union of old and new in map
998 signature.signatures.clear();
999 for (auto &sigpair : signatureMap)
1000 {
1001 signature.signatures.insert(sigpair.second);
1002 }
1003
7bc7344c 1004 vector<unsigned char> vchSig = ::AsVector(signature);
1005
1006 // all signatures must be from valid keys, and if there are enough, it is valid
1007 return EncodeBase64(&vchSig[0], vchSig.size());
1008}
1009
02b4ca7e 1010UniValue signhash(const UniValue& params, bool fHelp)
1011{
1012 if (!EnsureWalletIsAvailable(fHelp))
1013 return NullUniValue;
1014
1015 if (fHelp || params.size() < 2 || params.size() > 3)
1016 throw runtime_error(
1017 "signhash \"address or identity\" \"hexhash\" \"curentsig\"\n"
1018 "\nSign a hexadecimal hash value with the private key of a t-addr or the authorities present in this wallet for an identity"
1019 + HelpRequiringPassphrase() + "\n"
1020 "\nNOTE: This API will only work for signing a data hash, but cannot properly sign the hash of a transaction\n"
1021 "\nArguments:\n"
1022 "1. \"t-addr or identity\" (string, required) The transparent address or identity to use for signing.\n"
1023 "2. \"hexhash\" (string, required) The hexadecimal hash to create a signature of.\n"
1024 "2. \"cursig\" (string) The current signature of the message encoded in base 64 if multisig ID\n"
1025 "\nResult:\n"
1026 "\"signature\" (string) The aggregate signature of the message encoded in base 64 if all or partial signing successful\n"
1027 "\nExamples:\n"
1028 "\nUnlock the wallet for 30 seconds\n"
1029 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
1030 "\nCreate the signature\n"
1031 + HelpExampleCli("signhash", "\"idname@\" \"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f\"") +
1032 "\nVerify the signature\n"
1033 + HelpExampleCli("verifyhash", "\"idname@\" \"signature\" \"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f\"") +
1034 "\nAs json rpc\n"
1035 + HelpExampleRpc("signhash", "\"idname@\", \"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f\"")
1036 );
1037
1038 LOCK2(cs_main, pwalletMain->cs_wallet);
1039
1040 EnsureWalletIsUnlocked();
1041
1042 string strAddress = params[0].get_str();
1043 string strHash = params[1].get_str();
1044
1045 bool fInvalid = false;
1046 uint256 msgHash;
1047
1048 CTxDestination destination = DecodeDestination(strAddress);
1049 if (!IsValidDestination(destination)) {
1050 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
1051 }
1052
1053 if (!strHash.size())
1054 {
1055 throw JSONRPCError(RPC_INVALID_PARAMETER, "No hash to verify");
1056 }
1057
1058 try
1059 {
1060 msgHash = uint256S(strHash.c_str());
1061 }
1062 catch(const std::exception& e)
1063 {
1064 throw JSONRPCError(RPC_INVALID_PARAMETER, "hexhash must be a valid, 32 byte hexadecimal hash value");
1065 }
1066
1067 // we expect the hash passed in to be reversed for compatibility with hashing tools
1068 // such as sha256sum
1069 std::reverse(msgHash.begin(), msgHash.end());
1070
1071 CTxDestination dest = DecodeDestination(strAddress);
1072 if (!IsValidDestination(dest)) {
1073 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address or identity");
1074 }
1075
1076 if (dest.which() == COptCCParams::ADDRTYPE_ID)
1077 {
1078 std::string strSign = params.size() > 2 ? uni_get_str(params[2]) : "";
1079
1080 CIdentity identity;
1081
1082 identity = CIdentity::LookupIdentity(GetDestinationID(dest));
1083 if (identity.IsValidUnrevoked())
1084 {
1085 uint32_t blockHeight = (uint32_t)chainActive.Height();
1086
1087 UniValue ret(UniValue::VOBJ);
1088 std::string sig = SignMessageHash(identity, msgHash, strSign, blockHeight);
1089 std::reverse(msgHash.begin(), msgHash.end()); // return a reversed hash for compatibility with sha256sum
1090 ret.push_back(Pair("hash", msgHash.GetHex()));
1091 ret.push_back(Pair("signature", sig));
1092 return ret;
1093 }
1094 else if (!identity.IsValid())
1095 {
1096 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid identity");
1097 }
1098 else
1099 {
1100 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Identity is revoked and cannot sign");
1101 }
1102 }
1103 else
1104 {
1105 const CKeyID *keyID = boost::get<CKeyID>(&dest);
1106 if (!keyID) {
1107 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
1108 }
1109
1110 CKey key;
1111 if (!pwalletMain->GetKey(*keyID, key)) {
1112 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
1113 }
1114
1115 CHashWriterSHA256 ss(SER_GETHASH, PROTOCOL_VERSION);
1116 ss << verusDataSignaturePrefix;
1117 ss << msgHash;
1118
1119 vector<unsigned char> vchSig;
1120
1121 if (!key.SignCompact(ss.GetHash(), vchSig))
1122 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
1123
1124 UniValue ret(UniValue::VOBJ);
1125 std::reverse(msgHash.begin(), msgHash.end()); // return a reversed hash for compatibility reasons
1126 ret.push_back(Pair("hash", msgHash.GetHex()));
1127 ret.push_back(Pair("signature", EncodeBase64(&vchSig[0], vchSig.size())));
1128 return ret;
1129 }
1130}
1131
d014114d 1132UniValue signmessage(const UniValue& params, bool fHelp)
e3bc5698 1133{
b9fb692d 1134 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1135 return NullUniValue;
9d365796 1136
67aa7dd4 1137 if (fHelp || params.size() < 2 || params.size() > 3)
e3bc5698 1138 throw runtime_error(
7bc7344c 1139 "signmessage \"address or identity\" \"message\" \"curentsig\"\n"
1713d73a 1140 "\nSign a message with the private key of a t-addr or the authorities present in this wallet for an identity"
a6099ef3 1141 + HelpRequiringPassphrase() + "\n"
1142 "\nArguments:\n"
67aa7dd4 1143 "1. \"t-addr or identity\" (string, required) The transparent address or identity to use for signing.\n"
02b4ca7e 1144 "2. \"message\" (string, required) The message to create a signature of.\n"
1145 "2. \"cursig\" (string) The current signature of the message encoded in base 64 if multisig ID\n"
a6099ef3 1146 "\nResult:\n"
02b4ca7e 1147 "{\n"
1148 " \"hash\":\"hexhash\" (string) The hash of the message (SHA256, NOT SHA256D)\n"
1149 " \"signature\":\"base64sig\" (string) The aggregate signature of the message encoded in base 64 if all or partial signing successful\n"
1150 "}\n"
a6099ef3 1151 "\nExamples:\n"
1152 "\nUnlock the wallet for 30 seconds\n"
1153 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
1154 "\nCreate the signature\n"
1333d0d7 1155 + HelpExampleCli("signmessage", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"my message\"") +
a6099ef3 1156 "\nVerify the signature\n"
1333d0d7 1157 + HelpExampleCli("verifymessage", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"signature\" \"my message\"") +
a6099ef3 1158 "\nAs json rpc\n"
1333d0d7 1159 + HelpExampleRpc("signmessage", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"my message\"")
a6099ef3 1160 );
e3bc5698 1161
4401b2d7
EL
1162 LOCK2(cs_main, pwalletMain->cs_wallet);
1163
e3bc5698
JG
1164 EnsureWalletIsUnlocked();
1165
1166 string strAddress = params[0].get_str();
1167 string strMessage = params[1].get_str();
1168
07444da1
PW
1169 CTxDestination dest = DecodeDestination(strAddress);
1170 if (!IsValidDestination(dest)) {
1713d73a 1171 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address or identity");
07444da1 1172 }
e3bc5698 1173
67aa7dd4 1174 if (dest.which() == COptCCParams::ADDRTYPE_ID)
1175 {
5d92da97 1176 std::string strSign = params.size() > 2 ? uni_get_str(params[2]) : "";
67aa7dd4 1177
7bc7344c 1178 CIdentity identity;
67aa7dd4 1179
7bc7344c 1180 identity = CIdentity::LookupIdentity(GetDestinationID(dest));
1181 if (identity.IsValidUnrevoked())
67aa7dd4 1182 {
6f679e45 1183 uint32_t blockHeight = (uint32_t)chainActive.Height();
02b4ca7e 1184 CHashWriterSHA256 ss(SER_GETHASH, PROTOCOL_VERSION);
67aa7dd4 1185 ss << strMessage;
67aa7dd4 1186 uint256 msgHash = ss.GetHash();
02b4ca7e 1187 std::string sig = SignMessageHash(identity, msgHash, strSign, blockHeight);
67aa7dd4 1188
02b4ca7e 1189 UniValue ret(UniValue::VOBJ);
1190 std::reverse(msgHash.begin(), msgHash.end()); // return a reversed hash for compatibility with sha256sum
1191 ret.push_back(Pair("hash", msgHash.GetHex()));
1192 ret.push_back(Pair("signature", sig));
1193 return ret;
7bc7344c 1194 }
1195 else if (!identity.IsValid())
1196 {
1197 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid identity");
1198 }
1199 else
1200 {
1201 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Identity is revoked and cannot sign");
67aa7dd4 1202 }
67aa7dd4 1203 }
1204 else
1205 {
1206 const CKeyID *keyID = boost::get<CKeyID>(&dest);
1207 if (!keyID) {
1208 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
1209 }
1210
1211 CKey key;
1212 if (!pwalletMain->GetKey(*keyID, key)) {
1213 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
1214 }
1215
02b4ca7e 1216 CHashWriterSHA256 ss(SER_GETHASH, PROTOCOL_VERSION);
67aa7dd4 1217 ss << strMessage;
02b4ca7e 1218 uint256 msgHash = ss.GetHash();
67aa7dd4 1219
02b4ca7e 1220 ss.Reset();
1221 ss << verusDataSignaturePrefix;
1222 ss << msgHash;
1223
67aa7dd4 1224 vector<unsigned char> vchSig;
1225 if (!key.SignCompact(ss.GetHash(), vchSig))
1226 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
1227
02b4ca7e 1228 UniValue ret(UniValue::VOBJ);
1229 std::reverse(msgHash.begin(), msgHash.end()); // return a reversed hash for compatibility reasons
1230 ret.push_back(Pair("hash", msgHash.GetHex()));
1231 ret.push_back(Pair("signature", EncodeBase64(&vchSig[0], vchSig.size())));
1232 return ret;
67aa7dd4 1233 }
1234}
1235
02b4ca7e 1236uint256 HashFile(std::string filepath);
1237
b90dccec 1238bool printoutAPI = false;
1239UniValue printapis(const UniValue& params, bool fHelp)
1240{
1241 if (fHelp || params.size() != 1)
1242 throw runtime_error(
1243 "printapis trueorfalse\n"
1244 "\nPrints the name of all APIs if parameter is true"
1245
1246 "\nResult:\n"
1247 ""
1248 "\nExamples:\n"
1249 + HelpExampleCli("signfile", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"filepath/filename\"") +
1250 "\nVerify the signature\n"
1251 + HelpExampleCli("verifyfile", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"signature\" \"filepath/filename\"") +
1252 "\nAs json rpc\n"
1253 + HelpExampleRpc("signfile", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"filepath/filename\"")
1254 );
1255 printoutAPI = uni_get_bool(params[0]);
d78b5e19 1256 return NullUniValue;
b90dccec 1257}
1258
7bc7344c 1259UniValue signfile(const UniValue& params, bool fHelp)
67aa7dd4 1260{
1261 if (!EnsureWalletIsAvailable(fHelp))
1262 return NullUniValue;
1263
7bc7344c 1264 if (fHelp || params.size() < 2 || params.size() > 3)
67aa7dd4 1265 throw runtime_error(
5b29ef68 1266 "signfile \"address or identity\" \"filepath/filename\" \"curentsig\"\n"
7bc7344c 1267 "\nGenerates a SHA256D hash of the file, returns the hash, and signs the hash with the private key specified"
67aa7dd4 1268 + HelpRequiringPassphrase() + "\n"
1269 "\nArguments:\n"
7bc7344c 1270 "1. \"t-addr or identity\" (string, required) The transparent address or identity to use for signing.\n"
1271 "2. \"filename\" (string, required) Local file to sign\n"
1272 "2. \"cursig\" (string) The current signature of the message encoded in base 64 if multisig ID\n"
67aa7dd4 1273 "\nResult:\n"
7bc7344c 1274 "{\n"
02b4ca7e 1275 " \"hash\":\"hexhash\" (string) The hash of the message (SHA256, NOT SHA256D)\n"
1276 " \"signature\":\"base64sig\" (string) The aggregate signature of the message encoded in base 64 if all or partial signing successful\n"
7bc7344c 1277 "}\n"
67aa7dd4 1278 "\nExamples:\n"
67aa7dd4 1279 "\nCreate the signature\n"
02b4ca7e 1280 + HelpExampleCli("signfile", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"filepath/filename\"") +
67aa7dd4 1281 "\nVerify the signature\n"
02b4ca7e 1282 + HelpExampleCli("verifyfile", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"signature\" \"filepath/filename\"") +
67aa7dd4 1283 "\nAs json rpc\n"
02b4ca7e 1284 + HelpExampleRpc("signfile", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"filepath/filename\"")
67aa7dd4 1285 );
1286
1287 LOCK2(cs_main, pwalletMain->cs_wallet);
1713d73a 1288
67aa7dd4 1289 EnsureWalletIsUnlocked();
1290
1291 string strAddress = params[0].get_str();
7bc7344c 1292 string strFileName = params[1].get_str();
67aa7dd4 1293
1294 CTxDestination dest = DecodeDestination(strAddress);
1295 if (!IsValidDestination(dest)) {
1296 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address or identity");
1297 }
1713d73a 1298
7bc7344c 1299 if (dest.which() == COptCCParams::ADDRTYPE_ID)
1300 {
5d92da97 1301 string strSign = params.size() > 2 ? uni_get_str(params[2]) : "";
7bc7344c 1302
1303 CIdentity identity;
1304
1305 identity = CIdentity::LookupIdentity(GetDestinationID(dest));
1306 if (identity.IsValidUnrevoked())
1307 {
02b4ca7e 1308 CHashWriterSHA256 ss(SER_GETHASH, PROTOCOL_VERSION);
1309 uint256 msgHash = HashFile(strFileName);
1310 if (msgHash.IsNull())
7bc7344c 1311 {
02b4ca7e 1312 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot open file " + strFileName);
7bc7344c 1313 }
1314 else
1315 {
02b4ca7e 1316 std::string sig = SignMessageHash(identity, msgHash, strSign, (uint32_t)chainActive.Height());
1317
1318 UniValue ret(UniValue::VOBJ);
1319 std::reverse(msgHash.begin(), msgHash.end()); // return a reversed hash for compatibility with sha256sum
1320 ret.push_back(Pair("hash", msgHash.GetHex()));
1321 ret.push_back(Pair("signature", sig));
1322 return ret;
7bc7344c 1323 }
1324 }
1325 else if (!identity.IsValid())
1326 {
1327 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid identity");
1328 }
1329 else
1330 {
1331 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Identity is revoked and cannot sign");
1332 }
07444da1 1333 }
7bc7344c 1334 else
1335 {
1336 const CKeyID *keyID = boost::get<CKeyID>(&dest);
1337 if (!keyID) {
1338 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
1339 }
1340
1341 CKey key;
1342 if (!pwalletMain->GetKey(*keyID, key)) {
1343 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
1344 }
1345
02b4ca7e 1346 CHashWriterSHA256 ss(SER_GETHASH, PROTOCOL_VERSION);
1347 uint256 msgHash = HashFile(strFileName);
1348 if (msgHash.IsNull())
7bc7344c 1349 {
02b4ca7e 1350 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot open file " + strFileName);
7bc7344c 1351 }
1352 else
1353 {
02b4ca7e 1354 ss << verusDataSignaturePrefix;
1355 ss << msgHash;
7bc7344c 1356 }
e3bc5698 1357
7bc7344c 1358 vector<unsigned char> vchSig;
02b4ca7e 1359 if (!key.SignCompact(ss.GetHash(), vchSig))
7bc7344c 1360 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
e3bc5698 1361
02b4ca7e 1362 UniValue ret(UniValue::VOBJ);
1363 std::reverse(msgHash.begin(), msgHash.end()); // return a reversed hash for compatibility with sha256sum
1364 ret.push_back(Pair("hash", msgHash.GetHex()));
1365 ret.push_back(Pair("signature", EncodeBase64(&vchSig[0], vchSig.size())));
1366 return ret;
7bc7344c 1367 }
e3bc5698
JG
1368}
1369
d014114d 1370UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
e3bc5698 1371{
b9fb692d 1372 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1373 return NullUniValue;
9d365796 1374
e3bc5698
JG
1375 if (fHelp || params.size() < 1 || params.size() > 2)
1376 throw runtime_error(
1333d0d7 1377 "getreceivedbyaddress \"" + strprintf("%s",komodo_chainname()) + "_address\" ( minconf )\n"
1378 "\nReturns the total amount received by the given " + strprintf("%s",komodo_chainname()) + " address in transactions with at least minconf confirmations.\n"
a6099ef3 1379 "\nArguments:\n"
1333d0d7 1380 "1. \"" + strprintf("%s",komodo_chainname()) + "_address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address for transactions.\n"
a6099ef3 1381 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
1382 "\nResult:\n"
1333d0d7 1383 "amount (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received at this address.\n"
a6099ef3 1384 "\nExamples:\n"
1385 "\nThe amount from transactions with at least 1 confirmation\n"
1333d0d7 1386 + HelpExampleCli("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"") +
a6099ef3 1387 "\nThe amount including unconfirmed transactions, zero confirmations\n"
1333d0d7 1388 + HelpExampleCli("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0") +
c938fb1f 1389 "\nThe amount with at least 6 confirmations, very safe\n"
1333d0d7 1390 + HelpExampleCli("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 6") +
a6099ef3 1391 "\nAs a json rpc call\n"
1333d0d7 1392 + HelpExampleRpc("getreceivedbyaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", 6")
a6099ef3 1393 );
e3bc5698 1394
4401b2d7
EL
1395 LOCK2(cs_main, pwalletMain->cs_wallet);
1396
e3bc5698 1397 // Bitcoin address
07444da1
PW
1398 CTxDestination dest = DecodeDestination(params[0].get_str());
1399 if (!IsValidDestination(dest)) {
5ae5090d 1400 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Verus address");
07444da1
PW
1401 }
1402 CScript scriptPubKey = GetScriptForDestination(dest);
1403 if (!IsMine(*pwalletMain, scriptPubKey)) {
b37b4b2f 1404 return ValueFromAmount(0);
07444da1 1405 }
e3bc5698
JG
1406
1407 // Minimum confirmations
1408 int nMinDepth = 1;
1409 if (params.size() > 1)
1410 nMinDepth = params[1].get_int();
1411
1412 // Tally
a372168e 1413 CAmount nAmount = 0;
e3bc5698
JG
1414 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1415 {
1416 const CWalletTx& wtx = (*it).second;
75a4d512 1417 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
1418 continue;
1419
1420 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1421 if (txout.scriptPubKey == scriptPubKey)
1422 if (wtx.GetDepthInMainChain() >= nMinDepth)
47658758 1423 nAmount += txout.nValue; // komodo_interest?
e3bc5698
JG
1424 }
1425
1426 return ValueFromAmount(nAmount);
1427}
1428
1429
d014114d 1430UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
e3bc5698 1431{
b9fb692d 1432 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1433 return NullUniValue;
9d365796 1434
e3bc5698
JG
1435 if (fHelp || params.size() < 1 || params.size() > 2)
1436 throw runtime_error(
a6099ef3 1437 "getreceivedbyaccount \"account\" ( minconf )\n"
7b782f5b 1438 "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
a6099ef3 1439 "\nArguments:\n"
3c31eb24 1440 "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 1441 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
1442 "\nResult:\n"
1333d0d7 1443 "amount (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received for this account.\n"
a6099ef3 1444 "\nExamples:\n"
1445 "\nAmount received by the default account with at least 1 confirmation\n"
1446 + HelpExampleCli("getreceivedbyaccount", "\"\"") +
1447 "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
1448 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
1449 "\nThe amount with at least 6 confirmation, very safe\n"
1450 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
1451 "\nAs a json rpc call\n"
1452 + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
1453 );
e3bc5698 1454
4401b2d7
EL
1455 LOCK2(cs_main, pwalletMain->cs_wallet);
1456
e3bc5698
JG
1457 // Minimum confirmations
1458 int nMinDepth = 1;
1459 if (params.size() > 1)
1460 nMinDepth = params[1].get_int();
1461
1462 // Get the set of pub keys assigned to account
1463 string strAccount = AccountFromValue(params[0]);
3624356e 1464 set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
e3bc5698
JG
1465
1466 // Tally
a372168e 1467 CAmount nAmount = 0;
e3bc5698
JG
1468 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1469 {
1470 const CWalletTx& wtx = (*it).second;
75a4d512 1471 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
1472 continue;
1473
1474 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1475 {
1476 CTxDestination address;
1477 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
1478 if (wtx.GetDepthInMainChain() >= nMinDepth)
47658758 1479 nAmount += txout.nValue; // komodo_interest?
e3bc5698
JG
1480 }
1481 }
1482
b37b4b2f 1483 return ValueFromAmount(nAmount);
e3bc5698
JG
1484}
1485
1486
a372168e 1487CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
e3bc5698 1488{
a372168e 1489 CAmount nBalance = 0;
e3bc5698
JG
1490
1491 // Tally wallet transactions
1492 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1493 {
1494 const CWalletTx& wtx = (*it).second;
75a4d512 1495 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
e3bc5698
JG
1496 continue;
1497
a372168e 1498 CAmount nReceived, nSent, nFee;
d4640d7d 1499 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
e3bc5698
JG
1500
1501 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1502 nBalance += nReceived;
e07c8e91 1503 nBalance -= nSent + nFee;
e3bc5698
JG
1504 }
1505
1506 // Tally internal accounting entries
1507 nBalance += walletdb.GetAccountCreditDebit(strAccount);
1508
1509 return nBalance;
1510}
1511
a372168e 1512CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
e3bc5698
JG
1513{
1514 CWalletDB walletdb(pwalletMain->strWalletFile);
d4640d7d 1515 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
e3bc5698
JG
1516}
1517
1518
d014114d 1519UniValue getbalance(const UniValue& params, bool fHelp)
e3bc5698 1520{
b9fb692d 1521 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1522 return NullUniValue;
9d365796 1523
d4640d7d 1524 if (fHelp || params.size() > 3)
e3bc5698 1525 throw runtime_error(
d4640d7d 1526 "getbalance ( \"account\" minconf includeWatchonly )\n"
3c31eb24 1527 "\nReturns the server's total available balance.\n"
a6099ef3 1528 "\nArguments:\n"
715e5bbe 1529 "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 1530 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
d4640d7d 1531 "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
a6099ef3 1532 "\nResult:\n"
1333d0d7 1533 "amount (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received for this account.\n"
a6099ef3 1534 "\nExamples:\n"
7b782f5b 1535 "\nThe total amount in the wallet\n"
a6099ef3 1536 + HelpExampleCli("getbalance", "") +
7b782f5b 1537 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3cf1f436 1538 + HelpExampleCli("getbalance", "\"*\" 6") +
a6099ef3 1539 "\nAs a json rpc call\n"
7b782f5b 1540 + HelpExampleRpc("getbalance", "\"*\", 6")
a6099ef3 1541 );
e3bc5698 1542
4401b2d7
EL
1543 LOCK2(cs_main, pwalletMain->cs_wallet);
1544
e3bc5698
JG
1545 if (params.size() == 0)
1546 return ValueFromAmount(pwalletMain->GetBalance());
1547
1548 int nMinDepth = 1;
1549 if (params.size() > 1)
1550 nMinDepth = params[1].get_int();
a3e192a3 1551 isminefilter filter = ISMINE_SPENDABLE;
a5c6c5d6
J
1552 if(params.size() > 2)
1553 if(params[2].get_bool())
efecad16 1554 filter = ISMINE_ALL;
e3bc5698
JG
1555
1556 if (params[0].get_str() == "*") {
1557 // Calculate total balance a different way from GetBalance()
1558 // (GetBalance() sums up all unspent TxOuts)
c9fd9078 1559 // getbalance and "getbalance * 1 true" should return the same number
a372168e 1560 CAmount nBalance = 0;
672414d7 1561 //CAmount altBalance = 0;
e3bc5698
JG
1562 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1563 {
1564 const CWalletTx& wtx = (*it).second;
c9fd9078 1565 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
e3bc5698
JG
1566 continue;
1567
a372168e 1568 CAmount allFee;
e3bc5698 1569 string strSentAccount;
1b4568cb
CL
1570 list<COutputEntry> listReceived;
1571 list<COutputEntry> listSent;
d4640d7d 1572 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
e3bc5698
JG
1573 if (wtx.GetDepthInMainChain() >= nMinDepth)
1574 {
672414d7 1575 //altBalance += wtx.GetAvailableCredit();
1b4568cb
CL
1576 BOOST_FOREACH(const COutputEntry& r, listReceived)
1577 nBalance += r.amount;
e3bc5698 1578 }
1b4568cb
CL
1579 BOOST_FOREACH(const COutputEntry& s, listSent)
1580 nBalance -= s.amount;
e3bc5698 1581 nBalance -= allFee;
e3bc5698 1582 }
672414d7 1583 //printf("alternate wallet balance: %s\n", ValueFromAmount(nBalance).write().c_str());
1584 return ValueFromAmount(nBalance);
e3bc5698
JG
1585 }
1586
1587 string strAccount = AccountFromValue(params[0]);
1588
a372168e 1589 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
e3bc5698
JG
1590
1591 return ValueFromAmount(nBalance);
1592}
1593
d014114d 1594UniValue getunconfirmedbalance(const UniValue &params, bool fHelp)
6027b460 1595{
b9fb692d 1596 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1597 return NullUniValue;
9d365796 1598
6027b460
MB
1599 if (fHelp || params.size() > 0)
1600 throw runtime_error(
1601 "getunconfirmedbalance\n"
1602 "Returns the server's total unconfirmed balance\n");
4401b2d7
EL
1603
1604 LOCK2(cs_main, pwalletMain->cs_wallet);
1605
6027b460
MB
1606 return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
1607}
1608
e3bc5698 1609
d014114d 1610UniValue movecmd(const UniValue& params, bool fHelp)
e3bc5698 1611{
b9fb692d 1612 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1613 return NullUniValue;
9d365796 1614
e3bc5698
JG
1615 if (fHelp || params.size() < 3 || params.size() > 5)
1616 throw runtime_error(
a6099ef3 1617 "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
7b782f5b 1618 "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
a6099ef3 1619 "\nArguments:\n"
3c31eb24
JG
1620 "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"
1621 "2. \"toaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1333d0d7 1622 "3. amount (numeric) Quantity of " + strprintf("%s",komodo_chainname()) + " to move between accounts.\n"
091b2116
RN
1623 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
1624 "5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
a6099ef3 1625 "\nResult:\n"
45bfa137 1626 "true|false (boolean) true if successful.\n"
a6099ef3 1627 "\nExamples:\n"
1333d0d7 1628 "\nMove 0.01 " + strprintf("%s",komodo_chainname()) + " from the default account to the account named tabby\n"
a6099ef3 1629 + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
1333d0d7 1630 "\nMove 0.01 " + strprintf("%s",komodo_chainname()) + " timotei to akiko with a comment and funds have 6 confirmations\n"
a6099ef3 1631 + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
1632 "\nAs a json rpc call\n"
1633 + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
1634 );
b310ffff 1635 if ( ASSETCHAINS_PRIVATE != 0 )
1636 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
e3bc5698 1637
4401b2d7
EL
1638 LOCK2(cs_main, pwalletMain->cs_wallet);
1639
e3bc5698
JG
1640 string strFrom = AccountFromValue(params[0]);
1641 string strTo = AccountFromValue(params[1]);
a372168e 1642 CAmount nAmount = AmountFromValue(params[2]);
e76a3849
WL
1643 if (nAmount <= 0)
1644 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
e3bc5698
JG
1645 if (params.size() > 3)
1646 // unused parameter, used to be nMinDepth, keep type-checking it though
1647 (void)params[3].get_int();
1648 string strComment;
1649 if (params.size() > 4)
1650 strComment = params[4].get_str();
1651
1652 CWalletDB walletdb(pwalletMain->strWalletFile);
1653 if (!walletdb.TxnBegin())
738835d7 1654 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
e3bc5698 1655
51ed9ec9 1656 int64_t nNow = GetAdjustedTime();
e3bc5698
JG
1657
1658 // Debit
1659 CAccountingEntry debit;
4291e8fe 1660 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
e3bc5698
JG
1661 debit.strAccount = strFrom;
1662 debit.nCreditDebit = -nAmount;
1663 debit.nTime = nNow;
1664 debit.strOtherAccount = strTo;
1665 debit.strComment = strComment;
1666 walletdb.WriteAccountingEntry(debit);
1667
1668 // Credit
1669 CAccountingEntry credit;
4291e8fe 1670 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
e3bc5698
JG
1671 credit.strAccount = strTo;
1672 credit.nCreditDebit = nAmount;
1673 credit.nTime = nNow;
1674 credit.strOtherAccount = strFrom;
1675 credit.strComment = strComment;
1676 walletdb.WriteAccountingEntry(credit);
1677
1678 if (!walletdb.TxnCommit())
738835d7 1679 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
e3bc5698
JG
1680
1681 return true;
1682}
1683
1684
d014114d 1685UniValue sendfrom(const UniValue& params, bool fHelp)
e3bc5698 1686{
b9fb692d 1687 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1688 return NullUniValue;
9d365796 1689
e3bc5698
JG
1690 if (fHelp || params.size() < 3 || params.size() > 6)
1691 throw runtime_error(
1333d0d7 1692 "sendfrom \"fromaccount\" \"to" + strprintf("%s",komodo_chainname()) + "address\" amount ( minconf \"comment\" \"comment-to\" )\n"
1693 "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a " + strprintf("%s",komodo_chainname()) + " address.\n"
a6099ef3 1694 "The amount is a real and is rounded to the nearest 0.00000001."
1695 + HelpRequiringPassphrase() + "\n"
1696 "\nArguments:\n"
3c31eb24 1697 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1333d0d7 1698 "2. \"to" + strprintf("%s",komodo_chainname()) + "address\" (string, required) The " + strprintf("%s",komodo_chainname()) + " address to send funds to.\n"
1699 "3. amount (numeric, required) The amount in " + strprintf("%s",komodo_chainname()) + " (transaction fee is added on top).\n"
a6099ef3 1700 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
1701 "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
1702 " This is not part of the transaction, just kept in your wallet.\n"
1703 "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n"
1704 " to which you're sending the transaction. This is not part of the transaction, \n"
1705 " it is just kept in your wallet.\n"
1706 "\nResult:\n"
b5ef85c7 1707 "\"transactionid\" (string) The transaction id.\n"
a6099ef3 1708 "\nExamples:\n"
1333d0d7 1709 "\nSend 0.01 " + strprintf("%s",komodo_chainname()) + " from the default account to the address, must have at least 1 confirmation\n"
1710 + HelpExampleCli("sendfrom", "\"\" \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.01") +
a6099ef3 1711 "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
1333d0d7 1712 + HelpExampleCli("sendfrom", "\"tabby\" \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 0.01 6 \"donation\" \"seans outpost\"") +
a6099ef3 1713 "\nAs a json rpc call\n"
1333d0d7 1714 + HelpExampleRpc("sendfrom", "\"tabby\", \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", 0.01, 6, \"donation\", \"seans outpost\"")
a6099ef3 1715 );
b310ffff 1716 if ( ASSETCHAINS_PRIVATE != 0 )
1717 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
e3bc5698 1718
4401b2d7
EL
1719 LOCK2(cs_main, pwalletMain->cs_wallet);
1720
07444da1 1721 std::string strAccount = AccountFromValue(params[0]);
aac91bcc 1722 CTxDestination dest = ValidateDestination(params[1].get_str());
07444da1 1723 if (!IsValidDestination(dest)) {
5ae5090d 1724 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Verus address");
07444da1 1725 }
a372168e 1726 CAmount nAmount = AmountFromValue(params[2]);
e76a3849
WL
1727 if (nAmount <= 0)
1728 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
e3bc5698
JG
1729 int nMinDepth = 1;
1730 if (params.size() > 3)
1731 nMinDepth = params[3].get_int();
1732
1733 CWalletTx wtx;
1734 wtx.strFromAccount = strAccount;
ed21d5bd 1735 if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty())
e3bc5698 1736 wtx.mapValue["comment"] = params[4].get_str();
ed21d5bd 1737 if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty())
e3bc5698
JG
1738 wtx.mapValue["to"] = params[5].get_str();
1739
1740 EnsureWalletIsUnlocked();
1741
1742 // Check funds
a372168e 1743 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
e3bc5698 1744 if (nAmount > nBalance)
738835d7 1745 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
e3bc5698 1746
9feb4b9e 1747 SendMoney(dest, nAmount, false, wtx, 0, 0, 0);
e3bc5698 1748
805344dc 1749 return wtx.GetHash().GetHex();
e3bc5698
JG
1750}
1751
1752
d014114d 1753UniValue sendmany(const UniValue& params, bool fHelp)
e3bc5698 1754{
b9fb692d 1755 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1756 return NullUniValue;
9d365796 1757
292623ad 1758 if (fHelp || params.size() < 2 || params.size() > 5)
e3bc5698 1759 throw runtime_error(
40a75733 1760 "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
92b42d28 1761 "\nSend multiple times. Amounts are decimal numbers with at most 8 digits of precision."
a6099ef3 1762 + HelpRequiringPassphrase() + "\n"
1763 "\nArguments:\n"
3c31eb24 1764 "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 1765 "2. \"amounts\" (string, required) A json object with addresses and amounts\n"
1766 " {\n"
1333d0d7 1767 " \"address\":amount (numeric) The " + strprintf("%s",komodo_chainname()) + " address is the key, the numeric amount in " + strprintf("%s",komodo_chainname()) + " is the value\n"
a6099ef3 1768 " ,...\n"
1769 " }\n"
1770 "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
1771 "4. \"comment\" (string, optional) A comment\n"
40a75733 1772 "5. subtractfeefromamount (string, optional) A json array with addresses.\n"
292623ad 1773 " The fee will be equally deducted from the amount of each selected address.\n"
1333d0d7 1774 " Those recipients will receive less " + strprintf("%s",komodo_chainname()) + " than you enter in their corresponding amount field.\n"
40a75733
LD
1775 " If no addresses are specified here, the sender pays the fee.\n"
1776 " [\n"
1777 " \"address\" (string) Subtract fee from this address\n"
292623ad 1778 " ,...\n"
40a75733 1779 " ]\n"
a6099ef3 1780 "\nResult:\n"
1781 "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
b5ef85c7 1782 " the number of addresses.\n"
a6099ef3 1783 "\nExamples:\n"
1784 "\nSend two amounts to two different addresses:\n"
1333d0d7 1785 + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\"") +
a6099ef3 1786 "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
1333d0d7 1787 + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\" 6 \"testing\"") +
292623ad 1788 "\nSend two amounts to two different addresses, subtract fee from amount:\n"
1333d0d7 1789 + HelpExampleCli("sendmany", "\"\" \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\" 1 \"\" \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"") +
a6099ef3 1790 "\nAs a json rpc call\n"
1333d0d7 1791 + HelpExampleRpc("sendmany", "\"\", \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\", 6, \"testing\"")
a6099ef3 1792 );
b310ffff 1793 if ( ASSETCHAINS_PRIVATE != 0 )
1794 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
e3bc5698 1795
4401b2d7
EL
1796 LOCK2(cs_main, pwalletMain->cs_wallet);
1797
e3bc5698 1798 string strAccount = AccountFromValue(params[0]);
851f58f9 1799 UniValue sendTo = params[1].get_obj();
e3bc5698
JG
1800 int nMinDepth = 1;
1801 if (params.size() > 2)
1802 nMinDepth = params[2].get_int();
1803
1804 CWalletTx wtx;
1805 wtx.strFromAccount = strAccount;
ed21d5bd 1806 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
e3bc5698
JG
1807 wtx.mapValue["comment"] = params[3].get_str();
1808
38fc4b70 1809 UniValue subtractFeeFromAmount(UniValue::VARR);
292623ad 1810 if (params.size() > 4)
40a75733 1811 subtractFeeFromAmount = params[4].get_array();
292623ad 1812
07444da1
PW
1813 std::set<CTxDestination> destinations;
1814 std::vector<CRecipient> vecSend;
e3bc5698 1815
a372168e 1816 CAmount totalAmount = 0;
07444da1
PW
1817 std::vector<std::string> keys = sendTo.getKeys();
1818 for (const std::string& name_ : keys) {
aac91bcc 1819 CTxDestination dest = ValidateDestination(name_);
07444da1 1820 if (!IsValidDestination(dest)) {
5ae5090d 1821 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Verus address: ") + name_);
07444da1 1822 }
e3bc5698 1823
07444da1
PW
1824 if (destinations.count(dest)) {
1825 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
1826 }
1827 destinations.insert(dest);
e3bc5698 1828
07444da1 1829 CScript scriptPubKey = GetScriptForDestination(dest);
ed21d5bd 1830 CAmount nAmount = AmountFromValue(sendTo[name_]);
e76a3849
WL
1831 if (nAmount <= 0)
1832 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
e3bc5698
JG
1833 totalAmount += nAmount;
1834
292623ad 1835 bool fSubtractFeeFromAmount = false;
cc71666a 1836 for (size_t idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
d014114d 1837 const UniValue& addr = subtractFeeFromAmount[idx];
9756b7bd 1838 if (addr.get_str() == name_)
292623ad 1839 fSubtractFeeFromAmount = true;
9756b7bd 1840 }
292623ad
CL
1841
1842 CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
1843 vecSend.push_back(recipient);
e3bc5698
JG
1844 }
1845
1846 EnsureWalletIsUnlocked();
1847
1848 // Check funds
170d7b7a 1849 CAmount nBalance = pwalletMain->GetBalance();
c83c59f9 1850 //CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
e3bc5698 1851 if (totalAmount > nBalance)
738835d7 1852 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
e3bc5698
JG
1853
1854 // Send
1855 CReserveKey keyChange(pwalletMain);
a372168e 1856 CAmount nFeeRequired = 0;
292623ad 1857 int nChangePosRet = -1;
1f00f4e9 1858 string strFailReason;
292623ad 1859 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
e3bc5698 1860 if (!fCreated)
1f00f4e9 1861 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
e3bc5698 1862 if (!pwalletMain->CommitTransaction(wtx, keyChange))
738835d7 1863 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
e3bc5698 1864
805344dc 1865 return wtx.GetHash().GetHex();
e3bc5698
JG
1866}
1867
4b184205 1868// Defined in rpc/misc.cpp
d014114d 1869extern CScript _createmultisig_redeemScript(const UniValue& params);
34226be7 1870
d014114d 1871UniValue addmultisigaddress(const UniValue& params, bool fHelp)
34226be7 1872{
b9fb692d 1873 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1874 return NullUniValue;
9d365796 1875
34226be7
GA
1876 if (fHelp || params.size() < 2 || params.size() > 3)
1877 {
a6099ef3 1878 string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
1879 "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
1333d0d7 1880 "Each key is a " + strprintf("%s",komodo_chainname()) + " address or hex-encoded public key.\n"
7b782f5b 1881 "If 'account' is specified (DEPRECATED), assign address to that account.\n"
a6099ef3 1882
1883 "\nArguments:\n"
1884 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
1333d0d7 1885 "2. \"keysobject\" (string, required) A json array of " + strprintf("%s",komodo_chainname()) + " addresses or hex-encoded public keys\n"
a6099ef3 1886 " [\n"
1333d0d7 1887 " \"address\" (string) " + strprintf("%s",komodo_chainname()) + " address or hex-encoded public key\n"
a6099ef3 1888 " ...,\n"
1889 " ]\n"
3c31eb24 1890 "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 1891
1892 "\nResult:\n"
1333d0d7 1893 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) A " + strprintf("%s",komodo_chainname()) + " address associated with the keys.\n"
a6099ef3 1894
1895 "\nExamples:\n"
1896 "\nAdd a multisig address from 2 addresses\n"
1333d0d7 1897 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"") +
a6099ef3 1898 "\nAs json rpc call\n"
1333d0d7 1899 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"")
a6099ef3 1900 ;
34226be7
GA
1901 throw runtime_error(msg);
1902 }
1903
4401b2d7
EL
1904 LOCK2(cs_main, pwalletMain->cs_wallet);
1905
34226be7
GA
1906 string strAccount;
1907 if (params.size() > 2)
1908 strAccount = AccountFromValue(params[2]);
e3bc5698
JG
1909
1910 // Construct using pay-to-script-hash:
787ee0c9 1911 CScript inner = _createmultisig_redeemScript(params);
066e2a14 1912 CScriptID innerID(inner);
e3bc5698
JG
1913 pwalletMain->AddCScript(inner);
1914
a41d5fe0 1915 pwalletMain->SetAddressBook(innerID, strAccount, "send");
07444da1 1916 return EncodeDestination(innerID);
e3bc5698
JG
1917}
1918
1919
1920struct tallyitem
1921{
a372168e 1922 CAmount nAmount;
e3bc5698 1923 int nConf;
62c9b115 1924 vector<uint256> txids;
0fa2f889 1925 bool fIsWatchonly;
e3bc5698
JG
1926 tallyitem()
1927 {
1928 nAmount = 0;
1929 nConf = std::numeric_limits<int>::max();
0fa2f889 1930 fIsWatchonly = false;
e3bc5698
JG
1931 }
1932};
1933
d014114d 1934UniValue ListReceived(const UniValue& params, bool fByAccounts)
e3bc5698
JG
1935{
1936 // Minimum confirmations
1937 int nMinDepth = 1;
1938 if (params.size() > 0)
1939 nMinDepth = params[0].get_int();
1940
1941 // Whether to include empty accounts
1942 bool fIncludeEmpty = false;
1943 if (params.size() > 1)
1944 fIncludeEmpty = params[1].get_bool();
1945
a3e192a3 1946 isminefilter filter = ISMINE_SPENDABLE;
0fa2f889
J
1947 if(params.size() > 2)
1948 if(params[2].get_bool())
efecad16 1949 filter = ISMINE_ALL;
0fa2f889 1950
e3bc5698 1951 // Tally
07444da1
PW
1952 std::map<CTxDestination, tallyitem> mapTally;
1953 for (const std::pair<uint256, CWalletTx>& pairWtx : pwalletMain->mapWallet) {
1954 const CWalletTx& wtx = pairWtx.second;
e3bc5698 1955
75a4d512 1956 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
1957 continue;
1958
1959 int nDepth = wtx.GetDepthInMainChain();
1960 if (nDepth < nMinDepth)
1961 continue;
1962
1963 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1964 {
1965 CTxDestination address;
0fa2f889
J
1966 if (!ExtractDestination(txout.scriptPubKey, address))
1967 continue;
1968
1969 isminefilter mine = IsMine(*pwalletMain, address);
f28707a8 1970 if(!(mine & filter))
e3bc5698
JG
1971 continue;
1972
1973 tallyitem& item = mapTally[address];
47658758 1974 item.nAmount += txout.nValue; // komodo_interest?
e3bc5698 1975 item.nConf = min(item.nConf, nDepth);
805344dc 1976 item.txids.push_back(wtx.GetHash());
a3e192a3 1977 if (mine & ISMINE_WATCH_ONLY)
0fa2f889 1978 item.fIsWatchonly = true;
e3bc5698
JG
1979 }
1980 }
1981
1982 // Reply
38fc4b70 1983 UniValue ret(UniValue::VARR);
07444da1
PW
1984 std::map<std::string, tallyitem> mapAccountTally;
1985 for (const std::pair<CTxDestination, CAddressBookData>& item : pwalletMain->mapAddressBook) {
1986 const CTxDestination& dest = item.first;
1987 const std::string& strAccount = item.second.name;
1988 std::map<CTxDestination, tallyitem>::iterator it = mapTally.find(dest);
e3bc5698
JG
1989 if (it == mapTally.end() && !fIncludeEmpty)
1990 continue;
1991
a372168e 1992 CAmount nAmount = 0;
e3bc5698 1993 int nConf = std::numeric_limits<int>::max();
0fa2f889 1994 bool fIsWatchonly = false;
e3bc5698
JG
1995 if (it != mapTally.end())
1996 {
1997 nAmount = (*it).second.nAmount;
1998 nConf = (*it).second.nConf;
0fa2f889 1999 fIsWatchonly = (*it).second.fIsWatchonly;
e3bc5698
JG
2000 }
2001
2002 if (fByAccounts)
2003 {
2004 tallyitem& item = mapAccountTally[strAccount];
2005 item.nAmount += nAmount;
2006 item.nConf = min(item.nConf, nConf);
0fa2f889 2007 item.fIsWatchonly = fIsWatchonly;
e3bc5698
JG
2008 }
2009 else
2010 {
38fc4b70 2011 UniValue obj(UniValue::VOBJ);
0fa2f889
J
2012 if(fIsWatchonly)
2013 obj.push_back(Pair("involvesWatchonly", true));
07444da1 2014 obj.push_back(Pair("address", EncodeDestination(dest)));
e3bc5698
JG
2015 obj.push_back(Pair("account", strAccount));
2016 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
2017 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
38fc4b70 2018 UniValue transactions(UniValue::VARR);
1a204694 2019 if (it != mapTally.end())
62c9b115 2020 {
1a204694
A
2021 BOOST_FOREACH(const uint256& item, (*it).second.txids)
2022 {
2023 transactions.push_back(item.GetHex());
2024 }
62c9b115
A
2025 }
2026 obj.push_back(Pair("txids", transactions));
e3bc5698
JG
2027 ret.push_back(obj);
2028 }
2029 }
2030
2031 if (fByAccounts)
2032 {
2033 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
2034 {
a372168e 2035 CAmount nAmount = (*it).second.nAmount;
e3bc5698 2036 int nConf = (*it).second.nConf;
38fc4b70 2037 UniValue obj(UniValue::VOBJ);
0fa2f889
J
2038 if((*it).second.fIsWatchonly)
2039 obj.push_back(Pair("involvesWatchonly", true));
e3bc5698
JG
2040 obj.push_back(Pair("account", (*it).first));
2041 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
2042 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
2043 ret.push_back(obj);
2044 }
2045 }
2046
2047 return ret;
2048}
2049
d014114d 2050UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
e3bc5698 2051{
b9fb692d 2052 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2053 return NullUniValue;
9d365796 2054
0fa2f889 2055 if (fHelp || params.size() > 3)
e3bc5698 2056 throw runtime_error(
0fa2f889 2057 "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
a6099ef3 2058 "\nList balances by receiving address.\n"
2059 "\nArguments:\n"
2060 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
5617267c 2061 "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n"
0fa2f889 2062 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
a6099ef3 2063
2064 "\nResult:\n"
2065 "[\n"
2066 " {\n"
8f6860a0 2067 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
a6099ef3 2068 " \"address\" : \"receivingaddress\", (string) The receiving address\n"
7b782f5b 2069 " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
1333d0d7 2070 " \"amount\" : x.xxx, (numeric) The total amount in " + strprintf("%s",komodo_chainname()) + " received by the address\n"
a6099ef3 2071 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
2072 " }\n"
2073 " ,...\n"
2074 "]\n"
2075
2076 "\nExamples:\n"
2077 + HelpExampleCli("listreceivedbyaddress", "")
2078 + HelpExampleCli("listreceivedbyaddress", "6 true")
0fa2f889 2079 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
a6099ef3 2080 );
e3bc5698 2081
4401b2d7
EL
2082 LOCK2(cs_main, pwalletMain->cs_wallet);
2083
e3bc5698
JG
2084 return ListReceived(params, false);
2085}
2086
d014114d 2087UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
e3bc5698 2088{
b9fb692d 2089 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2090 return NullUniValue;
9d365796 2091
0fa2f889 2092 if (fHelp || params.size() > 3)
e3bc5698 2093 throw runtime_error(
0fa2f889 2094 "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
7b782f5b 2095 "\nDEPRECATED. List balances by account.\n"
a6099ef3 2096 "\nArguments:\n"
2097 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
2098 "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
0fa2f889 2099 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
a6099ef3 2100
2101 "\nResult:\n"
2102 "[\n"
2103 " {\n"
8f6860a0 2104 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
a6099ef3 2105 " \"account\" : \"accountname\", (string) The account name of the receiving account\n"
2106 " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
2107 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
2108 " }\n"
2109 " ,...\n"
2110 "]\n"
2111
2112 "\nExamples:\n"
2113 + HelpExampleCli("listreceivedbyaccount", "")
2114 + HelpExampleCli("listreceivedbyaccount", "6 true")
0fa2f889 2115 + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
a6099ef3 2116 );
e3bc5698 2117
4401b2d7
EL
2118 LOCK2(cs_main, pwalletMain->cs_wallet);
2119
e3bc5698
JG
2120 return ListReceived(params, true);
2121}
2122
851f58f9 2123static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
cc6cfab3 2124{
07444da1
PW
2125 if (IsValidDestination(dest)) {
2126 entry.push_back(Pair("address", EncodeDestination(dest)));
2127 }
cc6cfab3
LD
2128}
2129
a9774a32 2130bool ValidateStakeTransaction(const CTransaction &stakeTx, CStakeParams &stakeParams, bool validateSig = true);
2131
d014114d 2132void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
e3bc5698 2133{
a372168e 2134 CAmount nFee;
e3bc5698 2135 string strSentAccount;
1b4568cb
CL
2136 list<COutputEntry> listReceived;
2137 list<COutputEntry> listSent;
e3bc5698 2138
a9774a32 2139 CStakeParams p;
2140 bool bIsStake = false;
2141 bool bIsCoinbase = false;
2142 bool bIsMint = false;
4005d836 2143 bool bIsReserve = ConnectedChains.ThisChain().IsFractional();
9d9d90c5 2144 CReserveTransactionDescriptor rtxd;
2145 CCoinsViewCache view(pcoinsTip);
2146 uint32_t nHeight = chainActive.Height();
2147
a9774a32 2148 if (ValidateStakeTransaction(wtx, p, false))
2149 {
2150 bIsStake = true;
2151 }
2152 else
2153 {
2154 bIsCoinbase = wtx.IsCoinBase();
2155 bIsMint = bIsCoinbase && wtx.vout.size() > 0 && wtx.vout[0].scriptPubKey.IsPayToCryptoCondition();
2156 }
2157
fde58f33 2158 if (bIsReserve && (rtxd = CReserveTransactionDescriptor(wtx, view, nHeight)).IsReserve())
9d9d90c5 2159 {
f191ea95 2160 ret.push_back(Pair("isreserve", true));
9d9d90c5 2161 bool isReserveExchange = rtxd.IsReserveExchange();
f191ea95 2162 ret.push_back(Pair("isreserveexchange", isReserveExchange));
9d9d90c5 2163 if (isReserveExchange)
2164 {
2165 if (rtxd.IsMarket())
2166 {
f191ea95 2167 ret.push_back(Pair("exchangetype", "market"));
9d9d90c5 2168 }
2169 else if (rtxd.IsLimit())
2170 {
f191ea95 2171 ret.push_back(Pair("exchangetype", "limit"));
9d9d90c5 2172 }
2173 }
f191ea95 2174 ret.push_back(Pair("nativefees", rtxd.NativeFees()));
56fe75cb 2175 ret.push_back(Pair("reservefees", rtxd.ReserveFees().ToUniValue()));
2176 if (rtxd.nativeConversionFees || (rtxd.ReserveConversionFeesMap() > CCurrencyValueMap()))
9d9d90c5 2177 {
f191ea95 2178 ret.push_back(Pair("nativeconversionfees", rtxd.nativeConversionFees));
56fe75cb 2179 ret.push_back(Pair("reserveconversionfees", rtxd.ReserveConversionFeesMap().ToUniValue()));
9d9d90c5 2180 }
2181 }
2182 else
2183 {
f191ea95 2184 ret.push_back(Pair("isreserve", false));
9d9d90c5 2185 }
2186
73b4d696 2187 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, bIsStake ? ISMINE_ALLANDCHANGE : filter);
2188
e3bc5698 2189 bool fAllAccounts = (strAccount == string("*"));
a3e192a3 2190 bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
e3bc5698 2191
e3bc5698
JG
2192 // Sent
2193 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
2194 {
1b4568cb 2195 BOOST_FOREACH(const COutputEntry& s, listSent)
e3bc5698 2196 {
38fc4b70 2197 UniValue entry(UniValue::VOBJ);
1b4568cb 2198 if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
952877e0 2199 entry.push_back(Pair("involvesWatchonly", true));
e3bc5698 2200 entry.push_back(Pair("account", strSentAccount));
1b4568cb 2201 MaybePushAddress(entry, s.destination);
a9774a32 2202 entry.push_back(Pair("category", bIsStake ? "stake" : "send"));
1b4568cb 2203 entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
cc3d5cb5 2204
375c5ff8 2205 if (wtx.vout.size() > s.vout)
cc3d5cb5 2206 {
375c5ff8 2207 CCurrencyValueMap tokenAmounts = wtx.vout[s.vout].scriptPubKey.ReserveOutValue();
2208 if (tokenAmounts.valueMap.size())
2209 {
2210 entry.push_back(Pair("tokenamounts", tokenAmounts.ToUniValue()));
2211 }
cc3d5cb5 2212 }
2213
1b4568cb 2214 entry.push_back(Pair("vout", s.vout));
e3bc5698
JG
2215 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
2216 if (fLong)
2217 WalletTxToJSON(wtx, entry);
a8e5ae92 2218 entry.push_back(Pair("size", static_cast<uint64_t>(GetSerializeSize(static_cast<CTransaction>(wtx), SER_NETWORK, PROTOCOL_VERSION))));
e3bc5698
JG
2219 ret.push_back(entry);
2220 }
2221 }
2222
2223 // Received
2224 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
2225 {
1b4568cb 2226 BOOST_FOREACH(const COutputEntry& r, listReceived)
e3bc5698
JG
2227 {
2228 string account;
1b4568cb
CL
2229 if (pwalletMain->mapAddressBook.count(r.destination))
2230 account = pwalletMain->mapAddressBook[r.destination].name;
e3bc5698
JG
2231 if (fAllAccounts || (account == strAccount))
2232 {
38fc4b70 2233 UniValue entry(UniValue::VOBJ);
1b4568cb 2234 if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
952877e0 2235 entry.push_back(Pair("involvesWatchonly", true));
e3bc5698 2236 entry.push_back(Pair("account", account));
cc1ae28b
MT
2237
2238 CTxDestination dest;
2239 if (CScriptExt::ExtractVoutDestination(wtx, r.vout, dest))
2240 MaybePushAddress(entry, dest);
2241 else
2242 MaybePushAddress(entry, r.destination);
2243
a9774a32 2244 if (bIsCoinbase)
e07c8e91 2245 {
c2f6623f 2246 int btm;
e07c8e91
LD
2247 if (wtx.GetDepthInMainChain() < 1)
2248 entry.push_back(Pair("category", "orphan"));
c2f6623f 2249 else if ((btm = wtx.GetBlocksToMaturity()) > 0)
2250 {
e07c8e91 2251 entry.push_back(Pair("category", "immature"));
c2f6623f 2252 entry.push_back(Pair("blockstomaturity", btm));
2253 }
e07c8e91 2254 else
a9774a32 2255 entry.push_back(Pair("category", bIsMint ? "mint" : "generate"));
e07c8e91
LD
2256 }
2257 else
2b72d46f 2258 {
a9774a32 2259 entry.push_back(Pair("category", bIsStake ? "stake" : "receive"));
2b72d46f 2260 }
9d9d90c5 2261
2262 COptCCParams p;
2263 if (rtxd.IsValid() && wtx.vout[r.vout].scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid())
2264 {
2265 UniValue ccUni;
f477c8b0 2266 ScriptPubKeyToJSON(wtx.vout[r.vout].scriptPubKey, ccUni, false, false);
9d9d90c5 2267 entry.push_back(Pair("cryptocondition", ccUni));
2268 }
a9774a32 2269
1b4568cb 2270 entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
375c5ff8 2271 if (wtx.vout.size() > r.vout && rtxd.IsReserve())
9d9d90c5 2272 {
56fe75cb 2273 entry.push_back(Pair("reserveamount", wtx.vout[r.vout].scriptPubKey.ReserveOutValue().ToUniValue()));
9d9d90c5 2274 }
1b4568cb 2275 entry.push_back(Pair("vout", r.vout));
e3bc5698
JG
2276 if (fLong)
2277 WalletTxToJSON(wtx, entry);
a8e5ae92 2278 entry.push_back(Pair("size", static_cast<uint64_t>(GetSerializeSize(static_cast<CTransaction>(wtx), SER_NETWORK, PROTOCOL_VERSION))));
e3bc5698
JG
2279 ret.push_back(entry);
2280 }
2281 }
2282 }
2283}
2284
d014114d 2285void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret)
e3bc5698
JG
2286{
2287 bool fAllAccounts = (strAccount == string("*"));
2288
2289 if (fAllAccounts || acentry.strAccount == strAccount)
2290 {
38fc4b70 2291 UniValue entry(UniValue::VOBJ);
e3bc5698
JG
2292 entry.push_back(Pair("account", acentry.strAccount));
2293 entry.push_back(Pair("category", "move"));
d56e30ca 2294 entry.push_back(Pair("time", acentry.nTime));
e3bc5698
JG
2295 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
2296 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
2297 entry.push_back(Pair("comment", acentry.strComment));
2298 ret.push_back(entry);
2299 }
2300}
2301
d014114d 2302UniValue listtransactions(const UniValue& params, bool fHelp)
e3bc5698 2303{
b9fb692d 2304 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2305 return NullUniValue;
9d365796 2306
d7d5d23b 2307 if (fHelp || params.size() > 4)
e3bc5698 2308 throw runtime_error(
d7d5d23b 2309 "listtransactions ( \"account\" count from includeWatchonly)\n"
a6099ef3 2310 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
2311 "\nArguments:\n"
7b782f5b 2312 "1. \"account\" (string, optional) DEPRECATED. The account name. Should be \"*\".\n"
a6099ef3 2313 "2. count (numeric, optional, default=10) The number of transactions to return\n"
2314 "3. from (numeric, optional, default=0) The number of transactions to skip\n"
d7d5d23b 2315 "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
a6099ef3 2316 "\nResult:\n"
2317 "[\n"
2318 " {\n"
7b782f5b 2319 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n"
a6099ef3 2320 " It will be \"\" for the default account.\n"
1333d0d7 2321 " \"address\":\"" + strprintf("%s",komodo_chainname()) + "_address\", (string) The " + strprintf("%s",komodo_chainname()) + " address of the transaction. Not present for \n"
a6099ef3 2322 " move transactions (category = move).\n"
2323 " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
2324 " transaction between accounts, and not associated with an address,\n"
2325 " transaction id or block. 'send' and 'receive' transactions are \n"
2326 " associated with an address, transaction id and block details\n"
1333d0d7 2327 " \"amount\": x.xxx, (numeric) The amount in " + strprintf("%s",komodo_chainname()) + ". This is negative for the 'send' category, and for the\n"
a6099ef3 2328 " 'move' category for moves outbound. It is positive for the 'receive' category,\n"
2329 " and for the 'move' category for inbound funds.\n"
1b4568cb 2330 " \"vout\" : n, (numeric) the vout value\n"
1333d0d7 2331 " \"fee\": x.xxx, (numeric) The amount of the fee in " + strprintf("%s",komodo_chainname()) + ". This is negative and only available for the \n"
a6099ef3 2332 " 'send' category of transactions.\n"
2333 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
2334 " 'receive' category of transactions.\n"
2335 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
2336 " category of transactions.\n"
2337 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
2338 " category of transactions.\n"
b5ef85c7 2339 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
a6099ef3 2340 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
2341 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
2342 " for 'send' and 'receive' category of transactions.\n"
2343 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
2344 " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
2345 " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
2346 " negative amounts).\n"
f32cade8 2347 " \"size\": n, (numeric) Transaction size in bytes\n"
a6099ef3 2348 " }\n"
2349 "]\n"
2350
2351 "\nExamples:\n"
2352 "\nList the most recent 10 transactions in the systems\n"
2353 + HelpExampleCli("listtransactions", "") +
7b782f5b
LD
2354 "\nList transactions 100 to 120\n"
2355 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
a6099ef3 2356 "\nAs a json rpc call\n"
7b782f5b 2357 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
a6099ef3 2358 );
e3bc5698 2359
4401b2d7
EL
2360 LOCK2(cs_main, pwalletMain->cs_wallet);
2361
e3bc5698
JG
2362 string strAccount = "*";
2363 if (params.size() > 0)
2364 strAccount = params[0].get_str();
2365 int nCount = 10;
2366 if (params.size() > 1)
2367 nCount = params[1].get_int();
2368 int nFrom = 0;
2369 if (params.size() > 2)
2370 nFrom = params[2].get_int();
a3e192a3 2371 isminefilter filter = ISMINE_SPENDABLE;
a5c6c5d6
J
2372 if(params.size() > 3)
2373 if(params[3].get_bool())
efecad16 2374 filter = ISMINE_ALL;
e3bc5698
JG
2375
2376 if (nCount < 0)
738835d7 2377 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
e3bc5698 2378 if (nFrom < 0)
738835d7 2379 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
e3bc5698 2380
38fc4b70 2381 UniValue ret(UniValue::VARR);
e3bc5698 2382
ddb709e9
LD
2383 std::list<CAccountingEntry> acentries;
2384 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
e3bc5698
JG
2385
2386 // iterate backwards until we have nCount items to return:
c3f95ef1 2387 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
e3bc5698
JG
2388 {
2389 CWalletTx *const pwtx = (*it).second.first;
2390 if (pwtx != 0)
d7d5d23b 2391 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
e3bc5698
JG
2392 CAccountingEntry *const pacentry = (*it).second.second;
2393 if (pacentry != 0)
2394 AcentryToJSON(*pacentry, strAccount, ret);
2395
2396 if ((int)ret.size() >= (nCount+nFrom)) break;
2397 }
2398 // ret is newest to oldest
2399
2400 if (nFrom > (int)ret.size())
2401 nFrom = ret.size();
2402 if ((nFrom + nCount) > (int)ret.size())
2403 nCount = ret.size() - nFrom;
ed21d5bd
JG
2404
2405 vector<UniValue> arrTmp = ret.getValues();
2406
2407 vector<UniValue>::iterator first = arrTmp.begin();
e3bc5698 2408 std::advance(first, nFrom);
ed21d5bd 2409 vector<UniValue>::iterator last = arrTmp.begin();
e3bc5698
JG
2410 std::advance(last, nFrom+nCount);
2411
ed21d5bd
JG
2412 if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
2413 if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
e3bc5698 2414
ed21d5bd 2415 std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
e3bc5698 2416
ed21d5bd 2417 ret.clear();
38fc4b70 2418 ret.setArray();
ed21d5bd 2419 ret.push_backV(arrTmp);
e3bc5698
JG
2420
2421 return ret;
2422}
2423
d014114d 2424UniValue listaccounts(const UniValue& params, bool fHelp)
e3bc5698 2425{
b9fb692d 2426 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2427 return NullUniValue;
9d365796 2428
83f3543f 2429 if (fHelp || params.size() > 2)
e3bc5698 2430 throw runtime_error(
83f3543f 2431 "listaccounts ( minconf includeWatchonly)\n"
7b782f5b 2432 "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
a6099ef3 2433 "\nArguments:\n"
5617267c 2434 "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
83f3543f 2435 "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
a6099ef3 2436 "\nResult:\n"
2437 "{ (json object where keys are account names, and values are numeric balances\n"
2438 " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
2439 " ...\n"
2440 "}\n"
2441 "\nExamples:\n"
2442 "\nList account balances where there at least 1 confirmation\n"
2443 + HelpExampleCli("listaccounts", "") +
2444 "\nList account balances including zero confirmation transactions\n"
2445 + HelpExampleCli("listaccounts", "0") +
2446 "\nList account balances for 6 or more confirmations\n"
2447 + HelpExampleCli("listaccounts", "6") +
2448 "\nAs json rpc call\n"
2449 + HelpExampleRpc("listaccounts", "6")
2450 );
e3bc5698 2451
4401b2d7
EL
2452 LOCK2(cs_main, pwalletMain->cs_wallet);
2453
e3bc5698
JG
2454 int nMinDepth = 1;
2455 if (params.size() > 0)
2456 nMinDepth = params[0].get_int();
a3e192a3 2457 isminefilter includeWatchonly = ISMINE_SPENDABLE;
a5c6c5d6
J
2458 if(params.size() > 1)
2459 if(params[1].get_bool())
efecad16 2460 includeWatchonly = ISMINE_ALL;
e3bc5698 2461
a372168e 2462 map<string, CAmount> mapAccountBalances;
61885513 2463 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
83f3543f 2464 if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
61885513 2465 mapAccountBalances[entry.second.name] = 0;
e3bc5698
JG
2466 }
2467
2468 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
2469 {
2470 const CWalletTx& wtx = (*it).second;
a372168e 2471 CAmount nFee;
e3bc5698 2472 string strSentAccount;
1b4568cb
CL
2473 list<COutputEntry> listReceived;
2474 list<COutputEntry> listSent;
93a18a36
GA
2475 int nDepth = wtx.GetDepthInMainChain();
2476 if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
731b89b8 2477 continue;
83f3543f 2478 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
e3bc5698 2479 mapAccountBalances[strSentAccount] -= nFee;
1b4568cb
CL
2480 BOOST_FOREACH(const COutputEntry& s, listSent)
2481 mapAccountBalances[strSentAccount] -= s.amount;
93a18a36 2482 if (nDepth >= nMinDepth)
e3bc5698 2483 {
1b4568cb
CL
2484 BOOST_FOREACH(const COutputEntry& r, listReceived)
2485 if (pwalletMain->mapAddressBook.count(r.destination))
2486 mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
e3bc5698 2487 else
1b4568cb 2488 mapAccountBalances[""] += r.amount;
e3bc5698
JG
2489 }
2490 }
2491
2492 list<CAccountingEntry> acentries;
2493 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
2494 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
2495 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
2496
38fc4b70 2497 UniValue ret(UniValue::VOBJ);
a372168e 2498 BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
e3bc5698
JG
2499 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
2500 }
2501 return ret;
2502}
2503
d014114d 2504UniValue listsinceblock(const UniValue& params, bool fHelp)
e3bc5698 2505{
b9fb692d 2506 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2507 return NullUniValue;
9d365796 2508
e3bc5698
JG
2509 if (fHelp)
2510 throw runtime_error(
d7d5d23b 2511 "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
a6099ef3 2512 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
2513 "\nArguments:\n"
2514 "1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
2515 "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
d7d5d23b 2516 "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
a6099ef3 2517 "\nResult:\n"
2518 "{\n"
2519 " \"transactions\": [\n"
7b782f5b 2520 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
1333d0d7 2521 " \"address\":\"" + strprintf("%s",komodo_chainname()) + "_address\", (string) The " + strprintf("%s",komodo_chainname()) + " address of the transaction. Not present for move transactions (category = move).\n"
a6099ef3 2522 " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
1333d0d7 2523 " \"amount\": x.xxx, (numeric) The amount in " + strprintf("%s",komodo_chainname()) + ". This is negative for the 'send' category, and for the 'move' category for moves \n"
a6099ef3 2524 " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
1b4568cb 2525 " \"vout\" : n, (numeric) the vout value\n"
1333d0d7 2526 " \"fee\": x.xxx, (numeric) The amount of the fee in " + strprintf("%s",komodo_chainname()) + ". This is negative and only available for the 'send' category of transactions.\n"
a6099ef3 2527 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
2528 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
2529 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
2530 " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
b5ef85c7 2531 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
a6099ef3 2532 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
2533 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
2534 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
2535 " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
2536 " ],\n"
2537 " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
2538 "}\n"
2539 "\nExamples:\n"
2540 + HelpExampleCli("listsinceblock", "")
2541 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
2542 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
2543 );
e3bc5698 2544
4401b2d7
EL
2545 LOCK2(cs_main, pwalletMain->cs_wallet);
2546
e3bc5698
JG
2547 CBlockIndex *pindex = NULL;
2548 int target_confirms = 1;
a3e192a3 2549 isminefilter filter = ISMINE_SPENDABLE;
e3bc5698
JG
2550
2551 if (params.size() > 0)
2552 {
4f152496 2553 uint256 blockId;
e3bc5698
JG
2554
2555 blockId.SetHex(params[0].get_str());
145d5be8 2556 BlockMap::iterator it = mapBlockIndex.find(blockId);
e4daecda
PW
2557 if (it != mapBlockIndex.end())
2558 pindex = it->second;
e3bc5698
JG
2559 }
2560
2561 if (params.size() > 1)
2562 {
2563 target_confirms = params[1].get_int();
2564
2565 if (target_confirms < 1)
738835d7 2566 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
e3bc5698
JG
2567 }
2568
a5c6c5d6
J
2569 if(params.size() > 2)
2570 if(params[2].get_bool())
efecad16 2571 filter = ISMINE_ALL;
a5c6c5d6 2572
4b729ec5 2573 int depth = pindex ? (1 + chainActive.Height() - pindex->GetHeight()) : -1;
e3bc5698 2574
38fc4b70 2575 UniValue transactions(UniValue::VARR);
e3bc5698
JG
2576
2577 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
2578 {
2579 CWalletTx tx = (*it).second;
2580
2581 if (depth == -1 || tx.GetDepthInMainChain() < depth)
d7d5d23b 2582 ListTransactions(tx, "*", 0, true, transactions, filter);
e3bc5698
JG
2583 }
2584
4c6d41b8 2585 CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
4f152496 2586 uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
e3bc5698 2587
38fc4b70 2588 UniValue ret(UniValue::VOBJ);
e3bc5698
JG
2589 ret.push_back(Pair("transactions", transactions));
2590 ret.push_back(Pair("lastblock", lastblock.GetHex()));
2591
2592 return ret;
2593}
2594
d014114d 2595UniValue gettransaction(const UniValue& params, bool fHelp)
e3bc5698 2596{
b9fb692d 2597 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2598 return NullUniValue;
9d365796 2599
f87ba3df 2600 if (fHelp || params.size() < 1 || params.size() > 2)
e3bc5698 2601 throw runtime_error(
57e1716d 2602 "gettransaction \"txid\" ( includeWatchonly )\n"
a6099ef3 2603 "\nGet detailed information about in-wallet transaction <txid>\n"
2604 "\nArguments:\n"
2605 "1. \"txid\" (string, required) The transaction id\n"
f87ba3df 2606 "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
a6099ef3 2607 "\nResult:\n"
2608 "{\n"
1333d0d7 2609 " \"amount\" : x.xxx, (numeric) The transaction amount in " + strprintf("%s",komodo_chainname()) + "\n"
a6099ef3 2610 " \"confirmations\" : n, (numeric) The number of confirmations\n"
2611 " \"blockhash\" : \"hash\", (string) The block hash\n"
2612 " \"blockindex\" : xx, (numeric) The block index\n"
2613 " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
b5ef85c7 2614 " \"txid\" : \"transactionid\", (string) The transaction id.\n"
a6099ef3 2615 " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
2616 " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
2617 " \"details\" : [\n"
2618 " {\n"
7b782f5b 2619 " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
1333d0d7 2620 " \"address\" : \"" + strprintf("%s",komodo_chainname()) + "_address\", (string) The " + strprintf("%s",komodo_chainname()) + " address involved in the transaction\n"
a6099ef3 2621 " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
1333d0d7 2622 " \"amount\" : x.xxx (numeric) The amount in " + strprintf("%s",komodo_chainname()) + "\n"
1b4568cb 2623 " \"vout\" : n, (numeric) the vout value\n"
a6099ef3 2624 " }\n"
2625 " ,...\n"
3a1c20b7 2626 " ],\n"
f7cfb52d
S
2627 " \"vjoinsplit\" : [\n"
2628 " {\n"
2629 " \"anchor\" : \"treestateref\", (string) Merkle root of note commitment tree\n"
2630 " \"nullifiers\" : [ string, ... ] (string) Nullifiers of input notes\n"
2631 " \"commitments\" : [ string, ... ] (string) Note commitments for note outputs\n"
2632 " \"macs\" : [ string, ... ] (string) Message authentication tags\n"
2633 " \"vpub_old\" : x.xxx (numeric) The amount removed from the transparent value pool\n"
2634 " \"vpub_new\" : x.xxx, (numeric) The amount added to the transparent value pool\n"
2635 " }\n"
2636 " ,...\n"
2637 " ],\n"
3a1c20b7 2638 " \"hex\" : \"data\" (string) Raw data for transaction\n"
a6099ef3 2639 "}\n"
2640
ab45ddb5 2641 "\nExamples:\n"
a6099ef3 2642 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
57e1716d 2643 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
a6099ef3 2644 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
2645 );
e3bc5698 2646
4401b2d7
EL
2647 LOCK2(cs_main, pwalletMain->cs_wallet);
2648
e3bc5698
JG
2649 uint256 hash;
2650 hash.SetHex(params[0].get_str());
2651
a3e192a3 2652 isminefilter filter = ISMINE_SPENDABLE;
f87ba3df
J
2653 if(params.size() > 1)
2654 if(params[1].get_bool())
efecad16 2655 filter = ISMINE_ALL;
f87ba3df 2656
38fc4b70 2657 UniValue entry(UniValue::VOBJ);
e3bc5698 2658 if (!pwalletMain->mapWallet.count(hash))
738835d7 2659 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
e3bc5698
JG
2660 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
2661
ccca27a7 2662 CAmount nCredit = wtx.GetCredit(filter);
a372168e
MF
2663 CAmount nDebit = wtx.GetDebit(filter);
2664 CAmount nNet = nCredit - nDebit;
2665 CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
e3bc5698
JG
2666
2667 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
80dda36a 2668 if (wtx.IsFromMe(filter))
e3bc5698
JG
2669 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
2670
2671 WalletTxToJSON(wtx, entry);
2672
38fc4b70 2673 UniValue details(UniValue::VARR);
f87ba3df 2674 ListTransactions(wtx, "*", 0, false, details, filter);
e3bc5698
JG
2675 entry.push_back(Pair("details", details));
2676
ae775b5b 2677 string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
3a1c20b7
WL
2678 entry.push_back(Pair("hex", strHex));
2679
e3bc5698
JG
2680 return entry;
2681}
2682
2683
d014114d 2684UniValue backupwallet(const UniValue& params, bool fHelp)
e3bc5698 2685{
b9fb692d 2686 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2687 return NullUniValue;
9d365796 2688
e3bc5698
JG
2689 if (fHelp || params.size() != 1)
2690 throw runtime_error(
a6099ef3 2691 "backupwallet \"destination\"\n"
9064d73b 2692 "\nSafely copies wallet.dat to destination filename\n"
a6099ef3 2693 "\nArguments:\n"
9064d73b
S
2694 "1. \"destination\" (string, required) The destination filename, saved in the directory set by -exportdir option.\n"
2695 "\nResult:\n"
2696 "\"path\" (string) The full path of the destination file\n"
a6099ef3 2697 "\nExamples:\n"
9064d73b
S
2698 + HelpExampleCli("backupwallet", "\"backupdata\"")
2699 + HelpExampleRpc("backupwallet", "\"backupdata\"")
a6099ef3 2700 );
e3bc5698 2701
4401b2d7
EL
2702 LOCK2(cs_main, pwalletMain->cs_wallet);
2703
9064d73b
S
2704 boost::filesystem::path exportdir;
2705 try {
2706 exportdir = GetExportDir();
2707 } catch (const std::runtime_error& e) {
2708 throw JSONRPCError(RPC_INTERNAL_ERROR, e.what());
2709 }
2710 if (exportdir.empty()) {
2711 throw JSONRPCError(RPC_WALLET_ERROR, "Cannot backup wallet until the -exportdir option has been set");
2712 }
2713 std::string unclean = params[0].get_str();
2714 std::string clean = SanitizeFilename(unclean);
2715 if (clean.compare(unclean) != 0) {
2716 throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Filename is invalid as only alphanumeric characters are allowed. Try '%s' instead.", clean));
2717 }
2718 boost::filesystem::path exportfilepath = exportdir / clean;
2719
2720 if (!BackupWallet(*pwalletMain, exportfilepath.string()))
ad525e9c 2721 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
e3bc5698 2722
9064d73b 2723 return exportfilepath.string();
e3bc5698
JG
2724}
2725
2726
d014114d 2727UniValue keypoolrefill(const UniValue& params, bool fHelp)
e3bc5698 2728{
b9fb692d 2729 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2730 return NullUniValue;
9d365796 2731
36bd46f1 2732 if (fHelp || params.size() > 1)
e3bc5698 2733 throw runtime_error(
a6099ef3 2734 "keypoolrefill ( newsize )\n"
2735 "\nFills the keypool."
2736 + HelpRequiringPassphrase() + "\n"
2737 "\nArguments\n"
2738 "1. newsize (numeric, optional, default=100) The new keypool size\n"
2739 "\nExamples:\n"
2740 + HelpExampleCli("keypoolrefill", "")
2741 + HelpExampleRpc("keypoolrefill", "")
2742 );
e3bc5698 2743
4401b2d7
EL
2744 LOCK2(cs_main, pwalletMain->cs_wallet);
2745
f914c7a1
PK
2746 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
2747 unsigned int kpSize = 0;
36bd46f1
JG
2748 if (params.size() > 0) {
2749 if (params[0].get_int() < 0)
f914c7a1
PK
2750 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
2751 kpSize = (unsigned int)params[0].get_int();
36bd46f1
JG
2752 }
2753
e3bc5698 2754 EnsureWalletIsUnlocked();
36bd46f1 2755 pwalletMain->TopUpKeyPool(kpSize);
e3bc5698 2756
36bd46f1 2757 if (pwalletMain->GetKeyPoolSize() < kpSize)
738835d7 2758 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
e3bc5698 2759
ed21d5bd 2760 return NullUniValue;
e3bc5698
JG
2761}
2762
2763
92f2c1fe 2764static void LockWallet(CWallet* pWallet)
e3bc5698 2765{
92f2c1fe
GA
2766 LOCK(cs_nWalletUnlockTime);
2767 nWalletUnlockTime = 0;
2768 pWallet->Lock();
e3bc5698
JG
2769}
2770
d014114d 2771UniValue walletpassphrase(const UniValue& params, bool fHelp)
e3bc5698 2772{
b9fb692d 2773 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2774 return NullUniValue;
9d365796 2775
e3bc5698
JG
2776 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
2777 throw runtime_error(
a6099ef3 2778 "walletpassphrase \"passphrase\" timeout\n"
2779 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
1333d0d7 2780 "This is needed prior to performing transactions related to private keys such as sending " + strprintf("%s",komodo_chainname()) + "\n"
a6099ef3 2781 "\nArguments:\n"
2782 "1. \"passphrase\" (string, required) The wallet passphrase\n"
2783 "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
6c0db81c
WL
2784 "\nNote:\n"
2785 "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
2786 "time that overrides the old one.\n"
a6099ef3 2787 "\nExamples:\n"
2788 "\nunlock the wallet for 60 seconds\n"
2789 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
2790 "\nLock the wallet again (before 60 seconds)\n"
2791 + HelpExampleCli("walletlock", "") +
2792 "\nAs json rpc call\n"
2793 + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
2794 );
2795
4401b2d7
EL
2796 LOCK2(cs_main, pwalletMain->cs_wallet);
2797
e3bc5698
JG
2798 if (fHelp)
2799 return true;
2800 if (!pwalletMain->IsCrypted())
738835d7 2801 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
e3bc5698 2802
e3bc5698
JG
2803 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
2804 SecureString strWalletPass;
2805 strWalletPass.reserve(100);
2806 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2807 // Alternately, find a way to make params[0] mlock()'d to begin with.
2808 strWalletPass = params[0].get_str().c_str();
2809
2810 if (strWalletPass.length() > 0)
2811 {
2812 if (!pwalletMain->Unlock(strWalletPass))
738835d7 2813 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
e3bc5698
JG
2814 }
2815 else
2816 throw runtime_error(
2817 "walletpassphrase <passphrase> <timeout>\n"
2818 "Stores the wallet decryption key in memory for <timeout> seconds.");
2819
6e263a5f 2820 // No need to check return values, because the wallet was unlocked above
1a62587e 2821 pwalletMain->UpdateNullifierNoteMap();
92f2c1fe
GA
2822 pwalletMain->TopUpKeyPool();
2823
51ed9ec9 2824 int64_t nSleepTime = params[1].get_int64();
92f2c1fe
GA
2825 LOCK(cs_nWalletUnlockTime);
2826 nWalletUnlockTime = GetTime() + nSleepTime;
2827 RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
e3bc5698 2828
ed21d5bd 2829 return NullUniValue;
e3bc5698
JG
2830}
2831
2832
d014114d 2833UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
e3bc5698 2834{
b9fb692d 2835 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2836 return NullUniValue;
9d365796 2837
e3bc5698
JG
2838 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
2839 throw runtime_error(
a6099ef3 2840 "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
2841 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
2842 "\nArguments:\n"
2843 "1. \"oldpassphrase\" (string) The current passphrase\n"
2844 "2. \"newpassphrase\" (string) The new passphrase\n"
2845 "\nExamples:\n"
2846 + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
2847 + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
2848 );
2849
4401b2d7
EL
2850 LOCK2(cs_main, pwalletMain->cs_wallet);
2851
e3bc5698
JG
2852 if (fHelp)
2853 return true;
2854 if (!pwalletMain->IsCrypted())
738835d7 2855 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
e3bc5698
JG
2856
2857 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
2858 // Alternately, find a way to make params[0] mlock()'d to begin with.
2859 SecureString strOldWalletPass;
2860 strOldWalletPass.reserve(100);
2861 strOldWalletPass = params[0].get_str().c_str();
2862
2863 SecureString strNewWalletPass;
2864 strNewWalletPass.reserve(100);
2865 strNewWalletPass = params[1].get_str().c_str();
2866
2867 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
2868 throw runtime_error(
2869 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
2870 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
2871
2872 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
738835d7 2873 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
e3bc5698 2874
ed21d5bd 2875 return NullUniValue;
e3bc5698
JG
2876}
2877
2878
d014114d 2879UniValue walletlock(const UniValue& params, bool fHelp)
e3bc5698 2880{
b9fb692d 2881 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2882 return NullUniValue;
9d365796 2883
e3bc5698
JG
2884 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
2885 throw runtime_error(
2886 "walletlock\n"
a6099ef3 2887 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
e3bc5698 2888 "After calling this method, you will need to call walletpassphrase again\n"
a6099ef3 2889 "before being able to call any methods which require the wallet to be unlocked.\n"
2890 "\nExamples:\n"
2891 "\nSet the passphrase for 2 minutes to perform a transaction\n"
2892 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
2893 "\nPerform a send (requires passphrase set)\n"
1333d0d7 2894 + HelpExampleCli("sendtoaddress", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" 1.0") +
a6099ef3 2895 "\nClear the passphrase since we are done before 2 minutes is up\n"
2896 + HelpExampleCli("walletlock", "") +
2897 "\nAs json rpc call\n"
2898 + HelpExampleRpc("walletlock", "")
2899 );
2900
4401b2d7
EL
2901 LOCK2(cs_main, pwalletMain->cs_wallet);
2902
e3bc5698
JG
2903 if (fHelp)
2904 return true;
2905 if (!pwalletMain->IsCrypted())
738835d7 2906 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
e3bc5698
JG
2907
2908 {
2909 LOCK(cs_nWalletUnlockTime);
2910 pwalletMain->Lock();
2911 nWalletUnlockTime = 0;
2912 }
2913
ed21d5bd 2914 return NullUniValue;
e3bc5698
JG
2915}
2916
2917
d014114d 2918UniValue encryptwallet(const UniValue& params, bool fHelp)
e3bc5698 2919{
b9fb692d 2920 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2921 return NullUniValue;
62c0aa9e 2922
66dfcc13
LR
2923 string enableArg = "developerencryptwallet";
2924 auto fEnableWalletEncryption = fExperimentalMode && GetBoolArg("-" + enableArg, false);
62c0aa9e
JG
2925
2926 std::string strWalletEncryptionDisabledMsg = "";
2927 if (!fEnableWalletEncryption) {
66dfcc13 2928 strWalletEncryptionDisabledMsg = experimentalDisabledHelpMsg("encryptwallet", enableArg);
62c0aa9e
JG
2929 }
2930
e3bc5698
JG
2931 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
2932 throw runtime_error(
a6099ef3 2933 "encryptwallet \"passphrase\"\n"
62c0aa9e 2934 + strWalletEncryptionDisabledMsg +
a6099ef3 2935 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
2936 "After this, any calls that interact with private keys such as sending or signing \n"
2937 "will require the passphrase to be set prior the making these calls.\n"
2938 "Use the walletpassphrase call for this, and then walletlock call.\n"
2939 "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
2940 "Note that this will shutdown the server.\n"
2941 "\nArguments:\n"
2942 "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
2943 "\nExamples:\n"
2944 "\nEncrypt you wallet\n"
2945 + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
1333d0d7 2946 "\nNow set the passphrase to use the wallet, such as for signing or sending " + strprintf("%s",komodo_chainname()) + "\n"
a6099ef3 2947 + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
2948 "\nNow we can so something like sign\n"
1333d0d7 2949 + HelpExampleCli("signmessage", "\"" + strprintf("%s",komodo_chainname()) + "_address\" \"test message\"") +
a6099ef3 2950 "\nNow lock the wallet again by removing the passphrase\n"
2951 + HelpExampleCli("walletlock", "") +
2952 "\nAs a json rpc call\n"
2953 + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
2954 );
2955
4401b2d7
EL
2956 LOCK2(cs_main, pwalletMain->cs_wallet);
2957
e3bc5698
JG
2958 if (fHelp)
2959 return true;
62c0aa9e 2960 if (!fEnableWalletEncryption) {
1532cb75 2961 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet encryption is disabled.");
62c0aa9e 2962 }
e3bc5698 2963 if (pwalletMain->IsCrypted())
738835d7 2964 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
e3bc5698
JG
2965
2966 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2967 // Alternately, find a way to make params[0] mlock()'d to begin with.
2968 SecureString strWalletPass;
2969 strWalletPass.reserve(100);
2970 strWalletPass = params[0].get_str().c_str();
2971
2972 if (strWalletPass.length() < 1)
2973 throw runtime_error(
2974 "encryptwallet <passphrase>\n"
2975 "Encrypts the wallet with <passphrase>.");
2976
2977 if (!pwalletMain->EncryptWallet(strWalletPass))
738835d7 2978 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
e3bc5698
JG
2979
2980 // BDB seems to have a bad habit of writing old data into
2981 // slack space in .dat files; that is bad if the old data is
331544bc 2982 // unencrypted private keys. So:
e3bc5698 2983 StartShutdown();
b2a98c42 2984 return "wallet encrypted; Verus server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
e3bc5698
JG
2985}
2986
d014114d 2987UniValue lockunspent(const UniValue& params, bool fHelp)
fdbb537d 2988{
b9fb692d 2989 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2990 return NullUniValue;
9d365796 2991
fdbb537d
JG
2992 if (fHelp || params.size() < 1 || params.size() > 2)
2993 throw runtime_error(
a6099ef3 2994 "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
2995 "\nUpdates list of temporarily unspendable outputs.\n"
90fd8737 2996 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
1333d0d7 2997 "A locked transaction output will not be chosen by automatic coin selection, when spending " + strprintf("%s",komodo_chainname()) + ".\n"
a6099ef3 2998 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2999 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
3000 "Also see the listunspent call\n"
3001 "\nArguments:\n"
3002 "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
3003 "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
3004 " [ (json array of json objects)\n"
3005 " {\n"
3006 " \"txid\":\"id\", (string) The transaction id\n"
3007 " \"vout\": n (numeric) The output number\n"
3008 " }\n"
3009 " ,...\n"
3010 " ]\n"
3011
3012 "\nResult:\n"
3013 "true|false (boolean) Whether the command was successful or not\n"
3014
3015 "\nExamples:\n"
3016 "\nList the unspent transactions\n"
3017 + HelpExampleCli("listunspent", "") +
3018 "\nLock an unspent transaction\n"
3019 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
3020 "\nList the locked transactions\n"
3021 + HelpExampleCli("listlockunspent", "") +
3022 "\nUnlock the transaction again\n"
3023 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
3024 "\nAs a json rpc call\n"
3025 + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
3026 );
fdbb537d 3027
4401b2d7
EL
3028 LOCK2(cs_main, pwalletMain->cs_wallet);
3029
fdbb537d 3030 if (params.size() == 1)
ed21d5bd 3031 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL));
fdbb537d 3032 else
ed21d5bd 3033 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
fdbb537d
JG
3034
3035 bool fUnlock = params[0].get_bool();
3036
3037 if (params.size() == 1) {
3038 if (fUnlock)
3039 pwalletMain->UnlockAllCoins();
3040 return true;
3041 }
3042
851f58f9 3043 UniValue outputs = params[1].get_array();
cc71666a 3044 for (size_t idx = 0; idx < outputs.size(); idx++) {
ed21d5bd
JG
3045 const UniValue& output = outputs[idx];
3046 if (!output.isObject())
15117692 3047 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
d014114d 3048 const UniValue& o = output.get_obj();
fdbb537d 3049
ed21d5bd 3050 RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM));
fdbb537d
JG
3051
3052 string txid = find_value(o, "txid").get_str();
3053 if (!IsHex(txid))
15117692 3054 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
fdbb537d
JG
3055
3056 int nOutput = find_value(o, "vout").get_int();
3057 if (nOutput < 0)
15117692 3058 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
fdbb537d 3059
34cdc411 3060 COutPoint outpt(uint256S(txid), nOutput);
fdbb537d
JG
3061
3062 if (fUnlock)
3063 pwalletMain->UnlockCoin(outpt);
3064 else
3065 pwalletMain->LockCoin(outpt);
3066 }
3067
3068 return true;
3069}
3070
d014114d 3071UniValue listlockunspent(const UniValue& params, bool fHelp)
fdbb537d 3072{
b9fb692d 3073 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 3074 return NullUniValue;
9d365796 3075
fdbb537d
JG
3076 if (fHelp || params.size() > 0)
3077 throw runtime_error(
3078 "listlockunspent\n"
a6099ef3 3079 "\nReturns list of temporarily unspendable outputs.\n"
3080 "See the lockunspent call to lock and unlock transactions for spending.\n"
3081 "\nResult:\n"
3082 "[\n"
3083 " {\n"
3084 " \"txid\" : \"transactionid\", (string) The transaction id locked\n"
3085 " \"vout\" : n (numeric) The vout value\n"
3086 " }\n"
3087 " ,...\n"
3088 "]\n"
3089 "\nExamples:\n"
3090 "\nList the unspent transactions\n"
3091 + HelpExampleCli("listunspent", "") +
3092 "\nLock an unspent transaction\n"
3093 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
3094 "\nList the locked transactions\n"
3095 + HelpExampleCli("listlockunspent", "") +
3096 "\nUnlock the transaction again\n"
3097 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
3098 "\nAs a json rpc call\n"
3099 + HelpExampleRpc("listlockunspent", "")
3100 );
fdbb537d 3101
4401b2d7
EL
3102 LOCK2(cs_main, pwalletMain->cs_wallet);
3103
fdbb537d
JG
3104 vector<COutPoint> vOutpts;
3105 pwalletMain->ListLockedCoins(vOutpts);
3106
38fc4b70 3107 UniValue ret(UniValue::VARR);
fdbb537d
JG
3108
3109 BOOST_FOREACH(COutPoint &outpt, vOutpts) {
38fc4b70 3110 UniValue o(UniValue::VOBJ);
fdbb537d
JG
3111
3112 o.push_back(Pair("txid", outpt.hash.GetHex()));
3113 o.push_back(Pair("vout", (int)outpt.n));
3114 ret.push_back(o);
3115 }
3116
3117 return ret;
3118}
3119
d014114d 3120UniValue settxfee(const UniValue& params, bool fHelp)
a943bde6 3121{
b9fb692d 3122 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 3123 return NullUniValue;
9d365796 3124
a943bde6
WL
3125 if (fHelp || params.size() < 1 || params.size() > 1)
3126 throw runtime_error(
3127 "settxfee amount\n"
6943cb9b 3128 "\nSet the transaction fee per kB.\n"
a943bde6 3129 "\nArguments:\n"
1333d0d7 3130 "1. amount (numeric, required) The transaction fee in " + strprintf("%s",komodo_chainname()) + "/kB rounded to the nearest 0.00000001\n"
a943bde6
WL
3131 "\nResult\n"
3132 "true|false (boolean) Returns true if successful\n"
3133 "\nExamples:\n"
3134 + HelpExampleCli("settxfee", "0.00001")
3135 + HelpExampleRpc("settxfee", "0.00001")
3136 );
3137
4401b2d7
EL
3138 LOCK2(cs_main, pwalletMain->cs_wallet);
3139
a943bde6 3140 // Amount
e76a3849 3141 CAmount nAmount = AmountFromValue(params[0]);
a943bde6 3142
c6cb21d1 3143 payTxFee = CFeeRate(nAmount, 1000);
a943bde6
WL
3144 return true;
3145}
3146
d014114d 3147UniValue getwalletinfo(const UniValue& params, bool fHelp)
a00ebb51 3148{
b9fb692d 3149 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 3150 return NullUniValue;
9d365796 3151
a00ebb51
DN
3152 if (fHelp || params.size() != 0)
3153 throw runtime_error(
3154 "getwalletinfo\n"
3155 "Returns an object containing various wallet state info.\n"
3156 "\nResult:\n"
3157 "{\n"
3158 " \"walletversion\": xxxxx, (numeric) the wallet version\n"
1333d0d7 3159 " \"balance\": xxxxxxx, (numeric) the total confirmed balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
3a27113e 3160 " \"reserve_balance\": xxxxxxx, (numeric) for PBaaS reserve chains, the total confirmed reserve balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
1333d0d7 3161 " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
3a27113e 3162 " \"unconfirmed_reserve_balance\": xxx, (numeric) total unconfirmed reserve balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
1333d0d7 3163 " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
3a27113e 3164 " \"immature_reserve_balance\": xxxxxx, (numeric) total immature reserve balance of the wallet in " + strprintf("%s",komodo_chainname()) + "\n"
672414d7 3165 " \"eligible_staking_balance\": xxxxxx, (numeric) eligible staking balance in " + strprintf("%s",komodo_chainname()) + "\n"
a00ebb51
DN
3166 " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
3167 " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
3168 " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
3169 " \"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"
091b2116 3170 " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n"
d24ad4a6 3171 " \"seedfp\": \"uint256\", (string) the BLAKE2b-256 hash of the HD seed\n"
a00ebb51
DN
3172 "}\n"
3173 "\nExamples:\n"
3174 + HelpExampleCli("getwalletinfo", "")
3175 + HelpExampleRpc("getwalletinfo", "")
3176 );
3177
4401b2d7
EL
3178 LOCK2(cs_main, pwalletMain->cs_wallet);
3179
00b2551d 3180 uint32_t nHeight = chainActive.Height();
3181 bool checkunlockedIDs = CConstVerusSolutionVector::GetVersionByHeight(nHeight) >= CActivationHeight::ACTIVATE_PBAAS;
3182
38fc4b70 3183 UniValue obj(UniValue::VOBJ);
a00ebb51 3184 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
70cff737 3185
3186 CAmount allBal = pwalletMain->GetBalance();
3187 obj.push_back(Pair("balance", ValueFromAmount(allBal)));
00b2551d 3188 if (checkunlockedIDs)
3189 {
70cff737 3190 CAmount unlockBal = pwalletMain->GetBalance(false);
3191 if (unlockBal != allBal)
3192 {
3193 obj.push_back(Pair("unlocked_balance", ValueFromAmount(unlockBal)));
3194 }
00b2551d 3195 }
8024d67d 3196 obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
3a27113e 3197 obj.push_back(Pair("immature_balance", ValueFromAmount(pwalletMain->GetImmatureBalance())));
672414d7 3198
3199 std::vector<COutput> vecOutputs;
3200 CAmount totalStakingAmount = 0;
3201
672414d7 3202 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true, false);
3203
0f957664 3204 int numTransactions = 0;
3205 txnouttype whichType;
3206 std::vector<std::vector<unsigned char>> vSolutions;
3207
672414d7 3208 for (int i = 0; i < vecOutputs.size(); i++)
3209 {
3210 auto &txout = vecOutputs[i];
0f957664 3211 COptCCParams p;
672414d7 3212
3213 if (txout.tx &&
3214 txout.i < txout.tx->vout.size() &&
3215 txout.tx->vout[txout.i].nValue > 0 &&
3216 txout.fSpendable &&
3217 (txout.nDepth >= VERUS_MIN_STAKEAGE) &&
0f957664 3218 ((txout.tx->vout[txout.i].scriptPubKey.IsPayToCryptoCondition(p) &&
3219 p.IsValid() &&
3220 txout.tx->vout[txout.i].scriptPubKey.IsSpendableOutputType(p)) ||
3221 (!p.IsValid() &&
3222 Solver(txout.tx->vout[txout.i].scriptPubKey, whichType, vSolutions) &&
3223 (whichType == TX_PUBKEY || whichType == TX_PUBKEYHASH))))
672414d7 3224 {
3225 totalStakingAmount += txout.tx->vout[txout.i].nValue;
0f957664 3226 numTransactions++;
672414d7 3227 }
3228 }
3229
0f957664 3230 obj.push_back(Pair("eligible_staking_outputs", numTransactions));
672414d7 3231 obj.push_back(Pair("eligible_staking_balance", ValueFromAmount(totalStakingAmount)));
3232
58b4e7b5 3233 CCurrencyDefinition &chainDef = ConnectedChains.ThisChain();
cadf8969 3234 UniValue reserveBal(UniValue::VOBJ);
70cff737 3235 CCurrencyValueMap resBal = pwalletMain->GetReserveBalance();
d24ad4a6 3236
70cff737 3237 for (auto &oneBalance : resBal.valueMap)
58b4e7b5 3238 {
cadf8969 3239 reserveBal.push_back(make_pair(ConnectedChains.GetCachedCurrency(oneBalance.first).name, ValueFromAmount(oneBalance.second)));
58b4e7b5 3240 }
3241 if (reserveBal.size())
3242 {
00b2551d 3243 obj.push_back(Pair("reserve_balance", reserveBal));
3244 if (checkunlockedIDs)
289a7587 3245 {
00b2551d 3246 UniValue unlockedReserveBal(UniValue::VOBJ);
70cff737 3247 CCurrencyValueMap unlockedResBal = pwalletMain->GetReserveBalance(false);
3248 if (resBal != unlockedResBal)
00b2551d 3249 {
70cff737 3250 for (auto &oneBalance : unlockedResBal.valueMap)
3251 {
3252 unlockedReserveBal.push_back(make_pair(ConnectedChains.GetCachedCurrency(oneBalance.first).name, ValueFromAmount(oneBalance.second)));
3253 }
3254 obj.push_back(Pair("unlocked_reserve_balance", unlockedReserveBal));
00b2551d 3255 }
289a7587 3256 }
58b4e7b5 3257 }
3258
35b9e458 3259 UniValue unconfirmedReserveBal(UniValue::VOBJ);
58b4e7b5 3260 for (auto &oneBalance : pwalletMain->GetUnconfirmedReserveBalance().valueMap)
3261 {
35b9e458 3262 unconfirmedReserveBal.push_back(make_pair(ConnectedChains.GetCachedCurrency(oneBalance.first).name, ValueFromAmount(oneBalance.second)));
58b4e7b5 3263 }
3264 if (unconfirmedReserveBal.size())
3265 {
3266 obj.push_back(Pair("unconfirmed_reserve_balance", unconfirmedReserveBal));
3267 }
3268
35b9e458 3269 UniValue immatureReserveBal(UniValue::VOBJ);
58b4e7b5 3270 for (auto &oneBalance : pwalletMain->GetImmatureReserveBalance().valueMap)
3271 {
35b9e458 3272 immatureReserveBal.push_back(make_pair(ConnectedChains.GetCachedCurrency(oneBalance.first).name, ValueFromAmount(oneBalance.second)));
58b4e7b5 3273 }
3274 if (immatureReserveBal.size())
3275 {
3276 obj.push_back(Pair("immature_reserve_balance", immatureReserveBal));
3277 }
3278
3279 uint32_t height = chainActive.LastTip() ? chainActive.LastTip()->GetHeight() : 0;
3280
a00ebb51 3281 obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size()));
d56e30ca 3282 obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
a00ebb51
DN
3283 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
3284 if (pwalletMain->IsCrypted())
d56e30ca 3285 obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
6699b425 3286 obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
82e71233
JS
3287 uint256 seedFp = pwalletMain->GetHDChain().seedFp;
3288 if (!seedFp.IsNull())
3289 obj.push_back(Pair("seedfp", seedFp.GetHex()));
a00ebb51
DN
3290 return obj;
3291}
0f5954c4 3292
d014114d 3293UniValue resendwallettransactions(const UniValue& params, bool fHelp)
0f5954c4 3294{
b9fb692d 3295 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 3296 return NullUniValue;
9d365796 3297
0f5954c4
GA
3298 if (fHelp || params.size() != 0)
3299 throw runtime_error(
3300 "resendwallettransactions\n"
3301 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
3302 "Intended only for testing; the wallet code periodically re-broadcasts\n"
3303 "automatically.\n"
3304 "Returns array of transaction ids that were re-broadcast.\n"
3305 );
3306
3307 LOCK2(cs_main, pwalletMain->cs_wallet);
3308
3309 std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
38fc4b70 3310 UniValue result(UniValue::VARR);
0f5954c4
GA
3311 BOOST_FOREACH(const uint256& txid, txids)
3312 {
3313 result.push_back(txid.ToString());
3314 }
3315 return result;
3316}
0b9dc9c8 3317
d014114d 3318UniValue listunspent(const UniValue& params, bool fHelp)
0b9dc9c8
JS
3319{
3320 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 3321 return NullUniValue;
9d365796 3322
0b9dc9c8 3323 if (fHelp || params.size() > 3)
ea9e82df
JS
3324 throw runtime_error(
3325 "listunspent ( minconf maxconf [\"address\",...] )\n"
3326 "\nReturns array of unspent transaction outputs\n"
3327 "with between minconf and maxconf (inclusive) confirmations.\n"
3328 "Optionally filter to only include txouts paid to specified addresses.\n"
3329 "Results are an array of Objects, each of which has:\n"
3330 "{txid, vout, scriptPubKey, amount, confirmations}\n"
3331 "\nArguments:\n"
3332 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
3333 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
1333d0d7 3334 "3. \"addresses\" (string) A json array of " + strprintf("%s",komodo_chainname()) + " addresses to filter\n"
ea9e82df 3335 " [\n"
1333d0d7 3336 " \"address\" (string) " + strprintf("%s",komodo_chainname()) + " address\n"
ea9e82df
JS
3337 " ,...\n"
3338 " ]\n"
3339 "\nResult\n"
3340 "[ (array of json object)\n"
3341 " {\n"
181c511c 3342 " \"txid\" : \"txid\", (string) the transaction id \n"
ea9e82df 3343 " \"vout\" : n, (numeric) the vout value\n"
d77a0ac4 3344 " \"generated\" : true|false (boolean) true if txout is a coinbase transaction output\n"
181c511c
PB
3345 " \"address\" : \"address\", (string) the Zcash address\n"
3346 " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
3347 " \"scriptPubKey\" : \"key\", (string) the script key\n"
091b2116 3348 " \"amount\" : x.xxx, (numeric) the transaction amount in " + CURRENCY_UNIT + "\n"
181c511c
PB
3349 " \"confirmations\" : n, (numeric) The number of confirmations\n"
3350 " \"redeemScript\" : n (string) The redeemScript if scriptPubKey is P2SH\n"
3351 " \"spendable\" : xxx (bool) Whether we have the private keys to spend this output\n"
ea9e82df
JS
3352 " }\n"
3353 " ,...\n"
3354 "]\n"
3355
3356 "\nExamples\n"
3357 + HelpExampleCli("listunspent", "")
1333d0d7 3358 + HelpExampleCli("listunspent", "6 9999999 \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"")
3359 + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\",\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\"]\"")
ea9e82df
JS
3360 );
3361
9756b7bd 3362 RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
ea9e82df 3363
0b9dc9c8
JS
3364 int nMinDepth = 1;
3365 if (params.size() > 0)
ea9e82df
JS
3366 nMinDepth = params[0].get_int();
3367
0b9dc9c8
JS
3368 int nMaxDepth = 9999999;
3369 if (params.size() > 1)
ea9e82df
JS
3370 nMaxDepth = params[1].get_int();
3371
07444da1 3372 std::set<CTxDestination> destinations;
0b9dc9c8 3373 if (params.size() > 2) {
851f58f9 3374 UniValue inputs = params[2].get_array();
cc71666a 3375 for (size_t idx = 0; idx < inputs.size(); idx++) {
d014114d 3376 const UniValue& input = inputs[idx];
07444da1
PW
3377 CTxDestination dest = DecodeDestination(input.get_str());
3378 if (!IsValidDestination(dest)) {
5ae5090d 3379 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Verus address: ") + input.get_str());
07444da1
PW
3380 }
3381 if (!destinations.insert(dest).second) {
3382 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
3383 }
0b9dc9c8
JS
3384 }
3385 }
ea9e82df 3386
38fc4b70 3387 UniValue results(UniValue::VARR);
0b9dc9c8
JS
3388 vector<COutput> vecOutputs;
3389 assert(pwalletMain != NULL);
3390 LOCK2(cs_main, pwalletMain->cs_wallet);
219953ce 3391 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
0b9dc9c8
JS
3392 BOOST_FOREACH(const COutput& out, vecOutputs) {
3393 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
ea9e82df
JS
3394 continue;
3395
181c511c
PB
3396 CTxDestination address;
3397 const CScript& scriptPubKey = out.tx->vout[out.i].scriptPubKey;
3398 bool fValidAddress = ExtractDestination(scriptPubKey, address);
ea9e82df 3399
07444da1 3400 if (destinations.size() && (!fValidAddress || !destinations.count(address)))
181c511c 3401 continue;
ea9e82df 3402
38fc4b70 3403 UniValue entry(UniValue::VOBJ);
805344dc 3404 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
0b9dc9c8 3405 entry.push_back(Pair("vout", out.i));
d77a0ac4 3406 entry.push_back(Pair("generated", out.tx->IsCoinBase()));
181c511c
PB
3407
3408 if (fValidAddress) {
07444da1 3409 entry.push_back(Pair("address", EncodeDestination(address)));
181c511c 3410
0b9dc9c8 3411 if (pwalletMain->mapAddressBook.count(address))
ea9e82df 3412 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
181c511c
PB
3413
3414 if (scriptPubKey.IsPayToScriptHash()) {
8b08d953 3415 const CScriptID& hash = boost::get<CScriptID>(address);
0b9dc9c8
JS
3416 CScript redeemScript;
3417 if (pwalletMain->GetCScript(hash, redeemScript))
ea9e82df 3418 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
0b9dc9c8
JS
3419 }
3420 }
9feb4b9e 3421 CAmount nValue = out.tx->vout[out.i].nValue;
181c511c 3422 entry.push_back(Pair("amount", ValueFromAmount(out.tx->vout[out.i].nValue)));
9d9d90c5 3423
56fe75cb 3424 CCurrencyValueMap reserveOut;
4005d836 3425 if (ConnectedChains.ThisChain().IsFractional() && (reserveOut = out.tx->vout[out.i].scriptPubKey.ReserveOutValue()).valueMap.size())
9d9d90c5 3426 {
56fe75cb 3427 entry.push_back(Pair("reserveAmount", reserveOut.ToUniValue()));
9d9d90c5 3428 }
fdbf481f 3429 if ( out.tx->nLockTime != 0 )
e42867d1 3430 {
fdbf481f 3431 BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
0fec0cc4 3432 CBlockIndex *tipindex,*pindex = it->second;
e7876b36 3433 uint64_t interest; uint32_t locktime; int32_t txheight;
86131275 3434 if ( pindex != 0 && (tipindex= chainActive.LastTip()) != 0 )
fdbf481f 3435 {
4b729ec5 3436 interest = komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->GetHeight());
ae3f3fea 3437 //interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime);
fdbf481f 3438 entry.push_back(Pair("interest",ValueFromAmount(interest)));
e7876b36 3439 }
4b729ec5 3440 //fprintf(stderr,"nValue %.8f pindex.%p tipindex.%p locktime.%u txheight.%d pindexht.%d\n",(double)nValue/COIN,pindex,chainActive.LastTip(),locktime,txheight,pindex->GetHeight());
e42867d1 3441 }
9feb4b9e 3442 entry.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
181c511c 3443 entry.push_back(Pair("confirmations", out.nDepth));
0b9dc9c8
JS
3444 entry.push_back(Pair("spendable", out.fSpendable));
3445 results.push_back(entry);
3446 }
ea9e82df 3447
0b9dc9c8 3448 return results;
c9fd9078 3449}
730790f7 3450
da16b12e 3451uint64_t komodo_interestsum()
09e3cf94 3452{
6fd79871 3453#ifdef ENABLE_WALLET
7714b7f1 3454 if ( GetBoolArg("-disablewallet", false) == 0 )
09e3cf94 3455 {
aa7dc846 3456 KOMODO_INTERESTSUM = 0;
7714b7f1 3457 KOMODO_WALLETBALANCE = pwalletMain->GetBalance();
aa7dc846 3458 return(0);
09e3cf94 3459 }
6fd79871 3460#endif
7714b7f1 3461 return(0);
09e3cf94 3462}
3463
d72c19a6
S
3464
3465UniValue z_listunspent(const UniValue& params, bool fHelp)
3466{
3467 if (!EnsureWalletIsAvailable(fHelp))
3468 return NullUniValue;
3469
3470 if (fHelp || params.size() > 4)
3471 throw runtime_error(
3472 "z_listunspent ( minconf maxconf includeWatchonly [\"zaddr\",...] )\n"
3473 "\nReturns array of unspent shielded notes with between minconf and maxconf (inclusive) confirmations.\n"
3474 "Optionally filter to only include notes sent to specified addresses.\n"
3475 "When minconf is 0, unspent notes with zero confirmations are returned, even though they are not immediately spendable.\n"
3476 "Results are an array of Objects, each of which has:\n"
5f57babd
S
3477 "{txid, jsindex, jsoutindex, confirmations, address, amount, memo} (Sprout)\n"
3478 "{txid, outindex, confirmations, address, amount, memo} (Sapling)\n"
d72c19a6
S
3479 "\nArguments:\n"
3480 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
3481 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
3482 "3. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n"
66795a40 3483 "4. \"addresses\" (string) A json array of zaddrs (both Sprout and Sapling) to filter on. Duplicate addresses not allowed.\n"
d72c19a6
S
3484 " [\n"
3485 " \"address\" (string) zaddr\n"
3486 " ,...\n"
3487 " ]\n"
3488 "\nResult\n"
3489 "[ (array of json object)\n"
3490 " {\n"
3491 " \"txid\" : \"txid\", (string) the transaction id \n"
4c646bb4
GD
3492 " \"jsindex\" (sprout) : n, (numeric) the joinsplit index\n"
3493 " \"jsoutindex\" (sprout) : n, (numeric) the output index of the joinsplit\n"
3494 " \"outindex\" (sapling) : n, (numeric) the output index\n"
3495 " \"confirmations\" : n, (numeric) the number of confirmations\n"
3496 " \"spendable\" : true|false, (boolean) true if note can be spent by wallet, false if address is watchonly\n"
d72c19a6
S
3497 " \"address\" : \"address\", (string) the shielded address\n"
3498 " \"amount\": xxxxx, (numeric) the amount of value in the note\n"
3499 " \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
0646f749 3500 " \"change\": true|false, (boolean) true if the address that received the note is also one of the sending addresses\n"
d72c19a6
S
3501 " }\n"
3502 " ,...\n"
3503 "]\n"
3504
3505 "\nExamples\n"
3506 + HelpExampleCli("z_listunspent", "")
3507 + HelpExampleCli("z_listunspent", "6 9999999 false \"[\\\"ztbx5DLDxa5ZLFTchHhoPNkKs57QzSyib6UqXpEdy76T1aUdFxJt1w9318Z8DJ73XzbnWHKEZP9Yjg712N5kMmP4QzS9iC9\\\",\\\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\\\"]\"")
3508 + HelpExampleRpc("z_listunspent", "6 9999999 false \"[\\\"ztbx5DLDxa5ZLFTchHhoPNkKs57QzSyib6UqXpEdy76T1aUdFxJt1w9318Z8DJ73XzbnWHKEZP9Yjg712N5kMmP4QzS9iC9\\\",\\\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\\\"]\"")
3509 );
3510
3511 RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VBOOL)(UniValue::VARR));
3512
3513 int nMinDepth = 1;
3514 if (params.size() > 0) {
3515 nMinDepth = params[0].get_int();
3516 }
3517 if (nMinDepth < 0) {
3518 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3519 }
3520
3521 int nMaxDepth = 9999999;
3522 if (params.size() > 1) {
3523 nMaxDepth = params[1].get_int();
3524 }
3525 if (nMaxDepth < nMinDepth) {
3526 throw JSONRPCError(RPC_INVALID_PARAMETER, "Maximum number of confirmations must be greater or equal to the minimum number of confirmations");
3527 }
3528
3529 std::set<libzcash::PaymentAddress> zaddrs = {};
3530
3531 bool fIncludeWatchonly = false;
3532 if (params.size() > 2) {
3533 fIncludeWatchonly = params[2].get_bool();
3534 }
3535
3536 LOCK2(cs_main, pwalletMain->cs_wallet);
3537
3538 // User has supplied zaddrs to filter on
3539 if (params.size() > 3) {
3540 UniValue addresses = params[3].get_array();
3541 if (addresses.size()==0)
3542 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, addresses array is empty.");
3543
3544 // Keep track of addresses to spot duplicates
3545 set<std::string> setAddress;
3546
3547 // Sources
3548 for (const UniValue& o : addresses.getValues()) {
3549 if (!o.isStr()) {
3550 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
3551 }
3552 string address = o.get_str();
80ed13d5 3553 auto zaddr = DecodePaymentAddress(address);
27a6a99c 3554 if (!IsValidPaymentAddress(zaddr)) {
d72c19a6
S
3555 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, address is not a valid zaddr: ") + address);
3556 }
27a6a99c
LR
3557 auto hasSpendingKey = boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr);
3558 if (!fIncludeWatchonly && !hasSpendingKey) {
3559 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, spending key for address does not belong to wallet: ") + address);
3560 }
3561 zaddrs.insert(zaddr);
d72c19a6
S
3562
3563 if (setAddress.count(address)) {
3564 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + address);
3565 }
3566 setAddress.insert(address);
3567 }
3568 }
3569 else {
3570 // User did not provide zaddrs, so use default i.e. all addresses
e5eab182 3571 std::set<libzcash::SproutPaymentAddress> sproutzaddrs = {};
25d5e80c 3572 pwalletMain->GetSproutPaymentAddresses(sproutzaddrs);
66795a40 3573
cd1c6e37 3574 // Sapling support
66795a40
JG
3575 std::set<libzcash::SaplingPaymentAddress> saplingzaddrs = {};
3576 pwalletMain->GetSaplingPaymentAddresses(saplingzaddrs);
3577
e5eab182 3578 zaddrs.insert(sproutzaddrs.begin(), sproutzaddrs.end());
66795a40 3579 zaddrs.insert(saplingzaddrs.begin(), saplingzaddrs.end());
d72c19a6
S
3580 }
3581
3582 UniValue results(UniValue::VARR);
3583
3584 if (zaddrs.size() > 0) {
a630f503 3585 std::vector<SproutNoteEntry> sproutEntries;
9396b85d 3586 std::vector<SaplingNoteEntry> saplingEntries;
e92414f9 3587 pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs, nMinDepth, nMaxDepth, true, !fIncludeWatchonly, false);
0646f749 3588 std::set<std::pair<PaymentAddress, uint256>> nullifierSet = pwalletMain->GetNullifiersForAddresses(zaddrs);
66795a40 3589
9396b85d 3590 for (auto & entry : sproutEntries) {
d72c19a6 3591 UniValue obj(UniValue::VOBJ);
0646f749 3592 obj.push_back(Pair("txid", entry.jsop.hash.ToString()));
d72c19a6
S
3593 obj.push_back(Pair("jsindex", (int)entry.jsop.js ));
3594 obj.push_back(Pair("jsoutindex", (int)entry.jsop.n));
9396b85d 3595 obj.push_back(Pair("confirmations", entry.confirmations));
79298516
EOW
3596 bool hasSproutSpendingKey = pwalletMain->HaveSproutSpendingKey(boost::get<libzcash::SproutPaymentAddress>(entry.address));
3597 obj.push_back(Pair("spendable", hasSproutSpendingKey));
80ed13d5 3598 obj.push_back(Pair("address", EncodePaymentAddress(entry.address)));
a630f503
E
3599 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.note.value()))));
3600 std::string data(entry.memo.begin(), entry.memo.end());
d72c19a6 3601 obj.push_back(Pair("memo", HexStr(data)));
79298516 3602 if (hasSproutSpendingKey) {
e4f0d6a8 3603 obj.push_back(Pair("change", pwalletMain->IsNoteSproutChange(nullifierSet, entry.address, entry.jsop)));
79298516 3604 }
d72c19a6
S
3605 results.push_back(obj);
3606 }
66795a40 3607
9396b85d 3608 for (auto & entry : saplingEntries) {
5f57babd
S
3609 UniValue obj(UniValue::VOBJ);
3610 obj.push_back(Pair("txid", entry.op.hash.ToString()));
3611 obj.push_back(Pair("outindex", (int)entry.op.n));
9396b85d 3612 obj.push_back(Pair("confirmations", entry.confirmations));
5f57babd
S
3613 libzcash::SaplingIncomingViewingKey ivk;
3614 libzcash::SaplingFullViewingKey fvk;
3615 pwalletMain->GetSaplingIncomingViewingKey(boost::get<libzcash::SaplingPaymentAddress>(entry.address), ivk);
3616 pwalletMain->GetSaplingFullViewingKey(ivk, fvk);
3617 bool hasSaplingSpendingKey = pwalletMain->HaveSaplingSpendingKey(fvk);
3618 obj.push_back(Pair("spendable", hasSaplingSpendingKey));
3619 obj.push_back(Pair("address", EncodePaymentAddress(entry.address)));
3620 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.note.value())))); // note.value() is equivalent to plaintext.value()
3621 obj.push_back(Pair("memo", HexStr(entry.memo)));
3622 if (hasSaplingSpendingKey) {
3623 obj.push_back(Pair("change", pwalletMain->IsNoteSaplingChange(nullifierSet, entry.address, entry.op)));
79298516 3624 }
d72c19a6
S
3625 results.push_back(obj);
3626 }
3627 }
3628
3629 return results;
3630}
3631
3632
3d8013a0
MC
3633UniValue fundrawtransaction(const UniValue& params, bool fHelp)
3634{
3635 if (!EnsureWalletIsAvailable(fHelp))
3636 return NullUniValue;
3637
3638 if (fHelp || params.size() != 1)
3639 throw runtime_error(
3640 "fundrawtransaction \"hexstring\"\n"
3641 "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
3642 "This will not modify existing inputs, and will add one change output to the outputs.\n"
3643 "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
3644 "The inputs added will not be signed, use signrawtransaction for that.\n"
3645 "\nArguments:\n"
3646 "1. \"hexstring\" (string, required) The hex string of the raw transaction\n"
3647 "\nResult:\n"
3648 "{\n"
3649 " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
3650 " \"fee\": n, (numeric) The fee added to the transaction\n"
3651 " \"changepos\": n (numeric) The position of the added change output, or -1\n"
3652 "}\n"
3653 "\"hex\" \n"
3654 "\nExamples:\n"
3655 "\nCreate a transaction with no inputs\n"
3656 + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
3657 "\nAdd sufficient unsigned inputs to meet the output value\n"
3658 + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
3659 "\nSign the transaction\n"
3660 + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
3661 "\nSend the transaction\n"
3662 + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
3663 );
3664
3665 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
3666
3667 // parse hex string from parameter
3668 CTransaction origTx;
3669 if (!DecodeHexTx(origTx, params[0].get_str()))
3670 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
3671
3672 CMutableTransaction tx(origTx);
3673 CAmount nFee;
3674 string strFailReason;
3675 int nChangePos = -1;
3676 if(!pwalletMain->FundTransaction(tx, nFee, nChangePos, strFailReason))
3677 throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
3678
3679 UniValue result(UniValue::VOBJ);
3680 result.push_back(Pair("hex", EncodeHexTx(tx)));
3681 result.push_back(Pair("changepos", nChangePos));
3682 result.push_back(Pair("fee", ValueFromAmount(nFee)));
3683
3684 return result;
3685}
3686
0d37ae3a 3687UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp)
1737627c
SB
3688{
3689 if (fHelp) {
3690 throw runtime_error(
3691 "zcsamplejoinsplit\n"
3692 "\n"
3693 "Perform a joinsplit and return the JSDescription.\n"
3694 );
3695 }
3696
3697 LOCK(cs_main);
3698
e1a3461c 3699 uint256 joinSplitPubKey;
4fc309f0 3700 uint256 anchor = SproutMerkleTree().root();
34f6ea95 3701 JSDescription samplejoinsplit(true,
b7a6c321 3702 *pzcashParams,
e1a3461c 3703 joinSplitPubKey,
1737627c
SB
3704 anchor,
3705 {JSInput(), JSInput()},
3706 {JSOutput(), JSOutput()},
3707 0,
3708 0);
3709
f55029e7 3710 CDataStream ss(SER_NETWORK, SAPLING_TX_VERSION | (1 << 31));
1737627c
SB
3711 ss << samplejoinsplit;
3712
3713 return HexStr(ss.begin(), ss.end());
3714}
3715
0d37ae3a 3716UniValue zc_benchmark(const UniValue& params, bool fHelp)
6962bb3d
TH
3717{
3718 if (!EnsureWalletIsAvailable(fHelp)) {
0d37ae3a 3719 return NullUniValue;
6962bb3d
TH
3720 }
3721
3722 if (fHelp || params.size() < 2) {
3723 throw runtime_error(
3724 "zcbenchmark benchmarktype samplecount\n"
3725 "\n"
3726 "Runs a benchmark of the selected type samplecount times,\n"
3727 "returning the running times of each sample.\n"
3728 "\n"
3729 "Output: [\n"
3730 " {\n"
3731 " \"runningtime\": runningtime\n"
3732 " },\n"
3733 " {\n"
3734 " \"runningtime\": runningtime\n"
3735 " }\n"
3736 " ...\n"
3737 "]\n"
3738 );
3739 }
3740
3741 LOCK(cs_main);
3742
3743 std::string benchmarktype = params[0].get_str();
3744 int samplecount = params[1].get_int();
3745
3746 if (samplecount <= 0) {
3747 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount");
3748 }
3749
3750 std::vector<double> sample_times;
3751
1737627c 3752 JSDescription samplejoinsplit;
2fbbde59
SB
3753
3754 if (benchmarktype == "verifyjoinsplit") {
f55029e7 3755 CDataStream ss(ParseHexV(params[2].get_str(), "js"), SER_NETWORK, SAPLING_TX_VERSION | (1 << 31));
1737627c 3756 ss >> samplejoinsplit;
2fbbde59
SB
3757 }
3758
6962bb3d
TH
3759 for (int i = 0; i < samplecount; i++) {
3760 if (benchmarktype == "sleep") {
3761 sample_times.push_back(benchmark_sleep());
3762 } else if (benchmarktype == "parameterloading") {
3763 sample_times.push_back(benchmark_parameter_loading());
3764 } else if (benchmarktype == "createjoinsplit") {
4082dcb1
JG
3765 if (params.size() < 3) {
3766 sample_times.push_back(benchmark_create_joinsplit());
3767 } else {
3768 int nThreads = params[2].get_int();
3769 std::vector<double> vals = benchmark_create_joinsplit_threaded(nThreads);
3770 // Divide by nThreads^2 to get average seconds per JoinSplit because
3771 // we are running one JoinSplit per thread.
3772 sample_times.push_back(std::accumulate(vals.begin(), vals.end(), 0.0) / (nThreads*nThreads));
3773 }
6962bb3d 3774 } else if (benchmarktype == "verifyjoinsplit") {
1737627c 3775 sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
2cc0a252 3776#ifdef ENABLE_MINING
bf8def97 3777 } else if (benchmarktype == "solveequihash") {
f7478de6 3778 if (params.size() < 3) {
9e52ca32 3779 sample_times.push_back(benchmark_solve_equihash());
f7478de6
JG
3780 } else {
3781 int nThreads = params[2].get_int();
9e52ca32
JG
3782 std::vector<double> vals = benchmark_solve_equihash_threaded(nThreads);
3783 sample_times.insert(sample_times.end(), vals.begin(), vals.end());
f7478de6 3784 }
2cc0a252 3785#endif
bf8def97 3786 } else if (benchmarktype == "verifyequihash") {
a1cd1a27 3787 sample_times.push_back(benchmark_verify_equihash());
f5edc37f 3788 } else if (benchmarktype == "validatelargetx") {
818b94f9 3789 // Number of inputs in the spending transaction that we will simulate
ddcee7e1 3790 int nInputs = 11130;
818b94f9
JG
3791 if (params.size() >= 3) {
3792 nInputs = params[2].get_int();
3793 }
3794 sample_times.push_back(benchmark_large_tx(nInputs));
0fbab55b 3795 } else if (benchmarktype == "trydecryptnotes") {
3e5cc59c
EOW
3796 int nKeys = params[2].get_int();
3797 sample_times.push_back(benchmark_try_decrypt_sprout_notes(nKeys));
89e75c8c 3798 } else if (benchmarktype == "trydecryptsaplingnotes") {
3e5cc59c
EOW
3799 int nKeys = params[2].get_int();
3800 sample_times.push_back(benchmark_try_decrypt_sapling_notes(nKeys));
0bb3d40f
JG
3801 } else if (benchmarktype == "incnotewitnesses") {
3802 int nTxs = params[2].get_int();
8a1d1930
EOW
3803 sample_times.push_back(benchmark_increment_sprout_note_witnesses(nTxs));
3804 } else if (benchmarktype == "incsaplingnotewitnesses") {
3e5cc59c 3805 int nTxs = params[2].get_int();
8a1d1930 3806 sample_times.push_back(benchmark_increment_sapling_note_witnesses(nTxs));
c66c731a
JG
3807 } else if (benchmarktype == "connectblockslow") {
3808 if (Params().NetworkIDString() != "regtest") {
3809 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
3810 }
3811 sample_times.push_back(benchmark_connectblock_slow());
a76174b7
JG
3812 } else if (benchmarktype == "sendtoaddress") {
3813 if (Params().NetworkIDString() != "regtest") {
3814 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
3815 }
3816 auto amount = AmountFromValue(params[2]);
3817 sample_times.push_back(benchmark_sendtoaddress(amount));
2e8aefdc
AG
3818 } else if (benchmarktype == "loadwallet") {
3819 if (Params().NetworkIDString() != "regtest") {
3820 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
3821 }
3822 sample_times.push_back(benchmark_loadwallet());
99dd50c3
JG
3823 } else if (benchmarktype == "listunspent") {
3824 sample_times.push_back(benchmark_listunspent());
67d2b797
S
3825 } else if (benchmarktype == "createsaplingspend") {
3826 sample_times.push_back(benchmark_create_sapling_spend());
3827 } else if (benchmarktype == "createsaplingoutput") {
3828 sample_times.push_back(benchmark_create_sapling_output());
3829 } else if (benchmarktype == "verifysaplingspend") {
3830 sample_times.push_back(benchmark_verify_sapling_spend());
3831 } else if (benchmarktype == "verifysaplingoutput") {
3832 sample_times.push_back(benchmark_verify_sapling_output());
6962bb3d
TH
3833 } else {
3834 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
3835 }
3836 }
3837
0d37ae3a 3838 UniValue results(UniValue::VARR);
9e52ca32 3839 for (auto time : sample_times) {
0d37ae3a 3840 UniValue result(UniValue::VOBJ);
9e52ca32 3841 result.push_back(Pair("runningtime", time));
6962bb3d
TH
3842 results.push_back(result);
3843 }
3844
3845 return results;
3846}
3847
0d37ae3a 3848UniValue zc_raw_receive(const UniValue& params, bool fHelp)
a8ac403d 3849{
f15b9549 3850 if (!EnsureWalletIsAvailable(fHelp)) {
0d37ae3a 3851 return NullUniValue;
f15b9549
NW
3852 }
3853
3854 if (fHelp || params.size() != 2) {
3855 throw runtime_error(
eae37941 3856 "zcrawreceive zcsecretkey encryptednote\n"
f15b9549 3857 "\n"
ca0ec80b 3858 "DEPRECATED. Decrypts encryptednote and checks if the coin commitments\n"
f15b9549
NW
3859 "are in the blockchain as indicated by the \"exists\" result.\n"
3860 "\n"
3861 "Output: {\n"
3862 " \"amount\": value,\n"
4bc00dc1 3863 " \"note\": noteplaintext,\n"
f15b9549
NW
3864 " \"exists\": exists\n"
3865 "}\n"
3866 );
3867 }
3868
0d37ae3a 3869 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR));
f15b9549 3870
a8ac403d
SB
3871 LOCK(cs_main);
3872
472f75bc 3873 auto spendingkey = DecodeSpendingKey(params[0].get_str());
e5eab182 3874 if (!IsValidSpendingKey(spendingkey)) {
472f75bc
JG
3875 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
3876 }
e5eab182
JG
3877 if (boost::get<libzcash::SproutSpendingKey>(&spendingkey) == nullptr) {
3878 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout spending keys");
3879 }
3880 SproutSpendingKey k = boost::get<libzcash::SproutSpendingKey>(spendingkey);
a8ac403d 3881
6c36a9fe
SB
3882 uint256 epk;
3883 unsigned char nonce;
3884 ZCNoteEncryption::Ciphertext ct;
2dc35992 3885 uint256 h_sig;
6c36a9fe
SB
3886
3887 {
4bc00dc1 3888 CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
6c36a9fe
SB
3889 try {
3890 ssData >> nonce;
3891 ssData >> epk;
3892 ssData >> ct;
2dc35992 3893 ssData >> h_sig;
6c36a9fe
SB
3894 } catch(const std::exception &) {
3895 throw runtime_error(
4bc00dc1 3896 "encrypted_note could not be decoded"
6c36a9fe
SB
3897 );
3898 }
3899 }
3900
642a1caf 3901 ZCNoteDecryption decryptor(k.receiving_key());
a8ac403d 3902
5020a936 3903 SproutNotePlaintext npt = SproutNotePlaintext::decrypt(
2dc35992
SB
3904 decryptor,
3905 ct,
3906 epk,
3907 h_sig,
3908 nonce
3909 );
e5eab182 3910 SproutPaymentAddress payment_addr = k.address();
b230fe68 3911 SproutNote decrypted_note = npt.note(payment_addr);
a8ac403d
SB
3912
3913 assert(pwalletMain != NULL);
8ea8ef98 3914 std::vector<boost::optional<SproutWitness>> witnesses;
a8ac403d 3915 uint256 anchor;
2dc35992 3916 uint256 commitment = decrypted_note.cm();
4bc00dc1 3917 pwalletMain->WitnessNoteCommitment(
2dc35992
SB
3918 {commitment},
3919 witnesses,
3920 anchor
3921 );
a8ac403d
SB
3922
3923 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2dc35992 3924 ss << npt;
a8ac403d 3925
0d37ae3a 3926 UniValue result(UniValue::VOBJ);
5d99e3e9 3927 result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value())));
4bc00dc1 3928 result.push_back(Pair("note", HexStr(ss.begin(), ss.end())));
2dc35992 3929 result.push_back(Pair("exists", (bool) witnesses[0]));
a8ac403d
SB
3930 return result;
3931}
3932
2dc35992
SB
3933
3934
0d37ae3a 3935UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
730790f7 3936{
f15b9549 3937 if (!EnsureWalletIsAvailable(fHelp)) {
0d37ae3a 3938 return NullUniValue;
f15b9549
NW
3939 }
3940
3941 if (fHelp || params.size() != 5) {
3942 throw runtime_error(
eae37941 3943 "zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
4bc00dc1 3944 " inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
f15b9549
NW
3945 " outputs: a JSON object mapping {zcaddr: value, ...}\n"
3946 "\n"
ca0ec80b 3947 "DEPRECATED. Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
f15b9549
NW
3948 "Outputs are confidential between sender/receiver. The vpub_old and\n"
3949 "vpub_new values are globally public and move transparent value into\n"
3950 "or out of the confidential value store, respectively.\n"
3951 "\n"
3952 "Note: The caller is responsible for delivering the output enc1 and\n"
3953 "enc2 to the appropriate recipients, as well as signing rawtxout and\n"
3954 "ensuring it is mined. (A future RPC call will deliver the confidential\n"
3955 "payments in-band on the blockchain.)\n"
3956 "\n"
3957 "Output: {\n"
4bc00dc1
DH
3958 " \"encryptednote1\": enc1,\n"
3959 " \"encryptednote2\": enc2,\n"
f15b9549
NW
3960 " \"rawtxn\": rawtxout\n"
3961 "}\n"
3962 );
3963 }
3964
a8ac403d 3965 LOCK(cs_main);
730790f7
SB
3966
3967 CTransaction tx;
3968 if (!DecodeHexTx(tx, params[0].get_str()))
3969 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
3970
0d37ae3a
JG
3971 UniValue inputs = params[1].get_obj();
3972 UniValue outputs = params[2].get_obj();
730790f7
SB
3973
3974 CAmount vpub_old(0);
3975 CAmount vpub_new(0);
3976
3977 if (params[3].get_real() != 0.0)
3978 vpub_old = AmountFromValue(params[3]);
3979
3980 if (params[4].get_real() != 0.0)
3981 vpub_new = AmountFromValue(params[4]);
3982
b7e4abd6
SB
3983 std::vector<JSInput> vjsin;
3984 std::vector<JSOutput> vjsout;
b230fe68 3985 std::vector<SproutNote> notes;
e5eab182 3986 std::vector<SproutSpendingKey> keys;
2dc35992 3987 std::vector<uint256> commitments;
a8ac403d 3988
0d37ae3a 3989 for (const string& name_ : inputs.getKeys()) {
472f75bc 3990 auto spendingkey = DecodeSpendingKey(inputs[name_].get_str());
e5eab182 3991 if (!IsValidSpendingKey(spendingkey)) {
472f75bc
JG
3992 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
3993 }
e5eab182
JG
3994 if (boost::get<libzcash::SproutSpendingKey>(&spendingkey) == nullptr) {
3995 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout spending keys");
3996 }
3997 SproutSpendingKey k = boost::get<libzcash::SproutSpendingKey>(spendingkey);
a8ac403d 3998
2dc35992 3999 keys.push_back(k);
a8ac403d 4000
5020a936 4001 SproutNotePlaintext npt;
a8ac403d 4002
2dc35992 4003 {
0d37ae3a 4004 CDataStream ssData(ParseHexV(name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
2dc35992 4005 ssData >> npt;
a8ac403d
SB
4006 }
4007
e5eab182 4008 SproutPaymentAddress addr = k.address();
b230fe68 4009 SproutNote note = npt.note(addr);
2dc35992
SB
4010 notes.push_back(note);
4011 commitments.push_back(note.cm());
4012 }
4013
4014 uint256 anchor;
8ea8ef98 4015 std::vector<boost::optional<SproutWitness>> witnesses;
4bc00dc1 4016 pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
2dc35992
SB
4017
4018 assert(witnesses.size() == notes.size());
4019 assert(notes.size() == keys.size());
4020
4021 {
4022 for (size_t i = 0; i < witnesses.size(); i++) {
4023 if (!witnesses[i]) {
4024 throw runtime_error(
b7e4abd6 4025 "joinsplit input could not be found in tree"
2dc35992
SB
4026 );
4027 }
4028
b7e4abd6 4029 vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
2dc35992 4030 }
730790f7 4031 }
730790f7 4032
b7e4abd6
SB
4033 while (vjsin.size() < ZC_NUM_JS_INPUTS) {
4034 vjsin.push_back(JSInput());
a8ac403d 4035 }
730790f7 4036
0d37ae3a 4037 for (const string& name_ : outputs.getKeys()) {
80ed13d5 4038 auto addrTo = DecodePaymentAddress(name_);
e5eab182 4039 if (!IsValidPaymentAddress(addrTo)) {
80ed13d5
JG
4040 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid recipient address.");
4041 }
e5eab182
JG
4042 if (boost::get<libzcash::SproutPaymentAddress>(&addrTo) == nullptr) {
4043 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout payment addresses");
4044 }
0d37ae3a 4045 CAmount nAmount = AmountFromValue(outputs[name_]);
730790f7 4046
e5eab182 4047 vjsout.push_back(JSOutput(boost::get<libzcash::SproutPaymentAddress>(addrTo), nAmount));
730790f7
SB
4048 }
4049
b7e4abd6
SB
4050 while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
4051 vjsout.push_back(JSOutput());
730790f7
SB
4052 }
4053
4054 // TODO
b7e4abd6
SB
4055 if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
4056 throw runtime_error("unsupported joinsplit input/output counts");
730790f7
SB
4057 }
4058
320f2cc7
SB
4059 uint256 joinSplitPubKey;
4060 unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
4061 crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
6aae9d1a
TH
4062
4063 CMutableTransaction mtx(tx);
4064 mtx.nVersion = 2;
4065 mtx.joinSplitPubKey = joinSplitPubKey;
4066
b7a6c321
SB
4067 JSDescription jsdesc(false,
4068 *pzcashParams,
22de1602
SB
4069 joinSplitPubKey,
4070 anchor,
4071 {vjsin[0], vjsin[1]},
4072 {vjsout[0], vjsout[1]},
4073 vpub_old,
4074 vpub_new);
320f2cc7 4075
bc59f537
SB
4076 {
4077 auto verifier = libzcash::ProofVerifier::Strict();
4078 assert(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey));
4079 }
730790f7 4080
f57f76d7 4081 mtx.vJoinSplit.push_back(jsdesc);
730790f7 4082
6aae9d1a
TH
4083 // Empty output script.
4084 CScript scriptCode;
4085 CTransaction signTx(mtx);
be126699
JG
4086 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
4087 uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
6aae9d1a
TH
4088
4089 // Add the signature
320f2cc7
SB
4090 assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
4091 dataToBeSigned.begin(), 32,
4092 joinSplitPrivKey
4093 ) == 0);
4094
4095 // Sanity check
4096 assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
4097 dataToBeSigned.begin(), 32,
4098 mtx.joinSplitPubKey.begin()
4099 ) == 0);
6aae9d1a 4100
730790f7
SB
4101 CTransaction rawTx(mtx);
4102
4103 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
4104 ss << rawTx;
4105
4bc00dc1
DH
4106 std::string encryptedNote1;
4107 std::string encryptedNote2;
6c36a9fe
SB
4108 {
4109 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
4110 ss2 << ((unsigned char) 0x00);
22de1602
SB
4111 ss2 << jsdesc.ephemeralKey;
4112 ss2 << jsdesc.ciphertexts[0];
4113 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
6c36a9fe 4114
4bc00dc1 4115 encryptedNote1 = HexStr(ss2.begin(), ss2.end());
6c36a9fe
SB
4116 }
4117 {
4118 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
4119 ss2 << ((unsigned char) 0x01);
22de1602
SB
4120 ss2 << jsdesc.ephemeralKey;
4121 ss2 << jsdesc.ciphertexts[1];
4122 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
6c36a9fe 4123
4bc00dc1 4124 encryptedNote2 = HexStr(ss2.begin(), ss2.end());
6c36a9fe
SB
4125 }
4126
0d37ae3a 4127 UniValue result(UniValue::VOBJ);
4bc00dc1
DH
4128 result.push_back(Pair("encryptednote1", encryptedNote1));
4129 result.push_back(Pair("encryptednote2", encryptedNote2));
730790f7
SB
4130 result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
4131 return result;
4132}
4133
0d37ae3a 4134UniValue zc_raw_keygen(const UniValue& params, bool fHelp)
730790f7 4135{
f15b9549 4136 if (!EnsureWalletIsAvailable(fHelp)) {
0d37ae3a 4137 return NullUniValue;
f15b9549
NW
4138 }
4139
4140 if (fHelp || params.size() != 0) {
4141 throw runtime_error(
eae37941 4142 "zcrawkeygen\n"
f15b9549 4143 "\n"
ca0ec80b 4144 "DEPRECATED. Generate a zcaddr which can send and receive confidential values.\n"
f15b9549
NW
4145 "\n"
4146 "Output: {\n"
4147 " \"zcaddress\": zcaddr,\n"
4148 " \"zcsecretkey\": zcsecretkey,\n"
7b8d4f87 4149 " \"zcviewingkey\": zcviewingkey,\n"
f15b9549
NW
4150 "}\n"
4151 );
4152 }
4153
e5eab182 4154 auto k = SproutSpendingKey::random();
2dc35992
SB
4155 auto addr = k.address();
4156 auto viewing_key = k.viewing_key();
730790f7 4157
0d37ae3a 4158 UniValue result(UniValue::VOBJ);
80ed13d5 4159 result.push_back(Pair("zcaddress", EncodePaymentAddress(addr)));
472f75bc 4160 result.push_back(Pair("zcsecretkey", EncodeSpendingKey(k)));
8bf3a3d7 4161 result.push_back(Pair("zcviewingkey", EncodeViewingKey(viewing_key)));
730790f7 4162 return result;
f15b9549 4163}
c1c45943
S
4164
4165
0d37ae3a 4166UniValue z_getnewaddress(const UniValue& params, bool fHelp)
c1c45943
S
4167{
4168 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 4169 return NullUniValue;
c1c45943 4170
e9cf0166 4171 std::string defaultType = ADDR_TYPE_SAPLING;
eec85c43
JG
4172
4173 if (fHelp || params.size() > 1)
c1c45943 4174 throw runtime_error(
eec85c43
JG
4175 "z_getnewaddress ( type )\n"
4176 "\nReturns a new shielded address for receiving payments.\n"
6eec2812 4177 "\nWith no arguments, returns a Sapling address.\n"
c1c45943 4178 "\nArguments:\n"
eec85c43
JG
4179 "1. \"type\" (string, optional, default=\"" + defaultType + "\") The type of address. One of [\""
4180 + ADDR_TYPE_SPROUT + "\", \"" + ADDR_TYPE_SAPLING + "\"].\n"
c1c45943 4181 "\nResult:\n"
9feb4b9e 4182 "\"" + strprintf("%s",komodo_chainname()) + "_address\" (string) The new shielded address.\n"
c1c45943
S
4183 "\nExamples:\n"
4184 + HelpExampleCli("z_getnewaddress", "")
eec85c43 4185 + HelpExampleCli("z_getnewaddress", ADDR_TYPE_SAPLING)
c1c45943
S
4186 + HelpExampleRpc("z_getnewaddress", "")
4187 );
4188
4189 LOCK2(cs_main, pwalletMain->cs_wallet);
4190
73699cea
S
4191 EnsureWalletIsUnlocked();
4192
eec85c43
JG
4193 auto addrType = defaultType;
4194 if (params.size() > 0) {
4195 addrType = params[0].get_str();
4196 }
4197
4198 if (addrType == ADDR_TYPE_SPROUT) {
92fc29a3 4199 return EncodePaymentAddress(pwalletMain->GenerateNewSproutZKey());
34e222c1 4200 } else if (addrType == ADDR_TYPE_SAPLING) {
eec85c43
JG
4201 return EncodePaymentAddress(pwalletMain->GenerateNewSaplingZKey());
4202 } else {
4203 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid address type");
4204 }
c1c45943
S
4205}
4206
e709997f 4207
0d37ae3a 4208UniValue z_listaddresses(const UniValue& params, bool fHelp)
e709997f
S
4209{
4210 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 4211 return NullUniValue;
e709997f
S
4212
4213 if (fHelp || params.size() > 1)
4214 throw runtime_error(
44e37656 4215 "z_listaddresses ( includeWatchonly )\n"
eec85c43 4216 "\nReturns the list of Sprout and Sapling shielded addresses belonging to the wallet.\n"
e709997f 4217 "\nArguments:\n"
44e37656 4218 "1. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n"
e709997f
S
4219 "\nResult:\n"
4220 "[ (json array of string)\n"
4221 " \"zaddr\" (string) a zaddr belonging to the wallet\n"
4222 " ,...\n"
4223 "]\n"
4224 "\nExamples:\n"
4225 + HelpExampleCli("z_listaddresses", "")
4226 + HelpExampleRpc("z_listaddresses", "")
4227 );
4228
4229 LOCK2(cs_main, pwalletMain->cs_wallet);
4230
44e37656
JG
4231 bool fIncludeWatchonly = false;
4232 if (params.size() > 0) {
4233 fIncludeWatchonly = params[0].get_bool();
4234 }
4235
0d37ae3a 4236 UniValue ret(UniValue::VARR);
eec85c43
JG
4237 {
4238 std::set<libzcash::SproutPaymentAddress> addresses;
25d5e80c 4239 pwalletMain->GetSproutPaymentAddresses(addresses);
fbd029d9 4240 for (auto addr : addresses) {
25d5e80c 4241 if (fIncludeWatchonly || pwalletMain->HaveSproutSpendingKey(addr)) {
eec85c43
JG
4242 ret.push_back(EncodePaymentAddress(addr));
4243 }
4244 }
4245 }
4246 {
4247 std::set<libzcash::SaplingPaymentAddress> addresses;
4248 pwalletMain->GetSaplingPaymentAddresses(addresses);
4249 libzcash::SaplingIncomingViewingKey ivk;
4250 libzcash::SaplingFullViewingKey fvk;
fbd029d9 4251 for (auto addr : addresses) {
eec85c43
JG
4252 if (fIncludeWatchonly || (
4253 pwalletMain->GetSaplingIncomingViewingKey(addr, ivk) &&
4254 pwalletMain->GetSaplingFullViewingKey(ivk, fvk) &&
4255 pwalletMain->HaveSaplingSpendingKey(fvk)
4256 )) {
4257 ret.push_back(EncodePaymentAddress(addr));
4258 }
44e37656 4259 }
e709997f
S
4260 }
4261 return ret;
4262}
4263
44e37656 4264CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ignoreUnspendable=true) {
b6be3e88 4265 std::set<CTxDestination> destinations;
a0a3334c 4266 vector<COutput> vecOutputs;
9d365796 4267 CAmount balance = 0;
4268
eed98728 4269
4270 bool wildCardRAddress = transparentAddress == "R*";
4271 bool wildCardiAddress = transparentAddress == "i*";
4272 if (transparentAddress == "*")
4273 {
4274 wildCardRAddress = true;
4275 wildCardiAddress = true;
4276 }
4277
4278 if (!(wildCardRAddress || wildCardiAddress) && transparentAddress.length() > 0) {
b6be3e88
JG
4279 CTxDestination taddr = DecodeDestination(transparentAddress);
4280 if (!IsValidDestination(taddr)) {
a0a3334c
S
4281 throw std::runtime_error("invalid transparent address");
4282 }
b6be3e88 4283 destinations.insert(taddr);
a0a3334c 4284 }
9d365796 4285
a0a3334c
S
4286 LOCK2(cs_main, pwalletMain->cs_wallet);
4287
4288 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
4289
4290 BOOST_FOREACH(const COutput& out, vecOutputs) {
4291 if (out.nDepth < minDepth) {
4292 continue;
4293 }
4294
44e37656
JG
4295 if (ignoreUnspendable && !out.fSpendable) {
4296 continue;
4297 }
4298
eed98728 4299 if (wildCardRAddress || wildCardiAddress || destinations.size()) {
a0a3334c
S
4300 CTxDestination address;
4301 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
4302 continue;
4303 }
4304
eed98728 4305 if (wildCardRAddress || wildCardiAddress)
4306 {
4307 bool keep = false;
4308 if (wildCardRAddress)
4309 {
4310 keep = address.which() == COptCCParams::ADDRTYPE_PKH || address.which() == COptCCParams::ADDRTYPE_PK;
4311 }
4312 if (!keep && wildCardiAddress)
4313 {
4314 keep = address.which() == COptCCParams::ADDRTYPE_ID;
4315 }
4316 if (!keep)
4317 {
4318 continue;
4319 }
4320 }
4321 else
4322 {
4323 if (!destinations.count(address)) {
4324 continue;
4325 }
a0a3334c
S
4326 }
4327 }
9d365796 4328
47658758 4329 CAmount nValue = out.tx->vout[out.i].nValue; // komodo_interest
a0a3334c
S
4330 balance += nValue;
4331 }
4332 return balance;
4333}
4334
757a6ada 4335CCurrencyValueMap getCurrencyBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ignoreUnspendable=true) {
4336 std::set<CTxDestination> destinations;
4337 vector<COutput> vecOutputs;
4338 CCurrencyValueMap balance;
4339
4340
4341 bool wildCardRAddress = transparentAddress == "R*";
4342 bool wildCardiAddress = transparentAddress == "i*";
4343 if (transparentAddress == "*")
4344 {
4345 wildCardRAddress = true;
4346 wildCardiAddress = true;
4347 }
4348
4349 if (!(wildCardRAddress || wildCardiAddress) && transparentAddress.length() > 0) {
4350 CTxDestination taddr = DecodeDestination(transparentAddress);
4351 if (!IsValidDestination(taddr)) {
4352 throw std::runtime_error("invalid transparent address");
4353 }
4354 destinations.insert(taddr);
4355 }
4356
4357 LOCK2(cs_main, pwalletMain->cs_wallet);
4358
4359 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
4360
4361 BOOST_FOREACH(const COutput& out, vecOutputs) {
4362 if (out.nDepth < minDepth) {
4363 continue;
4364 }
4365
4366 if (ignoreUnspendable && !out.fSpendable) {
4367 continue;
4368 }
4369
4370 if (wildCardRAddress || wildCardiAddress || destinations.size()) {
4371 CTxDestination address;
4372 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
4373 continue;
4374 }
4375
4376 if (wildCardRAddress || wildCardiAddress)
4377 {
4378 bool keep = false;
4379 if (wildCardRAddress)
4380 {
4381 keep = address.which() == COptCCParams::ADDRTYPE_PKH || address.which() == COptCCParams::ADDRTYPE_PK;
4382 }
4383 if (!keep && wildCardiAddress)
4384 {
4385 keep = address.which() == COptCCParams::ADDRTYPE_ID;
4386 }
4387 if (!keep)
4388 {
4389 continue;
4390 }
4391 }
4392 else
4393 {
4394 if (!destinations.count(address)) {
4395 continue;
4396 }
4397 }
4398 }
4399
4400 CAmount nValue = out.tx->vout[out.i].nValue; // komodo_interest
4401 balance += out.tx->vout[out.i].ReserveOutValue();
4402 if (nValue)
4403 {
4404 balance.valueMap[ASSETCHAINS_CHAINID] += nValue;
4405 }
4406 }
4407 return balance;
4408}
4409
44e37656 4410CAmount getBalanceZaddr(std::string address, int minDepth = 1, bool ignoreUnspendable=true) {
a0a3334c 4411 CAmount balance = 0;
a630f503 4412 std::vector<SproutNoteEntry> sproutEntries;
94e99acd 4413 std::vector<SaplingNoteEntry> saplingEntries;
eed98728 4414
4415
a0a3334c 4416 LOCK2(cs_main, pwalletMain->cs_wallet);
eed98728 4417
4418 libzcash::PaymentAddress zaddress;
4419 if (pwalletMain->GetAndValidateSaplingZAddress(address, zaddress))
4420 {
4421 address = EncodePaymentAddress(zaddress);
4422 }
4423
94e99acd
JG
4424 pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, address, minDepth, true, ignoreUnspendable);
4425 for (auto & entry : sproutEntries) {
a630f503 4426 balance += CAmount(entry.note.value());
a0a3334c 4427 }
053cb349
JG
4428 for (auto & entry : saplingEntries) {
4429 balance += CAmount(entry.note.value());
a0a3334c 4430 }
a0a3334c
S
4431 return balance;
4432}
4433
4434
0d37ae3a 4435UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
6c41028f
S
4436{
4437 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 4438 return NullUniValue;
6c41028f
S
4439
4440 if (fHelp || params.size()==0 || params.size() >2)
4441 throw runtime_error(
4442 "z_listreceivedbyaddress \"address\" ( minconf )\n"
23c9deaf 4443 "\nReturn a list of amounts received by a zaddr belonging to the node's wallet.\n"
6c41028f
S
4444 "\nArguments:\n"
4445 "1. \"address\" (string) The private address.\n"
4446 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
4447 "\nResult:\n"
4448 "{\n"
a3f39072 4449 " \"txid\": \"txid\", string) the transaction id\n"
4450 " \"amount\": xxxxx, (numeric) the amount of value in the note\n"
4451 " \"memo\": xxxxx, (string) hexadecimal string representation of memo field\n"
4452 " \"jsindex\" (sprout) : n, (numeric) the joinsplit index\n"
4453 " \"jsoutindex\" (sprout) : n, (numeric) the output index of the joinsplit\n"
4454 " \"outindex\" (sapling) : n, (numeric) the output index\n"
4455 " \"confirmations\" : n, (numeric) number of block confirmations of transaction\n"
4456 " \"change\": true|false, (boolean) true if the address that received the note is also one of the sending addresses\n"
6c41028f 4457 "}\n"
337a99a2
JG
4458 "\nExamples:\n"
4459 + HelpExampleCli("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
4460 + HelpExampleRpc("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
6c41028f
S
4461 );
4462
4463 LOCK2(cs_main, pwalletMain->cs_wallet);
4464
4465 int nMinDepth = 1;
4466 if (params.size() > 1) {
4467 nMinDepth = params[1].get_int();
4468 }
4469 if (nMinDepth < 0) {
4470 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
4471 }
9d365796 4472
6c41028f
S
4473 // Check that the from address is valid.
4474 auto fromaddress = params[0].get_str();
4475
80ed13d5 4476 auto zaddr = DecodePaymentAddress(fromaddress);
e5eab182 4477 if (!IsValidPaymentAddress(zaddr)) {
6c41028f
S
4478 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
4479 }
4480
e4f0d6a8
LR
4481 // Visitor to support Sprout and Sapling addrs
4482 if (!boost::apply_visitor(PaymentAddressBelongsToWallet(pwalletMain), zaddr)) {
44e37656 4483 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
6c41028f 4484 }
9d365796 4485
0d37ae3a 4486 UniValue result(UniValue::VARR);
a630f503 4487 std::vector<SproutNoteEntry> sproutEntries;
94e99acd
JG
4488 std::vector<SaplingNoteEntry> saplingEntries;
4489 pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, fromaddress, nMinDepth, false, false);
e4f0d6a8
LR
4490
4491 std::set<std::pair<PaymentAddress, uint256>> nullifierSet;
4492 auto hasSpendingKey = boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr);
4493 if (hasSpendingKey) {
4494 nullifierSet = pwalletMain->GetNullifiersForAddresses({zaddr});
4495 }
4496
4497 if (boost::get<libzcash::SproutPaymentAddress>(&zaddr) != nullptr) {
a630f503 4498 for (SproutNoteEntry & entry : sproutEntries) {
e4f0d6a8
LR
4499 UniValue obj(UniValue::VOBJ);
4500 obj.push_back(Pair("txid", entry.jsop.hash.ToString()));
a630f503
E
4501 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.note.value()))));
4502 std::string data(entry.memo.begin(), entry.memo.end());
e4f0d6a8
LR
4503 obj.push_back(Pair("memo", HexStr(data)));
4504 obj.push_back(Pair("jsindex", entry.jsop.js));
4505 obj.push_back(Pair("jsoutindex", entry.jsop.n));
a3f39072 4506 obj.push_back(Pair("confirmations", entry.confirmations));
e4f0d6a8
LR
4507 if (hasSpendingKey) {
4508 obj.push_back(Pair("change", pwalletMain->IsNoteSproutChange(nullifierSet, entry.address, entry.jsop)));
4509 }
4510 result.push_back(obj);
4511 }
4512 } else if (boost::get<libzcash::SaplingPaymentAddress>(&zaddr) != nullptr) {
4513 for (SaplingNoteEntry & entry : saplingEntries) {
4514 UniValue obj(UniValue::VOBJ);
4515 obj.push_back(Pair("txid", entry.op.hash.ToString()));
4516 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.note.value()))));
4517 obj.push_back(Pair("memo", HexStr(entry.memo)));
4518 obj.push_back(Pair("outindex", (int)entry.op.n));
a3f39072 4519 obj.push_back(Pair("confirmations", entry.confirmations));
e4f0d6a8
LR
4520 if (hasSpendingKey) {
4521 obj.push_back(Pair("change", pwalletMain->IsNoteSaplingChange(nullifierSet, entry.address, entry.op)));
4522 }
4523 result.push_back(obj);
79298516 4524 }
6c41028f
S
4525 }
4526 return result;
4527}
4528
0d37ae3a 4529UniValue z_getbalance(const UniValue& params, bool fHelp)
a0a3334c
S
4530{
4531 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 4532 return NullUniValue;
a0a3334c
S
4533
4534 if (fHelp || params.size()==0 || params.size() >2)
4535 throw runtime_error(
4536 "z_getbalance \"address\" ( minconf )\n"
23c9deaf 4537 "\nReturns the balance of a taddr or zaddr belonging to the node's wallet.\n"
573de712
JG
4538 "\nCAUTION: If the wallet has only an incoming viewing key for this address, then spends cannot be"
4539 "\ndetected, and so the returned balance may be larger than the actual balance.\n"
a0a3334c 4540 "\nArguments:\n"
b404945c 4541 "1. \"address\" (string) The selected address. It may be a transparent or private address and include z*, R*, and i* wildcards.\n"
a0a3334c
S
4542 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
4543 "\nResult:\n"
757a6ada 4544 "amount (numeric) The total amount in " + std::string(ASSETCHAINS_SYMBOL) + " received for this address.\n"
a0a3334c
S
4545 "\nExamples:\n"
4546 "\nThe total amount received by address \"myaddress\"\n"
4547 + HelpExampleCli("z_getbalance", "\"myaddress\"") +
4548 "\nThe total amount received by address \"myaddress\" at least 5 blocks confirmed\n"
4549 + HelpExampleCli("z_getbalance", "\"myaddress\" 5") +
4550 "\nAs a json rpc call\n"
4551 + HelpExampleRpc("z_getbalance", "\"myaddress\", 5")
4552 );
4553
4554 LOCK2(cs_main, pwalletMain->cs_wallet);
4555
4556 int nMinDepth = 1;
4557 if (params.size() > 1) {
4558 nMinDepth = params[1].get_int();
4559 }
12448b64
S
4560 if (nMinDepth < 0) {
4561 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
4562 }
9d365796 4563
a0a3334c
S
4564 // Check that the from address is valid.
4565 auto fromaddress = params[0].get_str();
4566 bool fromTaddr = false;
eed98728 4567 CTxDestination taddr;
4568
eaed00e3 4569 if (fromaddress == "z*")
4570 {
4571 fromaddress = "";
4572 }
4573 else if (fromaddress == "*" || fromaddress == "R*" || fromaddress == "i*")
eed98728 4574 {
4575 fromTaddr = true;
4576 }
4577 else
4578 {
4579 taddr = DecodeDestination(fromaddress);
4580 fromTaddr = IsValidDestination(taddr);
4581 if (!fromTaddr) {
872102dd 4582 libzcash::PaymentAddress res;
4583 bool isSapling = pwalletMain->GetAndValidateSaplingZAddress(fromaddress, res);
4584 if (!isSapling)
4585 {
4586 res = DecodePaymentAddress(fromaddress);
4587 }
eed98728 4588 if (!IsValidPaymentAddress(res)) {
4589 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
4590 }
4591 if (!boost::apply_visitor(PaymentAddressBelongsToWallet(pwalletMain), res)) {
4592 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, spending key or viewing key not found.");
4593 }
12448b64 4594 }
a0a3334c
S
4595 }
4596
4597 CAmount nBalance = 0;
4598 if (fromTaddr) {
44e37656 4599 nBalance = getBalanceTaddr(fromaddress, nMinDepth, false);
a0a3334c 4600 } else {
44e37656 4601 nBalance = getBalanceZaddr(fromaddress, nMinDepth, false);
a0a3334c
S
4602 }
4603
4604 return ValueFromAmount(nBalance);
4605}
4606
757a6ada 4607UniValue getcurrencybalance(const UniValue& params, bool fHelp)
4608{
4609 if (!EnsureWalletIsAvailable(fHelp))
4610 return NullUniValue;
4611
b404945c 4612 if (fHelp || params.size()==0 || params.size() > 3)
757a6ada 4613 throw runtime_error(
b404945c 4614 "getcurrencybalance \"address\" ( minconf ) ( friendlynames )\n"
757a6ada 4615 "\nReturns the balance in all currencies of a taddr or zaddr belonging to the node's wallet.\n"
4616 "\nCAUTION: If the wallet has only an incoming viewing key for this address, then spends cannot be"
4617 "\ndetected, and so the returned balance may be larger than the actual balance.\n"
4618 "\nArguments:\n"
4619 "1. \"address\" (string) The selected address. It may be a transparent or private address and include z*, R*, and i* wildcards.\n"
4620 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
b404945c 4621 "3. friendlynames (boolean, optional, default=true) use friendly names instead of i-addresses.\n"
757a6ada 4622 "\nResult:\n"
4623 "amount (numeric) The total amount in " + std::string(ASSETCHAINS_SYMBOL) + " received for this address.\n"
4624 "\nExamples:\n"
4625 "\nThe total amount received by address \"myaddress\"\n"
4626 + HelpExampleCli("getcurrencybalance", "\"myaddress\"") +
4627 "\nThe total amount received by address \"myaddress\" at least 5 blocks confirmed\n"
4628 + HelpExampleCli("getcurrencybalance", "\"myaddress\" 5") +
4629 "\nAs a json rpc call\n"
4630 + HelpExampleRpc("getcurrencybalance", "\"myaddress\", 5")
4631 );
4632
4633 LOCK2(cs_main, pwalletMain->cs_wallet);
4634
4635 int nMinDepth = 1;
b404945c 4636 bool friendlyNames = true;
757a6ada 4637 if (params.size() > 1) {
1a23d48e 4638 nMinDepth = params[1].get_int();
b404945c 4639 }
4640 if (params.size() > 2) {
1a23d48e 4641 friendlyNames = params[2].get_bool();
757a6ada 4642 }
4643 if (nMinDepth < 0) {
4644 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
4645 }
4646
4647 // Check that the from address is valid.
4648 auto fromaddress = params[0].get_str();
4649 bool fromTaddr = false;
4650 CTxDestination taddr;
4651
4652 if (fromaddress == "z*")
4653 {
4654 fromaddress = "";
4655 }
4656 else if (fromaddress == "*" || fromaddress == "R*" || fromaddress == "i*")
4657 {
4658 fromTaddr = true;
4659 }
4660 else
4661 {
4662 taddr = DecodeDestination(fromaddress);
4663 fromTaddr = IsValidDestination(taddr);
4664 if (!fromTaddr) {
4665 libzcash::PaymentAddress res;
4666 bool isSapling = pwalletMain->GetAndValidateSaplingZAddress(fromaddress, res);
4667 if (!isSapling)
4668 {
4669 res = DecodePaymentAddress(fromaddress);
4670 }
4671 if (!IsValidPaymentAddress(res)) {
4672 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
4673 }
4674 if (!boost::apply_visitor(PaymentAddressBelongsToWallet(pwalletMain), res)) {
4675 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, spending key or viewing key not found.");
4676 }
4677 }
4678 }
4679
4680 CCurrencyValueMap balance;
4681 if (fromTaddr) {
4682 balance = getCurrencyBalanceTaddr(fromaddress, nMinDepth, false);
4683 } else {
4684 CAmount nBalance = getBalanceZaddr(fromaddress, nMinDepth, false);
4685 if (nBalance)
4686 {
4687 balance.valueMap[ASSETCHAINS_CHAINID] = nBalance;
4688 }
4689 }
4690
4691 UniValue currencyBal(UniValue::VOBJ);
4692 if (balance.valueMap.count(ASSETCHAINS_CHAINID))
4693 {
b404945c 4694 std::string name = friendlyNames ? ConnectedChains.ThisChain().name : EncodeDestination(CIdentityID(ConnectedChains.ThisChain().GetID()));
4695 currencyBal.push_back(make_pair(name, ValueFromAmount(balance.valueMap[ASSETCHAINS_CHAINID])));
757a6ada 4696 balance.valueMap.erase(ASSETCHAINS_CHAINID);
4697 }
4698 for (auto &oneBalance : balance.valueMap)
4699 {
b404945c 4700 std::string name = friendlyNames ? ConnectedChains.GetCachedCurrency(oneBalance.first).name :
4701 EncodeDestination(CIdentityID(ConnectedChains.GetCachedCurrency(oneBalance.first).GetID()));
4702 currencyBal.push_back(make_pair(name, ValueFromAmount(oneBalance.second)));
757a6ada 4703 }
4704
4705 return currencyBal;
4706}
a0a3334c 4707
0d37ae3a 4708UniValue z_gettotalbalance(const UniValue& params, bool fHelp)
a0a3334c
S
4709{
4710 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 4711 return NullUniValue;
a0a3334c 4712
44e37656 4713 if (fHelp || params.size() > 2)
a0a3334c 4714 throw runtime_error(
44e37656 4715 "z_gettotalbalance ( minconf includeWatchonly )\n"
23c9deaf 4716 "\nReturn the total value of funds stored in the node's wallet.\n"
573de712
JG
4717 "\nCAUTION: If the wallet contains any addresses for which it only has incoming viewing keys,"
4718 "\nthe returned private balance may be larger than the actual balance, because spends cannot"
4719 "\nbe detected with incoming viewing keys.\n"
a0a3334c
S
4720 "\nArguments:\n"
4721 "1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
44e37656 4722 "2. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress' and 'z_importviewingkey')\n"
a0a3334c
S
4723 "\nResult:\n"
4724 "{\n"
4725 " \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
ff1840f6
DA
4726 " \"private\": xxxxx, (numeric) the total balance of shielded funds (in both Sprout and Sapling addresses)\n"
4727 " \"total\": xxxxx, (numeric) the total balance of both transparent and shielded funds\n"
a0a3334c
S
4728 "}\n"
4729 "\nExamples:\n"
4730 "\nThe total amount in the wallet\n"
4731 + HelpExampleCli("z_gettotalbalance", "") +
4732 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
4733 + HelpExampleCli("z_gettotalbalance", "5") +
4734 "\nAs a json rpc call\n"
4735 + HelpExampleRpc("z_gettotalbalance", "5")
4736 );
4737
4738 LOCK2(cs_main, pwalletMain->cs_wallet);
4739
4740 int nMinDepth = 1;
44e37656 4741 if (params.size() > 0) {
a0a3334c
S
4742 nMinDepth = params[0].get_int();
4743 }
12448b64
S
4744 if (nMinDepth < 0) {
4745 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
4746 }
a0a3334c 4747
44e37656
JG
4748 bool fIncludeWatchonly = false;
4749 if (params.size() > 1) {
4750 fIncludeWatchonly = params[1].get_bool();
4751 }
4752
a0a3334c 4753 // getbalance and "getbalance * 1 true" should return the same number
9d365796 4754 // but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
a0a3334c
S
4755 // pwalletMain->GetBalance() does not accept min depth parameter
4756 // so we use our own method to get balance of utxos.
44e37656
JG
4757 CAmount nBalance = getBalanceTaddr("", nMinDepth, !fIncludeWatchonly);
4758 CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth, !fIncludeWatchonly);
da16b12e 4759 uint64_t interest = komodo_interestsum();
a0a3334c 4760 CAmount nTotalBalance = nBalance + nPrivateBalance;
0d37ae3a 4761 UniValue result(UniValue::VOBJ);
f54db399 4762 result.push_back(Pair("transparent", FormatMoney(nBalance)));
aad9fc3e 4763 //result.push_back(Pair("interest", FormatMoney(interest)));
f54db399
JG
4764 result.push_back(Pair("private", FormatMoney(nPrivateBalance)));
4765 result.push_back(Pair("total", FormatMoney(nTotalBalance)));
a0a3334c
S
4766 return result;
4767}
4768
79cd5c96 4769UniValue z_viewtransaction(const UniValue& params, bool fHelp)
4770{
4771 if (!EnsureWalletIsAvailable(fHelp))
4772 return NullUniValue;
4773
4774 if (fHelp || params.size() != 1)
4775 throw runtime_error(
4776 "z_viewtransaction \"txid\"\n"
4777 "\nGet detailed shielded information about in-wallet transaction <txid>\n"
4778 "\nArguments:\n"
4779 "1. \"txid\" (string, required) The transaction id\n"
4780 "\nResult:\n"
4781 "{\n"
4782 " \"txid\" : \"transactionid\", (string) The transaction id\n"
4783 " \"spends\" : [\n"
4784 " {\n"
4785 " \"type\" : \"sprout|sapling\", (string) The type of address\n"
4786 " \"js\" : n, (numeric, sprout) the index of the JSDescription within vJoinSplit\n"
4787 " \"jsSpend\" : n, (numeric, sprout) the index of the spend within the JSDescription\n"
4788 " \"spend\" : n, (numeric, sapling) the index of the spend within vShieldedSpend\n"
4789 " \"txidPrev\" : \"transactionid\", (string) The id for the transaction this note was created in\n"
4790 " \"jsPrev\" : n, (numeric, sprout) the index of the JSDescription within vJoinSplit\n"
4791 " \"jsOutputPrev\" : n, (numeric, sprout) the index of the output within the JSDescription\n"
4792 " \"outputPrev\" : n, (numeric, sapling) the index of the output within the vShieldedOutput\n"
56fe75cb 4793 " \"address\" : \"zaddress\", (string) The z address involved in the transaction\n"
79cd5c96 4794 " \"value\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n"
4795 " \"valueZat\" : xxxx (numeric) The amount in zatoshis\n"
4796 " }\n"
4797 " ,...\n"
4798 " ],\n"
4799 " \"outputs\" : [\n"
4800 " {\n"
4801 " \"type\" : \"sprout|sapling\", (string) The type of address\n"
4802 " \"js\" : n, (numeric, sprout) the index of the JSDescription within vJoinSplit\n"
4803 " \"jsOutput\" : n, (numeric, sprout) the index of the output within the JSDescription\n"
4804 " \"output\" : n, (numeric, sapling) the index of the output within the vShieldedOutput\n"
56fe75cb 4805 " \"address\" : \"address\", (string) The Verus private address involved in the transaction\n"
79cd5c96 4806 " \"recovered\" : true|false (boolean, sapling) True if the output is not for an address in the wallet\n"
4807 " \"value\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n"
4808 " \"valueZat\" : xxxx (numeric) The amount in zatoshis\n"
4809 " \"memo\" : \"hexmemo\", (string) Hexademical string representation of the memo field\n"
4810 " \"memoStr\" : \"memo\", (string) Only returned if memo contains valid UTF-8 text.\n"
4811 " }\n"
4812 " ,...\n"
4813 " ],\n"
4814 "}\n"
4815
4816 "\nExamples:\n"
4817 + HelpExampleCli("z_viewtransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
79cd5c96 4818 + HelpExampleRpc("z_viewtransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
4819 );
4820
4821 LOCK2(cs_main, pwalletMain->cs_wallet);
4822
4823 uint256 hash;
4824 hash.SetHex(params[0].get_str());
4825
4826 UniValue entry(UniValue::VOBJ);
4827 if (!pwalletMain->mapWallet.count(hash))
4828 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
4829 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
4830
4831 entry.push_back(Pair("txid", hash.GetHex()));
4832
4833 UniValue spends(UniValue::VARR);
4834 UniValue outputs(UniValue::VARR);
4835
4836 // Sprout spends - retained for old sprout addresses and transactions
4837 for (size_t i = 0; i < wtx.vJoinSplit.size(); ++i) {
4838 for (size_t j = 0; j < wtx.vJoinSplit[i].nullifiers.size(); ++j) {
4839 auto nullifier = wtx.vJoinSplit[i].nullifiers[j];
4840
4841 // Fetch the note that is being spent, if ours
4842 auto res = pwalletMain->mapSproutNullifiersToNotes.find(nullifier);
4843 if (res == pwalletMain->mapSproutNullifiersToNotes.end()) {
4844 continue;
4845 }
4846 auto jsop = res->second;
4847 auto wtxPrev = pwalletMain->mapWallet.at(jsop.hash);
4848
4849 auto decrypted = wtxPrev.DecryptSproutNote(jsop);
4850 auto notePt = decrypted.first;
4851 auto pa = decrypted.second;
4852
4853 UniValue entry(UniValue::VOBJ);
4854 entry.push_back(Pair("type", ADDR_TYPE_SPROUT));
4855 entry.push_back(Pair("js", (int)i));
4856 entry.push_back(Pair("jsSpend", (int)j));
4857 entry.push_back(Pair("txidPrev", jsop.hash.GetHex()));
4858 entry.push_back(Pair("jsPrev", (int)jsop.js));
4859 entry.push_back(Pair("jsOutputPrev", (int)jsop.n));
4860 entry.push_back(Pair("address", EncodePaymentAddress(pa)));
4861 entry.push_back(Pair("value", ValueFromAmount(notePt.value())));
4862 entry.push_back(Pair("valueZat", notePt.value()));
4863 outputs.push_back(entry);
4864 }
4865 }
4866
4867 // Sprout outputs
4868 for (auto & pair : wtx.mapSproutNoteData) {
4869 JSOutPoint jsop = pair.first;
4870
4871 auto decrypted = wtx.DecryptSproutNote(jsop);
4872 auto notePt = decrypted.first;
4873 auto pa = decrypted.second;
4874 auto memo = notePt.memo();
4875
4876 UniValue entry(UniValue::VOBJ);
4877 entry.push_back(Pair("type", ADDR_TYPE_SPROUT));
4878 entry.push_back(Pair("js", (int)jsop.js));
4879 entry.push_back(Pair("jsOutput", (int)jsop.n));
4880 entry.push_back(Pair("address", EncodePaymentAddress(pa)));
4881 entry.push_back(Pair("value", ValueFromAmount(notePt.value())));
4882 entry.push_back(Pair("valueZat", notePt.value()));
4883 entry.push_back(Pair("memo", HexStr(memo)));
4884 if (memo[0] <= 0xf4) {
4885 auto end = std::find_if(memo.rbegin(), memo.rend(), [](unsigned char v) { return v != 0; });
4886 std::string memoStr(memo.begin(), end.base());
4887 //if (utf8::is_valid(memoStr))
4888 {
4889 entry.push_back(Pair("memoStr", memoStr));
4890 }
4891 }
4892 outputs.push_back(entry);
4893 }
4894
4895 // Sapling spends
4896 std::set<uint256> ovks;
4897 for (size_t i = 0; i < wtx.vShieldedSpend.size(); ++i) {
4898 auto spend = wtx.vShieldedSpend[i];
4899
4900 // Fetch teh note that is being spent
4901 auto res = pwalletMain->mapSaplingNullifiersToNotes.find(spend.nullifier);
4902 if (res == pwalletMain->mapSaplingNullifiersToNotes.end()) {
4903 continue;
4904 }
4905 auto op = res->second;
4906 auto wtxPrev = pwalletMain->mapWallet.at(op.hash);
4907
4908 auto decrypted = wtxPrev.DecryptSaplingNote(op).get();
4909 auto notePt = decrypted.first;
4910 auto pa = decrypted.second;
4911
4912 // Store the OutgoingViewingKey for recovering outputs
4913 libzcash::SaplingFullViewingKey fvk;
4914 assert(pwalletMain->GetSaplingFullViewingKey(wtxPrev.mapSaplingNoteData.at(op).ivk, fvk));
4915 ovks.insert(fvk.ovk);
4916
4917 UniValue entry(UniValue::VOBJ);
4918 entry.push_back(Pair("type", ADDR_TYPE_SAPLING));
4919 entry.push_back(Pair("spend", (int)i));
4920 entry.push_back(Pair("txidPrev", op.hash.GetHex()));
4921 entry.push_back(Pair("outputPrev", (int)op.n));
4922 entry.push_back(Pair("address", EncodePaymentAddress(pa)));
4923 entry.push_back(Pair("value", ValueFromAmount(notePt.value())));
4924 entry.push_back(Pair("valueZat", notePt.value()));
4925 spends.push_back(entry);
4926 }
4927
4928 // Sapling outputs
4929 for (uint32_t i = 0; i < wtx.vShieldedOutput.size(); ++i) {
4930 auto op = SaplingOutPoint(hash, i);
4931
4932 SaplingNotePlaintext notePt;
4933 SaplingPaymentAddress pa;
4934 bool isRecovered;
4935
4936 auto decrypted = wtx.DecryptSaplingNote(op);
4937 if (decrypted) {
4938 notePt = decrypted->first;
4939 pa = decrypted->second;
4940 isRecovered = false;
4941 } else {
4942 // Try recovering the output
4943 auto recovered = wtx.RecoverSaplingNote(op, ovks);
4944 if (recovered) {
4945 notePt = recovered->first;
4946 pa = recovered->second;
4947 isRecovered = true;
4948 } else {
4949 // Unreadable
4950 continue;
4951 }
4952 }
4953 auto memo = notePt.memo();
4954
4955 UniValue entry(UniValue::VOBJ);
4956 entry.push_back(Pair("type", ADDR_TYPE_SAPLING));
4957 entry.push_back(Pair("output", (int)op.n));
4958 entry.push_back(Pair("recovered", isRecovered));
4959 entry.push_back(Pair("address", EncodePaymentAddress(pa)));
4960 entry.push_back(Pair("value", ValueFromAmount(notePt.value())));
4961 entry.push_back(Pair("valueZat", notePt.value()));
4962 entry.push_back(Pair("memo", HexStr(memo)));
4963 if (memo[0] <= 0xf4) {
4964 auto end = std::find_if(memo.rbegin(), memo.rend(), [](unsigned char v) { return v != 0; });
4965 std::string memoStr(memo.begin(), end.base());
4966 //if (utf8::is_valid(memoStr))
4967 {
4968 entry.push_back(Pair("memoStr", memoStr));
4969 }
4970 }
4971 outputs.push_back(entry);
4972 }
4973
4974 entry.push_back(Pair("spends", spends));
4975 entry.push_back(Pair("outputs", outputs));
4976
4977 return entry;
4978}
4979
0d37ae3a 4980UniValue z_getoperationresult(const UniValue& params, bool fHelp)
c1eae280
S
4981{
4982 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 4983 return NullUniValue;
c1eae280
S
4984
4985 if (fHelp || params.size() > 1)
4986 throw runtime_error(
4987 "z_getoperationresult ([\"operationid\", ... ]) \n"
4988 "\nRetrieve the result and status of an operation which has finished, and then remove the operation from memory."
4989 + HelpRequiringPassphrase() + "\n"
4990 "\nArguments:\n"
4991 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
4992 "\nResult:\n"
4993 "\" [object, ...]\" (array) A list of JSON objects\n"
337a99a2
JG
4994 "\nExamples:\n"
4995 + HelpExampleCli("z_getoperationresult", "'[\"operationid\", ... ]'")
4996 + HelpExampleRpc("z_getoperationresult", "'[\"operationid\", ... ]'")
c1eae280 4997 );
9d365796 4998
c1eae280
S
4999 // This call will remove finished operations
5000 return z_getoperationstatus_IMPL(params, true);
5001}
fc72c078 5002
0d37ae3a 5003UniValue z_getoperationstatus(const UniValue& params, bool fHelp)
fc72c078
S
5004{
5005 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 5006 return NullUniValue;
fc72c078 5007
34f0001c 5008 if (fHelp || params.size() > 1)
fc72c078 5009 throw runtime_error(
34f0001c 5010 "z_getoperationstatus ([\"operationid\", ... ]) \n"
c1eae280 5011 "\nGet operation status and any associated result or error data. The operation will remain in memory."
fc72c078
S
5012 + HelpRequiringPassphrase() + "\n"
5013 "\nArguments:\n"
c1eae280 5014 "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 5015 "\nResult:\n"
34f0001c 5016 "\" [object, ...]\" (array) A list of JSON objects\n"
337a99a2
JG
5017 "\nExamples:\n"
5018 + HelpExampleCli("z_getoperationstatus", "'[\"operationid\", ... ]'")
5019 + HelpExampleRpc("z_getoperationstatus", "'[\"operationid\", ... ]'")
fc72c078 5020 );
9d365796 5021
c1eae280
S
5022 // This call is idempotent so we don't want to remove finished operations
5023 return z_getoperationstatus_IMPL(params, false);
5024}
fc72c078 5025
0d37ae3a 5026UniValue z_getoperationstatus_IMPL(const UniValue& params, bool fRemoveFinishedOperations=false)
c1eae280 5027{
fc72c078
S
5028 LOCK2(cs_main, pwalletMain->cs_wallet);
5029
34f0001c
S
5030 std::set<AsyncRPCOperationId> filter;
5031 if (params.size()==1) {
0d37ae3a 5032 UniValue ids = params[0].get_array();
c24109ec 5033 for (const UniValue & v : ids.getValues()) {
34f0001c
S
5034 filter.insert(v.get_str());
5035 }
fc72c078 5036 }
34f0001c 5037 bool useFilter = (filter.size()>0);
fc72c078 5038
0d37ae3a 5039 UniValue ret(UniValue::VARR);
34f0001c
S
5040 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
5041 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
5042
5043 for (auto id : ids) {
5044 if (useFilter && !filter.count(id))
5045 continue;
9d365796 5046
34f0001c
S
5047 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
5048 if (!operation) {
5049 continue;
5050 // It's possible that the operation was removed from the internal queue and map during this loop
5051 // throw JSONRPCError(RPC_INVALID_PARAMETER, "No operation exists for that id.");
5052 }
fc72c078 5053
2f21206c
S
5054 UniValue obj = operation->getStatus();
5055 std::string s = obj["status"].get_str();
c1eae280
S
5056 if (fRemoveFinishedOperations) {
5057 // Caller is only interested in retrieving finished results
2f21206c
S
5058 if ("success"==s || "failed"==s || "cancelled"==s) {
5059 ret.push_back(obj);
c1eae280
S
5060 q->popOperationForId(id);
5061 }
5062 } else {
2f21206c 5063 ret.push_back(obj);
34f0001c 5064 }
fc72c078
S
5065 }
5066
0d37ae3a
JG
5067 std::vector<UniValue> arrTmp = ret.getValues();
5068
2d2f3d18 5069 // sort results chronologically by creation_time
0d37ae3a 5070 std::sort(arrTmp.begin(), arrTmp.end(), [](UniValue a, UniValue b) -> bool {
2d2f3d18
S
5071 const int64_t t1 = find_value(a.get_obj(), "creation_time").get_int64();
5072 const int64_t t2 = find_value(b.get_obj(), "creation_time").get_int64();
5073 return t1 < t2;
5074 });
5075
0d37ae3a
JG
5076 ret.clear();
5077 ret.setArray();
5078 ret.push_backV(arrTmp);
5079
34f0001c 5080 return ret;
fc72c078
S
5081}
5082
3920292b 5083
892ae945
JG
5084// JSDescription size depends on the transaction version
5085#define V3_JS_DESCRIPTION_SIZE (GetSerializeSize(JSDescription(), SER_NETWORK, (OVERWINTER_TX_VERSION | (1 << 31))))
3920292b
S
5086// Here we define the maximum number of zaddr outputs that can be included in a transaction.
5087// If input notes are small, we might actually require more than one joinsplit per zaddr output.
5088// For now though, we assume we use one joinsplit per zaddr output (and the second output note is change).
5089// We reduce the result by 1 to ensure there is room for non-joinsplit CTransaction data.
892ae945 5090#define Z_SENDMANY_MAX_ZADDR_OUTPUTS_BEFORE_SAPLING ((MAX_TX_SIZE_BEFORE_SAPLING / V3_JS_DESCRIPTION_SIZE) - 1)
3920292b
S
5091
5092// transaction.h comment: spending taddr output requires CTxIn >= 148 bytes and typical taddr txout is 34 bytes
5093#define CTXIN_SPEND_DUST_SIZE 148
5094#define CTXOUT_REGULAR_SIZE 34
5095
0d37ae3a 5096UniValue z_sendmany(const UniValue& params, bool fHelp)
fc72c078
S
5097{
5098 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 5099 return NullUniValue;
fc72c078 5100
af53da02 5101 if (fHelp || params.size() < 2 || params.size() > 4)
fc72c078 5102 throw runtime_error(
af53da02 5103 "z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee )\n"
92b42d28 5104 "\nSend multiple times. Amounts are decimal numbers with at most 8 digits of precision."
da85cdfe 5105 "\nChange generated from a taddr flows to a new taddr address, while change generated from a zaddr returns to itself."
48f9c65b 5106 "\nWhen sending coinbase UTXOs to a zaddr, change is not allowed. The entire value of the UTXO(s) must be consumed."
892ae945 5107 + strprintf("\nBefore Sapling activates, the maximum number of zaddr outputs is %d due to transaction size limits.\n", Z_SENDMANY_MAX_ZADDR_OUTPUTS_BEFORE_SAPLING)
fc72c078
S
5108 + HelpRequiringPassphrase() + "\n"
5109 "\nArguments:\n"
5110 "1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from.\n"
5111 "2. \"amounts\" (array, required) An array of json objects representing the amounts to send.\n"
5112 " [{\n"
5113 " \"address\":address (string, required) The address is a taddr or zaddr\n"
f37f614e 5114 " \"amount\":amount (numeric, required) The numeric amount in KMD is the value\n"
fc72c078
S
5115 " \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
5116 " }, ... ]\n"
5117 "3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
af53da02
S
5118 "4. fee (numeric, optional, default="
5119 + strprintf("%s", FormatMoney(ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
fc72c078
S
5120 "\nResult:\n"
5121 "\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
337a99a2 5122 "\nExamples:\n"
1333d0d7 5123 + HelpExampleCli("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" '[{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]'")
5124 + HelpExampleRpc("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", [{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]")
fc72c078
S
5125 );
5126
5127 LOCK2(cs_main, pwalletMain->cs_wallet);
5128
fc72c078
S
5129 // Check that the from address is valid.
5130 auto fromaddress = params[0].get_str();
5131 bool fromTaddr = false;
af4057b9 5132 bool fromSapling = false;
5f63373e 5133
5134 uint32_t branchId = CurrentEpochBranchId(chainActive.Height(), Params().GetConsensus());
5135
b6be3e88
JG
5136 CTxDestination taddr = DecodeDestination(fromaddress);
5137 fromTaddr = IsValidDestination(taddr);
fc72c078 5138 if (!fromTaddr) {
80ed13d5 5139 auto res = DecodePaymentAddress(fromaddress);
5f63373e 5140 if (!IsValidPaymentAddress(res, branchId)) {
fc72c078
S
5141 // invalid
5142 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
5143 }
fc72c078 5144
af4057b9
JG
5145 // Check that we have the spending key
5146 if (!boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), res)) {
fc72c078
S
5147 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
5148 }
af4057b9
JG
5149
5150 // Remember whether this is a Sprout or Sapling address
af4057b9 5151 fromSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
fc72c078 5152 }
07d85a64
JG
5153 // This logic will need to be updated if we add a new shielded pool
5154 bool fromSprout = !(fromTaddr || fromSapling);
fc72c078 5155
0d37ae3a 5156 UniValue outputs = params[1].get_array();
fc72c078
S
5157
5158 if (outputs.size()==0)
5159 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
5160
5161 // Keep track of addresses to spot duplicates
5162 set<std::string> setAddress;
5163
af4057b9 5164 // Track whether we see any Sprout addresses
07d85a64 5165 bool noSproutAddrs = !fromSprout;
af4057b9 5166
fc72c078 5167 // Recipients
dafb8161
S
5168 std::vector<SendManyRecipient> taddrRecipients;
5169 std::vector<SendManyRecipient> zaddrRecipients;
af53da02 5170 CAmount nTotalOut = 0;
fc72c078 5171
0917c84d
EOW
5172 bool containsSaplingOutput = false;
5173
0d37ae3a
JG
5174 for (const UniValue& o : outputs.getValues()) {
5175 if (!o.isObject())
fc72c078 5176 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
fc72c078 5177
fc72c078 5178 // sanity check, report error if unknown key-value pairs
0d37ae3a
JG
5179 for (const string& name_ : o.getKeys()) {
5180 std::string s = name_;
fc72c078
S
5181 if (s != "address" && s != "amount" && s!="memo")
5182 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown key: ")+s);
5183 }
5184
5185 string address = find_value(o, "address").get_str();
5186 bool isZaddr = false;
40c59fea 5187 CTxDestination taddr = ValidateDestination(address);
b6be3e88 5188 if (!IsValidDestination(taddr)) {
af4057b9 5189 auto res = DecodePaymentAddress(address);
5f63373e 5190 if (IsValidPaymentAddress(res, branchId)) {
fc72c078 5191 isZaddr = true;
af4057b9
JG
5192
5193 bool toSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
ee7656e8 5194 if (!toSapling)
5195 {
0917c84d
EOW
5196 throw JSONRPCError(
5197 RPC_INVALID_PARAMETER,
ee7656e8 5198 "Sprout addresses are deprecated on the Verus network. Either use z_setmigration or send from Sprout to transparent or VerusID, then to a Sapling address.");
0917c84d 5199 }
ee7656e8 5200 containsSaplingOutput |= toSapling;
0917c84d 5201
12040363 5202 // If sending between shielded addresses, they must be the same type
ee7656e8 5203 if ((fromSprout && toSapling)) {
7c02acc5
JG
5204 throw JSONRPCError(
5205 RPC_INVALID_PARAMETER,
ee7656e8 5206 "Cannot send between Sprout and Sapling addresses using z_sendmany. Either use z_setmigration or send from Sprout to transparent or VerusID, then to a Sapling address.");
af4057b9 5207 }
80ed13d5 5208 } else {
fc72c078
S
5209 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
5210 }
5211 }
2f151c30 5212 else if ( ASSETCHAINS_PRIVATE != 0 )
5213 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
fc72c078
S
5214
5215 if (setAddress.count(address))
5216 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address);
5217 setAddress.insert(address);
5218
0d37ae3a 5219 UniValue memoValue = find_value(o, "memo");
fc72c078 5220 string memo;
0d37ae3a 5221 if (!memoValue.isNull()) {
fc72c078
S
5222 memo = memoValue.get_str();
5223 if (!isZaddr) {
c938fb1f 5224 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo cannot be used with a taddr. It can only be used with a zaddr.");
fc72c078
S
5225 } else if (!IsHex(memo)) {
5226 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
5227 }
6114cfe7 5228 if (memo.length() > ZC_MEMO_SIZE*2) {
dafb8161
S
5229 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
5230 }
fc72c078
S
5231 }
5232
0d37ae3a 5233 UniValue av = find_value(o, "amount");
fc72c078
S
5234 CAmount nAmount = AmountFromValue( av );
5235 if (nAmount < 0)
5236 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
5237
dafb8161 5238 if (isZaddr) {
eed98728 5239 zaddrRecipients.push_back( SendManyRecipient(address, nAmount, memo, CScript()) );
dafb8161 5240 } else {
eed98728 5241 taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo, CScript()) );
dafb8161 5242 }
af53da02
S
5243
5244 nTotalOut += nAmount;
fc72c078
S
5245 }
5246
15ec5525 5247 int nextBlockHeight = chainActive.Height() + 1;
892ae945
JG
5248 CMutableTransaction mtx;
5249 mtx.fOverwintered = true;
5250 mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
5251 mtx.nVersion = SAPLING_TX_VERSION;
25fee350 5252 unsigned int max_tx_size = MAX_TX_SIZE_AFTER_SAPLING;
2c6c5526
EOW
5253 if (!Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_SAPLING)) {
5254 if (Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_OVERWINTER)) {
892ae945
JG
5255 mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
5256 mtx.nVersion = OVERWINTER_TX_VERSION;
5257 } else {
5258 mtx.fOverwintered = false;
5259 mtx.nVersion = 2;
5260 }
5261
15ec5525 5262 max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING;
15ec5525 5263
892ae945
JG
5264 // Check the number of zaddr outputs does not exceed the limit.
5265 if (zaddrRecipients.size() > Z_SENDMANY_MAX_ZADDR_OUTPUTS_BEFORE_SAPLING) {
5266 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, too many zaddr outputs");
5267 }
2c6c5526 5268 // If Sapling is not active, do not allow sending from or sending to Sapling addresses.
de1b86a4
S
5269 if (fromSapling || containsSaplingOutput) {
5270 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
5271 }
5272 }
5273
3920292b
S
5274 // As a sanity check, estimate and verify that the size of the transaction will be valid.
5275 // Depending on the input notes, the actual tx size may turn out to be larger and perhaps invalid.
5276 size_t txsize = 0;
3920292b 5277 for (int i = 0; i < zaddrRecipients.size(); i++) {
4dcc48b8
S
5278 auto address = std::get<0>(zaddrRecipients[i]);
5279 auto res = DecodePaymentAddress(address);
ee7656e8 5280 mtx.vShieldedOutput.push_back(OutputDescription());
3920292b
S
5281 }
5282 CTransaction tx(mtx);
a8e5ae92 5283 txsize += GetSerializeSize(tx, SER_NETWORK, tx.nVersion);
3920292b
S
5284 if (fromTaddr) {
5285 txsize += CTXIN_SPEND_DUST_SIZE;
5286 txsize += CTXOUT_REGULAR_SIZE; // There will probably be taddr change
5287 }
5288 txsize += CTXOUT_REGULAR_SIZE * taddrRecipients.size();
15ec5525
JG
5289 if (txsize > max_tx_size) {
5290 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
5291 }
5292
fc72c078
S
5293 // Minimum confirmations
5294 int nMinDepth = 1;
12448b64 5295 if (params.size() > 2) {
fc72c078 5296 nMinDepth = params[2].get_int();
12448b64
S
5297 }
5298 if (nMinDepth < 0) {
5299 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
5300 }
fc72c078 5301
af53da02 5302 // Fee in Zatoshis, not currency format)
e5aa9f61
DL
5303 CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE;
5304 CAmount nDefaultFee = nFee;
5305
af53da02 5306 if (params.size() > 3) {
7eccce4e
S
5307 if (params[3].get_real() == 0.0) {
5308 nFee = 0;
5309 } else {
5310 nFee = AmountFromValue( params[3] );
5311 }
5312
0b6eeac3 5313 // Check that the user specified fee is not absurd.
e5aa9f61
DL
5314 // This allows amount=0 (and all amount < nDefaultFee) transactions to use the default network fee
5315 // or anything less than nDefaultFee instead of being forced to use a custom fee and leak metadata
5316 if (nTotalOut < nDefaultFee) {
5317 if (nFee > nDefaultFee) {
5318 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Small transaction amount %s has fee %s that is greater than the default fee %s", FormatMoney(nTotalOut), FormatMoney(nFee), FormatMoney(nDefaultFee)));
5319 }
5320 } else {
0b6eeac3 5321 // Check that the user specified fee is not absurd.
e5aa9f61 5322 if (nFee > nTotalOut) {
4b8c52c6 5323 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the sum of outputs %s and also greater than the default fee", FormatMoney(nFee), FormatMoney(nTotalOut)));
e5aa9f61 5324 }
ee7656e8 5325 }
af53da02
S
5326 }
5327
8aa7937d 5328 // Use input parameters as the optional context info to be returned by z_getoperationstatus and z_getoperationresult.
0d37ae3a 5329 UniValue o(UniValue::VOBJ);
8aa7937d
S
5330 o.push_back(Pair("fromaddress", params[0]));
5331 o.push_back(Pair("amounts", params[1]));
5332 o.push_back(Pair("minconf", nMinDepth));
5333 o.push_back(Pair("fee", std::stod(FormatMoney(nFee))));
0d37ae3a 5334 UniValue contextInfo = o;
8aa7937d 5335
36e2141d
JG
5336 // Builder (used if Sapling addresses are involved)
5337 boost::optional<TransactionBuilder> builder;
af4057b9 5338 if (noSproutAddrs) {
36e2141d
JG
5339 builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain);
5340 }
5341
072099d7 5342 // Contextual transaction we will build on
36e2141d 5343 // (used if no Sapling addresses are involved)
9bb37bf0 5344 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextBlockHeight);
e6cd2a83
S
5345 bool isShielded = !fromTaddr || zaddrRecipients.size() > 0;
5346 if (contextualTx.nVersion == 1 && isShielded) {
7d2e4b3c 5347 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
072099d7
S
5348 }
5349
dafb8161 5350 // Create operation and add to global queue
fc72c078 5351 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
36e2141d 5352 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(builder, contextualTx, fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee, contextInfo) );
fc72c078
S
5353 q->addOperation(operation);
5354 AsyncRPCOperationId operationId = operation->getId();
5355 return operationId;
fc72c078 5356}
34f0001c 5357
81a45d69
E
5358UniValue z_setmigration(const UniValue& params, bool fHelp) {
5359 if (!EnsureWalletIsAvailable(fHelp))
5360 return NullUniValue;
5361 if (fHelp || params.size() != 1)
5362 throw runtime_error(
5363 "z_setmigration enabled\n"
5364 "When enabled the Sprout to Sapling migration will attempt to migrate all funds from this wallet’s\n"
699288b4
E
5365 "Sprout addresses to either the address for Sapling account 0 or the address specified by the parameter\n"
5366 "'-migrationdestaddress'.\n"
5367 "\n"
5368 "This migration is designed to minimize information leakage. As a result for wallets with a significant\n"
5369 "Sprout balance, this process may take several weeks. The migration works by sending, up to 5, as many\n"
5370 "transactions as possible whenever the blockchain reaches a height equal to 499 modulo 500. The transaction\n"
5371 "amounts are picked according to the random distribution specified in ZIP 308. The migration will end once\n"
9615caa8 5372 "the wallet’s Sprout balance is below " + strprintf("%s %s", FormatMoney(CENT), CURRENCY_UNIT) + ".\n"
81a45d69
E
5373 "\nArguments:\n"
5374 "1. enabled (boolean, required) 'true' or 'false' to enable or disable respectively.\n"
81a45d69 5375 );
162bfc3a
E
5376 LOCK(pwalletMain->cs_wallet);
5377 pwalletMain->fSaplingMigrationEnabled = params[0].get_bool();
699288b4 5378 return NullUniValue;
81a45d69 5379}
34f0001c 5380
6e82d728
E
5381UniValue z_getmigrationstatus(const UniValue& params, bool fHelp) {
5382 if (!EnsureWalletIsAvailable(fHelp))
5383 return NullUniValue;
5384 if (fHelp || params.size() != 0)
5385 throw runtime_error(
5386 "z_getmigrationstatus\n"
5387 "Returns information about the status of the Sprout to Sapling migration.\n"
406b8ff5
E
5388 "Note: A transaction is defined as finalized if it has at least ten confirmations.\n"
5389 "Also, it is possible that manually created transactions involving this wallet\n"
6e82d728
E
5390 "will be included in the result.\n"
5391 "\nResult:\n"
5392 "{\n"
5393 " \"enabled\": true|false, (boolean) Whether or not migration is enabled\n"
108e587c 5394 " \"destination_address\": \"zaddr\", (string) The Sapling address that will receive Sprout funds\n"
6e82d728
E
5395 " \"unmigrated_amount\": nnn.n, (numeric) The total amount of unmigrated " + CURRENCY_UNIT +" \n"
5396 " \"unfinalized_migrated_amount\": nnn.n, (numeric) The total amount of unfinalized " + CURRENCY_UNIT + " \n"
5397 " \"finalized_migrated_amount\": nnn.n, (numeric) The total amount of finalized " + CURRENCY_UNIT + " \n"
5398 " \"finalized_migration_transactions\": nnn, (numeric) The number of migration transactions involving this wallet\n"
345177cf 5399 " \"time_started\": ttt, (numeric, optional) The block time of the first migration transaction as a Unix timestamp\n"
6e82d728
E
5400 " \"migration_txids\": [txids] (json array of strings) An array of all migration txids involving this wallet\n"
5401 "}\n"
5402 );
5403 LOCK2(cs_main, pwalletMain->cs_wallet);
5404 UniValue migrationStatus(UniValue::VOBJ);
5405 migrationStatus.push_back(Pair("enabled", pwalletMain->fSaplingMigrationEnabled));
108e587c 5406 // The "destination_address" field MAY be omitted if the "-migrationdestaddress"
6e82d728
E
5407 // parameter is not set and no default address has yet been generated.
5408 // Note: The following function may return the default address even if it has not been added to the wallet
5409 auto destinationAddress = AsyncRPCOperation_saplingmigration::getMigrationDestAddress(pwalletMain->GetHDSeedForRPC());
5410 migrationStatus.push_back(Pair("destination_address", EncodePaymentAddress(destinationAddress)));
5411 // The values of "unmigrated_amount" and "migrated_amount" MUST take into
5412 // account failed transactions, that were not mined within their expiration
5413 // height.
5414 {
a630f503 5415 std::vector<SproutNoteEntry> sproutEntries;
6e82d728 5416 std::vector<SaplingNoteEntry> saplingEntries;
94e419f9
E
5417 std::set<PaymentAddress> noFilter;
5418 // Here we are looking for any and all Sprout notes for which we have the spending key, including those
5419 // which are locked and/or only exist in the mempool, as they should be included in the unmigrated amount.
5420 pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, noFilter, 0, INT_MAX, true, true, false);
6e82d728
E
5421 CAmount unmigratedAmount = 0;
5422 for (const auto& sproutEntry : sproutEntries) {
a630f503 5423 unmigratedAmount += sproutEntry.note.value();
6e82d728
E
5424 }
5425 migrationStatus.push_back(Pair("unmigrated_amount", FormatMoney(unmigratedAmount)));
5426 }
5427 // "migration_txids" is a list of strings representing transaction IDs of all
5428 // known migration transactions involving this wallet, as lowercase hexadecimal
5429 // in RPC byte order.
5430 UniValue migrationTxids(UniValue::VARR);
6e82d728
E
5431 CAmount unfinalizedMigratedAmount = 0;
5432 CAmount finalizedMigratedAmount = 0;
5433 int numFinalizedMigrationTxs = 0;
5434 uint64_t timeStarted = 0;
5435 for (const auto& txPair : pwalletMain->mapWallet) {
5436 CWalletTx tx = txPair.second;
5437 // A given transaction is defined as a migration transaction iff it has:
5438 // * one or more Sprout JoinSplits with nonzero vpub_new field; and
5439 // * no Sapling Spends, and;
5440 // * one or more Sapling Outputs.
f57f76d7 5441 if (tx.vJoinSplit.size() > 0 && tx.vShieldedSpend.empty() && tx.vShieldedOutput.size() > 0) {
e9530f40 5442 bool nonZeroVPubNew = false;
f57f76d7 5443 for (const auto& js : tx.vJoinSplit) {
e9530f40
E
5444 if (js.vpub_new > 0) {
5445 nonZeroVPubNew = true;
5446 break;
5447 }
6e82d728 5448 }
e9530f40 5449 if (!nonZeroVPubNew) {
6e82d728
E
5450 continue;
5451 }
5452 migrationTxids.push_back(txPair.first.ToString());
e9530f40 5453 // A transaction is "finalized" iff it has at least 10 confirmations.
6e82d728 5454 // TODO: subject to change, if the recommended number of confirmations changes.
e14cf966 5455 if (tx.GetDepthInMainChain() >= 10) {
e9530f40 5456 finalizedMigratedAmount -= tx.valueBalance;
6e82d728
E
5457 ++numFinalizedMigrationTxs;
5458 } else {
e9530f40 5459 unfinalizedMigratedAmount -= tx.valueBalance;
6e82d728 5460 }
7cf4749d
E
5461 // If the transaction is in the mempool it will not be associated with a block yet
5462 if (tx.hashBlock.IsNull() || mapBlockIndex[tx.hashBlock] == nullptr) {
5463 continue;
5464 }
5465 CBlockIndex* blockIndex = mapBlockIndex[tx.hashBlock];
6e82d728
E
5466 // The value of "time_started" is the earliest Unix timestamp of any known
5467 // migration transaction involving this wallet; if there is no such transaction,
5468 // then the field is absent.
5469 if (timeStarted == 0 || timeStarted > blockIndex->GetBlockTime()) {
5470 timeStarted = blockIndex->GetBlockTime();
5471 }
5472 }
5473 }
5474 migrationStatus.push_back(Pair("unfinalized_migrated_amount", FormatMoney(unfinalizedMigratedAmount)));
5475 migrationStatus.push_back(Pair("finalized_migrated_amount", FormatMoney(finalizedMigratedAmount)));
5476 migrationStatus.push_back(Pair("finalized_migration_transactions", numFinalizedMigrationTxs));
5477 if (timeStarted > 0) {
5478 migrationStatus.push_back(Pair("time_started", timeStarted));
5479 }
5480 migrationStatus.push_back(Pair("migration_txids", migrationTxids));
5481 return migrationStatus;
5482}
34f0001c 5483
06c19063
S
5484/**
5485When estimating the number of coinbase utxos we can shield in a single transaction:
54861. Joinsplit description is 1802 bytes.
54872. Transaction overhead ~ 100 bytes
54883. Spending a typical P2PKH is >=148 bytes, as defined in CTXIN_SPEND_DUST_SIZE.
54894. Spending a multi-sig P2SH address can vary greatly:
5490 https://github.com/bitcoin/bitcoin/blob/c3ad56f4e0b587d8d763af03d743fdfc2d180c9b/src/main.cpp#L517
5491 In real-world coinbase utxos, we consider a 3-of-3 multisig, where the size is roughly:
5492 (3*(33+1))+3 = 105 byte redeem script
5493 105 + 1 + 3*(73+1) = 328 bytes of scriptSig, rounded up to 400 based on testnet experiments.
5494*/
5495#define CTXIN_SPEND_P2SH_SIZE 400
5496
c5dabd2b
S
5497#define SHIELD_COINBASE_DEFAULT_LIMIT 50
5498
06c19063
S
5499UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
5500{
5501 if (!EnsureWalletIsAvailable(fHelp))
5502 return NullUniValue;
5503
c5dabd2b 5504 if (fHelp || params.size() < 2 || params.size() > 4)
06c19063 5505 throw runtime_error(
c5dabd2b 5506 "z_shieldcoinbase \"fromaddress\" \"tozaddress\" ( fee ) ( limit )\n"
06c19063
S
5507 "\nShield transparent coinbase funds by sending to a shielded zaddr. This is an asynchronous operation and utxos"
5508 "\nselected for shielding will be locked. If there is an error, they are unlocked. The RPC call `listlockunspent`"
c5dabd2b 5509 "\ncan be used to return a list of locked utxos. The number of coinbase utxos selected for shielding can be limited"
31afbcc5
JG
5510 "\nby the caller. If the limit parameter is set to zero, and Overwinter is not yet active, the -mempooltxinputlimit"
5511 "\noption will determine the number of uxtos. Any limit is constrained by the consensus rule defining a maximum"
5512 "\ntransaction size of "
25fee350 5513 + strprintf("%d bytes before Sapling, and %d bytes once Sapling activates.", MAX_TX_SIZE_BEFORE_SAPLING, MAX_TX_SIZE_AFTER_SAPLING)
06c19063
S
5514 + HelpRequiringPassphrase() + "\n"
5515 "\nArguments:\n"
5516 "1. \"fromaddress\" (string, required) The address is a taddr or \"*\" for all taddrs belonging to the wallet.\n"
5517 "2. \"toaddress\" (string, required) The address is a zaddr.\n"
5518 "3. fee (numeric, optional, default="
5519 + strprintf("%s", FormatMoney(SHIELD_COINBASE_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
c5dabd2b 5520 "4. limit (numeric, optional, default="
31afbcc5 5521 + strprintf("%d", SHIELD_COINBASE_DEFAULT_LIMIT) + ") Limit on the maximum number of utxos to shield. Set to 0 to use node option -mempooltxinputlimit (before Overwinter), or as many as will fit in the transaction (after Overwinter).\n"
06c19063
S
5522 "\nResult:\n"
5523 "{\n"
06c19063
S
5524 " \"remainingUTXOs\": xxx (numeric) Number of coinbase utxos still available for shielding.\n"
5525 " \"remainingValue\": xxx (numeric) Value of coinbase utxos still available for shielding.\n"
9eb8089e
JG
5526 " \"shieldingUTXOs\": xxx (numeric) Number of coinbase utxos being shielded.\n"
5527 " \"shieldingValue\": xxx (numeric) Value of coinbase utxos being shielded.\n"
5528 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
06c19063 5529 "}\n"
337a99a2 5530 "\nExamples:\n"
1333d0d7 5531 + HelpExampleCli("z_shieldcoinbase", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\" \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
5532 + HelpExampleRpc("z_shieldcoinbase", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
06c19063
S
5533 );
5534
5535 LOCK2(cs_main, pwalletMain->cs_wallet);
5536
5537 // Validate the from address
5538 auto fromaddress = params[0].get_str();
5539 bool isFromWildcard = fromaddress == "*";
b6be3e88 5540 CTxDestination taddr;
06c19063 5541 if (!isFromWildcard) {
b6be3e88
JG
5542 taddr = DecodeDestination(fromaddress);
5543 if (!IsValidDestination(taddr)) {
06c19063
S
5544 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or \"*\".");
5545 }
5546 }
5547
5548 // Validate the destination address
5549 auto destaddress = params[1].get_str();
5f63373e 5550 if (!IsValidPaymentAddressString(destaddress, CurrentEpochBranchId(chainActive.Height(), Params().GetConsensus()))) {
06c19063
S
5551 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
5552 }
5553
5554 // Convert fee from currency format to zatoshis
5555 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
5556 if (params.size() > 2) {
5557 if (params[2].get_real() == 0.0) {
5558 nFee = 0;
5559 } else {
5560 nFee = AmountFromValue( params[2] );
5561 }
5562 }
5563
c5dabd2b
S
5564 int nLimit = SHIELD_COINBASE_DEFAULT_LIMIT;
5565 if (params.size() > 3) {
5566 nLimit = params[3].get_int();
5567 if (nLimit < 0) {
5568 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of utxos cannot be negative");
5569 }
5570 }
5571
31afbcc5 5572 int nextBlockHeight = chainActive.Height() + 1;
2c6c5526 5573 bool overwinterActive = Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_OVERWINTER);
25fee350 5574 unsigned int max_tx_size = MAX_TX_SIZE_AFTER_SAPLING;
2c6c5526 5575 if (!Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_SAPLING)) {
15ec5525 5576 max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING;
de1b86a4 5577 auto res = DecodePaymentAddress(destaddress);
2c6c5526 5578 // If Sapling is not active, do not allow sending to a Sapling address.
de1b86a4
S
5579 if (IsValidPaymentAddress(res)) {
5580 bool toSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
5581 if (toSapling) {
5582 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
5583 }
5584 } else {
5585 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
5586 }
5587 }
5588
06c19063
S
5589 // Prepare to get coinbase utxos
5590 std::vector<ShieldCoinbaseUTXO> inputs;
5591 CAmount shieldedValue = 0;
5592 CAmount remainingValue = 0;
5593 size_t estimatedTxSize = 2000; // 1802 joinsplit description + tx overhead + wiggle room
7d2e4b3c 5594
5595 #ifdef __LP64__
5596 uint64_t utxoCounter = 0;
5597 #else
06c19063 5598 size_t utxoCounter = 0;
7d2e4b3c 5599 #endif
5600
06c19063 5601 bool maxedOutFlag = false;
31afbcc5 5602 size_t mempoolLimit = (nLimit != 0) ? nLimit : (overwinterActive ? 0 : (size_t)GetArg("-mempooltxinputlimit", 0));
06c19063
S
5603
5604 // Set of addresses to filter utxos by
b6be3e88 5605 std::set<CTxDestination> destinations = {};
06c19063 5606 if (!isFromWildcard) {
b6be3e88 5607 destinations.insert(taddr);
06c19063
S
5608 }
5609
5610 // Get available utxos
5611 vector<COutput> vecOutputs;
1f8fd6fc 5612 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true, true, false, false);
06c19063
S
5613
5614 // Find unspent coinbase utxos and update estimated size
5615 BOOST_FOREACH(const COutput& out, vecOutputs) {
5616 if (!out.fSpendable) {
5617 continue;
5618 }
5619
5620 CTxDestination address;
5621 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
5622 continue;
5623 }
204cf3fc 5624
06c19063 5625 // If taddr is not wildcard "*", filter utxos
b6be3e88 5626 if (destinations.size() > 0 && !destinations.count(address)) {
06c19063
S
5627 continue;
5628 }
5629
5630 if (!out.tx->IsCoinBase()) {
5631 continue;
5632 }
5633
5634 utxoCounter++;
5f91a956 5635 auto scriptPubKey = out.tx->vout[out.i].scriptPubKey;
06c19063
S
5636 CAmount nValue = out.tx->vout[out.i].nValue;
5637
5638 if (!maxedOutFlag) {
b6be3e88 5639 size_t increase = (boost::get<CScriptID>(&address) != nullptr) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
15ec5525 5640 if (estimatedTxSize + increase >= max_tx_size ||
06c19063
S
5641 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
5642 {
5643 maxedOutFlag = true;
5644 } else {
5645 estimatedTxSize += increase;
5f91a956 5646 ShieldCoinbaseUTXO utxo = {out.tx->GetHash(), out.i, scriptPubKey, nValue};
06c19063
S
5647 inputs.push_back(utxo);
5648 shieldedValue += nValue;
5649 }
5650 }
5651
5652 if (maxedOutFlag) {
5653 remainingValue += nValue;
5654 }
5655 }
5656
7d2e4b3c 5657 #ifdef __LP64__
5658 uint64_t numUtxos = inputs.size();
5659 #else
06c19063 5660 size_t numUtxos = inputs.size();
7d2e4b3c 5661 #endif
06c19063
S
5662
5663 if (numUtxos == 0) {
5664 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any coinbase funds to shield.");
5665 }
5666
5667 if (shieldedValue < nFee) {
5668 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
5669 strprintf("Insufficient coinbase funds, have %s, which is less than miners fee %s",
5670 FormatMoney(shieldedValue), FormatMoney(nFee)));
5671 }
5672
5673 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
5674 CAmount netAmount = shieldedValue - nFee;
5675 if (nFee > netAmount) {
5676 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
5677 }
5678
5679 // Keep record of parameters in context object
5680 UniValue contextInfo(UniValue::VOBJ);
5681 contextInfo.push_back(Pair("fromaddress", params[0]));
5682 contextInfo.push_back(Pair("toaddress", params[1]));
5683 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
5684
5f91a956
JG
5685 // Builder (used if Sapling addresses are involved)
5686 TransactionBuilder builder = TransactionBuilder(
5687 Params().GetConsensus(), nextBlockHeight, pwalletMain);
5688
072099d7 5689 // Contextual transaction we will build on
4b729ec5 5690 int blockHeight = chainActive.LastTip()->GetHeight();
9feb4b9e 5691 nextBlockHeight = blockHeight + 1;
5f91a956 5692 // (used if no Sapling addresses are involved)
072099d7 5693 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
9bb37bf0 5694 Params().GetConsensus(), nextBlockHeight);
4ac64cd2 5695 contextualTx.nLockTime = chainActive.LastTip()->GetHeight();
90cc70cc 5696
072099d7 5697 if (contextualTx.nVersion == 1) {
7d2e4b3c 5698 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
072099d7
S
5699 }
5700
06c19063
S
5701 // Create operation and add to global queue
5702 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
5f91a956 5703 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(builder, contextualTx, inputs, destaddress, nFee, contextInfo) );
06c19063
S
5704 q->addOperation(operation);
5705 AsyncRPCOperationId operationId = operation->getId();
5706
5707 // Return continuation information
5708 UniValue o(UniValue::VOBJ);
4ff92bb6 5709 o.push_back(Pair("remainingUTXOs", static_cast<uint64_t>(utxoCounter - numUtxos)));
06c19063 5710 o.push_back(Pair("remainingValue", ValueFromAmount(remainingValue)));
4ff92bb6 5711 o.push_back(Pair("shieldingUTXOs", static_cast<uint64_t>(numUtxos)));
06c19063
S
5712 o.push_back(Pair("shieldingValue", ValueFromAmount(shieldedValue)));
5713 o.push_back(Pair("opid", operationId));
5714 return o;
5715}
5716
5717
6e9c7629 5718#define MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT 50
487c9020
EOW
5719#define MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT 20
5720#define MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT 200
6e9c7629 5721
a8e5ae92 5722#define JOINSPLIT_SIZE GetSerializeSize(JSDescription(), SER_NETWORK, PROTOCOL_VERSION)
487c9020
EOW
5723#define OUTPUTDESCRIPTION_SIZE GetSerializeSize(OutputDescription(), SER_NETWORK, PROTOCOL_VERSION)
5724#define SPENDDESCRIPTION_SIZE GetSerializeSize(SpendDescription(), SER_NETWORK, PROTOCOL_VERSION)
6e9c7629
JG
5725
5726UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
5727{
5728 if (!EnsureWalletIsAvailable(fHelp))
5729 return NullUniValue;
5730
66dfcc13
LR
5731 string enableArg = "zmergetoaddress";
5732 auto fEnableMergeToAddress = fExperimentalMode && GetBoolArg("-" + enableArg, false);
553a5c1a
JG
5733 std::string strDisabledMsg = "";
5734 if (!fEnableMergeToAddress) {
66dfcc13 5735 strDisabledMsg = experimentalDisabledHelpMsg("z_mergetoaddress", enableArg);
553a5c1a
JG
5736 }
5737
6e9c7629
JG
5738 if (fHelp || params.size() < 2 || params.size() > 6)
5739 throw runtime_error(
5740 "z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n"
553a5c1a 5741 + strDisabledMsg +
1e435b54 5742 "\nMerge multiple UTXOs and notes into a single UTXO or note. Protected coinbase UTXOs are ignored, use `z_shieldcoinbase`"
6e9c7629
JG
5743 "\nto combine those into a single note."
5744 "\n\nThis is an asynchronous operation, and UTXOs selected for merging will be locked. If there is an error, they"
5745 "\nare unlocked. The RPC call `listlockunspent` can be used to return a list of locked UTXOs."
5746 "\n\nThe number of UTXOs and notes selected for merging can be limited by the caller. If the transparent limit"
31afbcc5 5747 "\nparameter is set to zero, and Overwinter is not yet active, the -mempooltxinputlimit option will determine the"
25f1f7dc
EOW
5748 "\nnumber of UTXOs. After Overwinter has activated -mempooltxinputlimit is ignored and having a transparent"
5749 "\ninput limit of zero will mean limit the number of UTXOs based on the size of the transaction. Any limit is"
5750 "\nconstrained by the consensus rule defining a maximum transaction size of "
5751 + strprintf("%d bytes before Sapling, and %d", MAX_TX_SIZE_BEFORE_SAPLING, MAX_TX_SIZE_AFTER_SAPLING)
5752 + "\nbytes once Sapling activates."
6e9c7629
JG
5753 + HelpRequiringPassphrase() + "\n"
5754 "\nArguments:\n"
25f1f7dc 5755 "1. fromaddresses (array, required) A JSON array with addresses.\n"
6e9c7629 5756 " The following special strings are accepted inside the array:\n"
1178ba60 5757 " - \"ANY_TADDR\": Merge UTXOs from any t-addrs belonging to the wallet.\n"
25f1f7dc
EOW
5758 " - \"ANY_SPROUT\": Merge notes from any Sprout zaddrs belonging to the wallet.\n"
5759 " - \"ANY_SAPLING\": Merge notes from any Sapling zaddrs belonging to the wallet.\n"
cf30355f
E
5760 " While it is possible to use a variety of different combinations of addresses and the above values,\n"
5761 " it is not possible to send funds from both sprout and sapling addresses simultaneously. If a special\n"
5762 " string is given, any given addresses of that type will be counted as duplicates and cause an error.\n"
6e9c7629 5763 " [\n"
fa6c4d7c 5764 " \"address\" (string) Can be a t-addr or a zaddr\n"
6e9c7629
JG
5765 " ,...\n"
5766 " ]\n"
258a2de0 5767 "2. \"toaddress\" (string, required) The t-addr or zaddr to send the funds to.\n"
6e9c7629
JG
5768 "3. fee (numeric, optional, default="
5769 + strprintf("%s", FormatMoney(MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
5770 "4. transparent_limit (numeric, optional, default="
31afbcc5 5771 + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT) + ") Limit on the maximum number of UTXOs to merge. Set to 0 to use node option -mempooltxinputlimit (before Overwinter), or as many as will fit in the transaction (after Overwinter).\n"
25f1f7dc 5772 "5. shielded_limit (numeric, optional, default="
487c9020 5773 + strprintf("%d Sprout or %d Sapling Notes", MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT, MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT) + ") Limit on the maximum number of notes to merge. Set to 0 to merge as many as will fit in the transaction.\n"
25f1f7dc 5774 "6. \"memo\" (string, optional) Encoded as hex. When toaddress is a zaddr, this will be stored in the memo field of the new note.\n"
6e9c7629
JG
5775 "\nResult:\n"
5776 "{\n"
5777 " \"remainingUTXOs\": xxx (numeric) Number of UTXOs still available for merging.\n"
5778 " \"remainingTransparentValue\": xxx (numeric) Value of UTXOs still available for merging.\n"
5779 " \"remainingNotes\": xxx (numeric) Number of notes still available for merging.\n"
5780 " \"remainingShieldedValue\": xxx (numeric) Value of notes still available for merging.\n"
5781 " \"mergingUTXOs\": xxx (numeric) Number of UTXOs being merged.\n"
5782 " \"mergingTransparentValue\": xxx (numeric) Value of UTXOs being merged.\n"
5783 " \"mergingNotes\": xxx (numeric) Number of notes being merged.\n"
5784 " \"mergingShieldedValue\": xxx (numeric) Value of notes being merged.\n"
25f1f7dc 5785 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
6e9c7629
JG
5786 "}\n"
5787 "\nExamples:\n"
88d014d0 5788 + HelpExampleCli("z_mergetoaddress", "'[\"ANY_SAPLING\", \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"]' ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf")
5789 + HelpExampleRpc("z_mergetoaddress", "[\"ANY_SAPLING\", \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"], \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
6e9c7629
JG
5790 );
5791
553a5c1a 5792 if (!fEnableMergeToAddress) {
25f1f7dc 5793 throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_mergetoaddress is disabled. Run './zcash-cli help z_mergetoaddress' for instructions on how to enable this feature.");
553a5c1a
JG
5794 }
5795
6e9c7629
JG
5796 LOCK2(cs_main, pwalletMain->cs_wallet);
5797
6e9c7629 5798 bool useAnyUTXO = false;
487c9020
EOW
5799 bool useAnySprout = false;
5800 bool useAnySapling = false;
b6be3e88 5801 std::set<CTxDestination> taddrs = {};
6e9c7629
JG
5802 std::set<libzcash::PaymentAddress> zaddrs = {};
5803
5f63373e 5804 uint32_t branchId = CurrentEpochBranchId(chainActive.Height(), Params().GetConsensus());
5805
6e9c7629
JG
5806 UniValue addresses = params[0].get_array();
5807 if (addresses.size()==0)
5808 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, fromaddresses array is empty.");
5809
5810 // Keep track of addresses to spot duplicates
5811 std::set<std::string> setAddress;
5812
5813 // Sources
5814 for (const UniValue& o : addresses.getValues()) {
5815 if (!o.isStr())
5816 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
5817
5818 std::string address = o.get_str();
487c9020
EOW
5819
5820 if (address == "ANY_TADDR") {
6e9c7629 5821 useAnyUTXO = true;
487c9020
EOW
5822 } else if (address == "ANY_SPROUT") {
5823 useAnySprout = true;
5824 } else if (address == "ANY_SAPLING") {
5825 useAnySapling = true;
6e9c7629 5826 } else {
b6be3e88
JG
5827 CTxDestination taddr = DecodeDestination(address);
5828 if (IsValidDestination(taddr)) {
487c9020 5829 taddrs.insert(taddr);
6e9c7629 5830 } else {
80ed13d5 5831 auto zaddr = DecodePaymentAddress(address);
e5eab182 5832 if (IsValidPaymentAddress(zaddr)) {
487c9020 5833 zaddrs.insert(zaddr);
80ed13d5 5834 } else {
487c9020 5835 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Unknown address format: ") + address);
6e9c7629
JG
5836 }
5837 }
5838 }
5839
5840 if (setAddress.count(address))
5841 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + address);
5842 setAddress.insert(address);
5843 }
5844
487c9020 5845 if (useAnyUTXO && taddrs.size() > 0) {
25f1f7dc 5846 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify specific taddrs when using \"ANY_TADDR\"");
487c9020
EOW
5847 }
5848 if ((useAnySprout || useAnySapling) && zaddrs.size() > 0) {
25f1f7dc 5849 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify specific zaddrs when using \"ANY_SPROUT\" or \"ANY_SAPLING\"");
487c9020
EOW
5850 }
5851
5852 const int nextBlockHeight = chainActive.Height() + 1;
2c6c5526
EOW
5853 const bool overwinterActive = Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_OVERWINTER);
5854 const bool saplingActive = Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_SAPLING);
487c9020 5855
6e9c7629
JG
5856 // Validate the destination address
5857 auto destaddress = params[1].get_str();
487c9020 5858 bool isToSproutZaddr = false;
61caa466 5859 bool isToSaplingZaddr = false;
b6be3e88
JG
5860 CTxDestination taddr = DecodeDestination(destaddress);
5861 if (!IsValidDestination(taddr)) {
5f63373e 5862 if (IsValidPaymentAddressString(destaddress, branchId)) {
61caa466
S
5863 // Is this a Sapling address?
5864 auto res = DecodePaymentAddress(destaddress);
5865 if (IsValidPaymentAddress(res)) {
5866 isToSaplingZaddr = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
5867 } else {
487c9020 5868 isToSproutZaddr = true;
61caa466 5869 }
80ed13d5 5870 } else {
6e9c7629
JG
5871 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
5872 }
5873 }
2f151c30 5874 else if ( ASSETCHAINS_PRIVATE != 0 )
5875 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain");
6e9c7629
JG
5876
5877 // Convert fee from currency format to zatoshis
5878 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
5879 if (params.size() > 2) {
5880 if (params[2].get_real() == 0.0) {
5881 nFee = 0;
5882 } else {
5883 nFee = AmountFromValue( params[2] );
5884 }
5885 }
5886
5887 int nUTXOLimit = MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT;
5888 if (params.size() > 3) {
5889 nUTXOLimit = params[3].get_int();
5890 if (nUTXOLimit < 0) {
5891 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of UTXOs cannot be negative");
5892 }
5893 }
5894
487c9020
EOW
5895 int sproutNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT;
5896 int saplingNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT;
6e9c7629 5897 if (params.size() > 4) {
487c9020 5898 int nNoteLimit = params[4].get_int();
6e9c7629
JG
5899 if (nNoteLimit < 0) {
5900 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of notes cannot be negative");
5901 }
487c9020
EOW
5902 sproutNoteLimit = nNoteLimit;
5903 saplingNoteLimit = nNoteLimit;
6e9c7629
JG
5904 }
5905
5906 std::string memo;
5907 if (params.size() > 5) {
5908 memo = params[5].get_str();
487c9020 5909 if (!(isToSproutZaddr || isToSaplingZaddr)) {
6e9c7629
JG
5910 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
5911 } else if (!IsHex(memo)) {
5912 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
5913 }
5914 if (memo.length() > ZC_MEMO_SIZE*2) {
5915 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
5916 }
5917 }
5918
5919 MergeToAddressRecipient recipient(destaddress, memo);
5920
5921 // Prepare to get UTXOs and notes
5922 std::vector<MergeToAddressInputUTXO> utxoInputs;
487c9020
EOW
5923 std::vector<MergeToAddressInputSproutNote> sproutNoteInputs;
5924 std::vector<MergeToAddressInputSaplingNote> saplingNoteInputs;
6e9c7629
JG
5925 CAmount mergedUTXOValue = 0;
5926 CAmount mergedNoteValue = 0;
5927 CAmount remainingUTXOValue = 0;
5928 CAmount remainingNoteValue = 0;
7d2e4b3c 5929 #ifdef __LP64__
5930 uint64_t utxoCounter = 0;
5931 uint64_t noteCounter = 0;
5932 #else
6e9c7629
JG
5933 size_t utxoCounter = 0;
5934 size_t noteCounter = 0;
7d2e4b3c 5935 #endif
6e9c7629
JG
5936 bool maxedOutUTXOsFlag = false;
5937 bool maxedOutNotesFlag = false;
31afbcc5 5938 size_t mempoolLimit = (nUTXOLimit != 0) ? nUTXOLimit : (overwinterActive ? 0 : (size_t)GetArg("-mempooltxinputlimit", 0));
6e9c7629 5939
487c9020 5940 unsigned int max_tx_size = saplingActive ? MAX_TX_SIZE_AFTER_SAPLING : MAX_TX_SIZE_BEFORE_SAPLING;
6e9c7629 5941 size_t estimatedTxSize = 200; // tx overhead + wiggle room
487c9020 5942 if (isToSproutZaddr) {
6e9c7629 5943 estimatedTxSize += JOINSPLIT_SIZE;
487c9020
EOW
5944 } else if (isToSaplingZaddr) {
5945 estimatedTxSize += OUTPUTDESCRIPTION_SIZE;
6e9c7629
JG
5946 }
5947
487c9020 5948 if (useAnyUTXO || taddrs.size() > 0) {
6e9c7629
JG
5949 // Get available utxos
5950 vector<COutput> vecOutputs;
1f8fd6fc 5951 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true, false, false, false);
6e9c7629
JG
5952
5953 // Find unspent utxos and update estimated size
5954 for (const COutput& out : vecOutputs) {
5955 if (!out.fSpendable) {
5956 continue;
5957 }
5958
487c9020
EOW
5959 CScript scriptPubKey = out.tx->vout[out.i].scriptPubKey;
5960
6e9c7629 5961 CTxDestination address;
487c9020 5962 if (!ExtractDestination(scriptPubKey, address)) {
6e9c7629
JG
5963 continue;
5964 }
5965 // If taddr is not wildcard "*", filter utxos
5966 if (taddrs.size() > 0 && !taddrs.count(address)) {
5967 continue;
5968 }
5969
5970 utxoCounter++;
5971 CAmount nValue = out.tx->vout[out.i].nValue;
5972
5973 if (!maxedOutUTXOsFlag) {
b6be3e88 5974 size_t increase = (boost::get<CScriptID>(&address) != nullptr) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
15ec5525 5975 if (estimatedTxSize + increase >= max_tx_size ||
6e9c7629
JG
5976 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
5977 {
5978 maxedOutUTXOsFlag = true;
5979 } else {
5980 estimatedTxSize += increase;
5981 COutPoint utxo(out.tx->GetHash(), out.i);
487c9020 5982 utxoInputs.emplace_back(utxo, nValue, scriptPubKey);
6e9c7629
JG
5983 mergedUTXOValue += nValue;
5984 }
5985 }
5986
5987 if (maxedOutUTXOsFlag) {
5988 remainingUTXOValue += nValue;
5989 }
5990 }
5991 }
5992
487c9020 5993 if (useAnySprout || useAnySapling || zaddrs.size() > 0) {
6e9c7629 5994 // Get available notes
a630f503 5995 std::vector<SproutNoteEntry> sproutEntries;
94e99acd
JG
5996 std::vector<SaplingNoteEntry> saplingEntries;
5997 pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs);
6e9c7629 5998
487c9020
EOW
5999 // If Sapling is not active, do not allow sending from a sapling addresses.
6000 if (!saplingActive && saplingEntries.size() > 0) {
6001 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
6002 }
a8055cfe
E
6003 // Do not include Sprout/Sapling notes if using "ANY_SAPLING"/"ANY_SPROUT" respectively
6004 if (useAnySprout) {
6005 saplingEntries.clear();
6006 }
6007 if (useAnySapling) {
6008 sproutEntries.clear();
6009 }
12040363 6010 // Sending from both Sprout and Sapling is currently unsupported using z_mergetoaddress
a8055cfe 6011 if ((sproutEntries.size() > 0 && saplingEntries.size() > 0) || (useAnySprout && useAnySapling)) {
487c9020
EOW
6012 throw JSONRPCError(
6013 RPC_INVALID_PARAMETER,
6014 "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress");
12040363
EOW
6015 }
6016 // If sending between shielded addresses, they must be the same type
6017 if ((saplingEntries.size() > 0 && isToSproutZaddr) || (sproutEntries.size() > 0 && isToSaplingZaddr)) {
487c9020
EOW
6018 throw JSONRPCError(
6019 RPC_INVALID_PARAMETER,
12040363 6020 "Cannot send between Sprout and Sapling addresses using z_mergetoaddress");
487c9020
EOW
6021 }
6022
6e9c7629 6023 // Find unspent notes and update estimated size
a630f503 6024 for (const SproutNoteEntry& entry : sproutEntries) {
6e9c7629 6025 noteCounter++;
a630f503 6026 CAmount nValue = entry.note.value();
6e9c7629
JG
6027
6028 if (!maxedOutNotesFlag) {
6029 // If we haven't added any notes yet and the merge is to a
6030 // z-address, we have already accounted for the first JoinSplit.
487c9020 6031 size_t increase = (sproutNoteInputs.empty() && !isToSproutZaddr) || (sproutNoteInputs.size() % 2 == 0) ? JOINSPLIT_SIZE : 0;
15ec5525 6032 if (estimatedTxSize + increase >= max_tx_size ||
487c9020 6033 (sproutNoteLimit > 0 && noteCounter > sproutNoteLimit))
6e9c7629
JG
6034 {
6035 maxedOutNotesFlag = true;
6036 } else {
6037 estimatedTxSize += increase;
94e99acd 6038 auto zaddr = entry.address;
e5eab182 6039 SproutSpendingKey zkey;
25d5e80c 6040 pwalletMain->GetSproutSpendingKey(zaddr, zkey);
a630f503 6041 sproutNoteInputs.emplace_back(entry.jsop, entry.note, nValue, zkey);
487c9020
EOW
6042 mergedNoteValue += nValue;
6043 }
6044 }
6045
6046 if (maxedOutNotesFlag) {
6047 remainingNoteValue += nValue;
6048 }
6049 }
6050
6051 for (const SaplingNoteEntry& entry : saplingEntries) {
6052 noteCounter++;
6053 CAmount nValue = entry.note.value();
6054 if (!maxedOutNotesFlag) {
6055 size_t increase = SPENDDESCRIPTION_SIZE;
6056 if (estimatedTxSize + increase >= max_tx_size ||
6057 (saplingNoteLimit > 0 && noteCounter > saplingNoteLimit))
6058 {
6059 maxedOutNotesFlag = true;
6060 } else {
6061 estimatedTxSize += increase;
6062 libzcash::SaplingExtendedSpendingKey extsk;
6063 if (!pwalletMain->GetSaplingExtendedSpendingKey(entry.address, extsk)) {
6064 throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find spending key for payment address.");
6065 }
6066 saplingNoteInputs.emplace_back(entry.op, entry.note, nValue, extsk.expsk);
6e9c7629
JG
6067 mergedNoteValue += nValue;
6068 }
6069 }
6070
6071 if (maxedOutNotesFlag) {
6072 remainingNoteValue += nValue;
6073 }
6074 }
6075 }
6076
7d2e4b3c 6077 #ifdef __LP64__
6078 uint64_t numUtxos = utxoInputs.size(); //ca333
7d2e4b3c 6079 #else
6e9c7629 6080 size_t numUtxos = utxoInputs.size();
7d2e4b3c 6081 #endif
6082
487c9020 6083 size_t numNotes = sproutNoteInputs.size() + saplingNoteInputs.size();
6e9c7629
JG
6084
6085 if (numUtxos == 0 && numNotes == 0) {
6086 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any funds to merge.");
6087 }
6088
6089 // Sanity check: Don't do anything if:
6090 // - We only have one from address
6091 // - It's equal to toaddress
6092 // - The address only contains a single UTXO or note
6093 if (setAddress.size() == 1 && setAddress.count(destaddress) && (numUtxos + numNotes) == 1) {
6094 throw JSONRPCError(RPC_INVALID_PARAMETER, "Destination address is also the only source address, and all its funds are already merged.");
6095 }
6096
6097 CAmount mergedValue = mergedUTXOValue + mergedNoteValue;
6098 if (mergedValue < nFee) {
6099 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
6100 strprintf("Insufficient funds, have %s, which is less than miners fee %s",
6101 FormatMoney(mergedValue), FormatMoney(nFee)));
6102 }
6103
6104 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
6105 CAmount netAmount = mergedValue - nFee;
6106 if (nFee > netAmount) {
6107 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
6108 }
6109
6110 // Keep record of parameters in context object
6111 UniValue contextInfo(UniValue::VOBJ);
6112 contextInfo.push_back(Pair("fromaddresses", params[0]));
6113 contextInfo.push_back(Pair("toaddress", params[1]));
6114 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
6115
6116 // Contextual transaction we will build on
6117 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
6118 Params().GetConsensus(),
7b92f27e 6119 nextBlockHeight);
487c9020
EOW
6120 bool isSproutShielded = sproutNoteInputs.size() > 0 || isToSproutZaddr;
6121 if (contextualTx.nVersion == 1 && isSproutShielded) {
f57f76d7 6122 contextualTx.nVersion = 2; // Tx format should support vJoinSplit
6e9c7629
JG
6123 }
6124
487c9020
EOW
6125 // Builder (used if Sapling addresses are involved)
6126 boost::optional<TransactionBuilder> builder;
6127 if (isToSaplingZaddr || saplingNoteInputs.size() > 0) {
8865f4b6 6128 builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain);
487c9020 6129 }
6e9c7629
JG
6130 // Create operation and add to global queue
6131 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
6132 std::shared_ptr<AsyncRPCOperation> operation(
487c9020 6133 new AsyncRPCOperation_mergetoaddress(builder, contextualTx, utxoInputs, sproutNoteInputs, saplingNoteInputs, recipient, nFee, contextInfo) );
6e9c7629
JG
6134 q->addOperation(operation);
6135 AsyncRPCOperationId operationId = operation->getId();
6136
6137 // Return continuation information
6138 UniValue o(UniValue::VOBJ);
4ff92bb6 6139 o.push_back(Pair("remainingUTXOs", static_cast<uint64_t>(utxoCounter - numUtxos)));
6e9c7629 6140 o.push_back(Pair("remainingTransparentValue", ValueFromAmount(remainingUTXOValue)));
4ff92bb6 6141 o.push_back(Pair("remainingNotes", static_cast<uint64_t>(noteCounter - numNotes)));
6e9c7629 6142 o.push_back(Pair("remainingShieldedValue", ValueFromAmount(remainingNoteValue)));
4ff92bb6 6143 o.push_back(Pair("mergingUTXOs", static_cast<uint64_t>(numUtxos)));
6e9c7629 6144 o.push_back(Pair("mergingTransparentValue", ValueFromAmount(mergedUTXOValue)));
4ff92bb6 6145 o.push_back(Pair("mergingNotes", static_cast<uint64_t>(numNotes)));
6e9c7629
JG
6146 o.push_back(Pair("mergingShieldedValue", ValueFromAmount(mergedNoteValue)));
6147 o.push_back(Pair("opid", operationId));
6148 return o;
6149}
6150
6151
0d37ae3a 6152UniValue z_listoperationids(const UniValue& params, bool fHelp)
34f0001c
S
6153{
6154 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 6155 return NullUniValue;
34f0001c
S
6156
6157 if (fHelp || params.size() > 1)
6158 throw runtime_error(
6159 "z_listoperationids\n"
6160 "\nReturns the list of operation ids currently known to the wallet.\n"
6161 "\nArguments:\n"
c938fb1f 6162 "1. \"status\" (string, optional) Filter result by the operation's state e.g. \"success\".\n"
34f0001c
S
6163 "\nResult:\n"
6164 "[ (json array of string)\n"
6165 " \"operationid\" (string) an operation id belonging to the wallet\n"
6166 " ,...\n"
6167 "]\n"
6168 "\nExamples:\n"
6169 + HelpExampleCli("z_listoperationids", "")
6170 + HelpExampleRpc("z_listoperationids", "")
6171 );
6172
6173 LOCK2(cs_main, pwalletMain->cs_wallet);
6174
6175 std::string filter;
6176 bool useFilter = false;
6177 if (params.size()==1) {
6178 filter = params[0].get_str();
6179 useFilter = true;
6180 }
6181
0d37ae3a 6182 UniValue ret(UniValue::VARR);
34f0001c
S
6183 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
6184 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
6185 for (auto id : ids) {
6186 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
6187 if (!operation) {
6188 continue;
6189 }
6190 std::string state = operation->getStateAsString();
6191 if (useFilter && filter.compare(state)!=0)
6192 continue;
6193 ret.push_back(id);
6194 }
6195
6196 return ret;
6197}
4c62ef37 6198
6199
6200#include "script/sign.h"
6201int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
6202extern std::string NOTARY_PUBKEY;
a7fc9554 6203uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime,char *destaddr);
ac531095 6204int8_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256 txid,int32_t vout);
53debd37 6205void komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n);
4c62ef37 6206
496f1fd2 6207int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33)
6208{
f31815fc 6209 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 6210 bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr;
6211 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
6212 const CKeyStore& keystore = *pwalletMain;
496f1fd2 6213 assert(pwalletMain != NULL);
6214 LOCK2(cs_main, pwalletMain->cs_wallet);
6215 utxovalue = 0;
6216 memset(&utxotxid,0,sizeof(utxotxid));
6217 memset(&utxovout,0,sizeof(utxovout));
6218 memset(utxosig,0,sizeof(utxosig));
6219 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
6220 BOOST_FOREACH(const COutput& out, vecOutputs)
6221 {
6222 if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth )
6223 continue;
6224 if ( setAddress.size() )
6225 {
6226 CTxDestination address;
6227 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
6228 continue;
6229 if (!setAddress.count(address))
6230 continue;
6231 }
6232 CAmount nValue = out.tx->vout[out.i].nValue;
39fefa6b 6233 if ( nValue != 10000 )
6234 continue;
496f1fd2 6235 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
6236 CTxDestination address;
6237 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
6238 {
6239 //entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
6240 //if (pwalletMain->mapAddressBook.count(address))
6241 // entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
6242 }
9feb4b9e 6243 script = (uint8_t *)&out.tx->vout[out.i].scriptPubKey[0];
496f1fd2 6244 if ( out.tx->vout[out.i].scriptPubKey.size() != 35 || script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(notarypub33,script+1,33) != 0 )
c4eb1abb 6245 {
137e08d7 6246 //fprintf(stderr,"scriptsize.%d [0] %02x\n",(int32_t)out.tx->vout[out.i].scriptPubKey.size(),script[0]);
496f1fd2 6247 continue;
c4eb1abb 6248 }
496f1fd2 6249 utxovalue = (uint64_t)nValue;
15000127 6250 //decode_hex((uint8_t *)&utxotxid,32,(char *)out.tx->GetHash().GetHex().c_str());
6251 utxotxid = out.tx->GetHash();
496f1fd2 6252 utxovout = out.i;
ff1ee86e 6253 best_scriptPubKey = out.tx->vout[out.i].scriptPubKey;
15000127 6254 //fprintf(stderr,"check %s/v%d %llu\n",(char *)utxotxid.GetHex().c_str(),utxovout,(long long)utxovalue);
fd2fd9a7 6255
496f1fd2 6256 txNew.vin.resize(1);
6257 txNew.vout.resize(1);
2ad15573 6258 txfee = utxovalue / 2;
3566cdf6 6259 //for (i=0; i<32; i++)
6260 // ((uint8_t *)&revtxid)[i] = ((uint8_t *)&utxotxid)[31 - i];
6261 txNew.vin[0].prevout.hash = utxotxid; //revtxid;
496f1fd2 6262 txNew.vin[0].prevout.n = utxovout;
221cc791 6263 txNew.vout[0].scriptPubKey = CScript() << ParseHex(CRYPTO777_PUBSECPSTR) << OP_CHECKSIG;
496f1fd2 6264 txNew.vout[0].nValue = utxovalue - txfee;
6265 CTransaction txNewConst(txNew);
6266 signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, utxovalue, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId);
6267 if (!signSuccess)
6268 fprintf(stderr,"notaryvin failed to create signature\n");
6269 else
6270 {
6271 UpdateTransaction(txNew,0,sigdata);
9feb4b9e 6272 ptr = (uint8_t *)&sigdata.scriptSig[0];
496f1fd2 6273 siglen = sigdata.scriptSig.size();
6274 for (i=0; i<siglen; i++)
db4b45a6 6275 utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]);
6276 //fprintf(stderr," siglen.%d notaryvin %s/v%d\n",siglen,utxotxid.GetHex().c_str(),utxovout);
ff1ee86e 6277 break;
496f1fd2 6278 }
6279 }
6280 return(siglen);
6281}
6282
ac531095 6283struct komodo_staking
4c62ef37 6284{
ac531095 6285 char address[64];
6286 uint256 txid;
6287 arith_uint256 hashval;
6288 uint64_t nValue;
1273624d 6289 uint32_t segid32,txtime;
ac531095 6290 int32_t vout;
1273624d 6291 CScript scriptPubKey;
ac531095 6292};
6293
1273624d 6294struct komodo_staking *komodo_addutxo(struct komodo_staking *array,int32_t *numkp,int32_t *maxkp,uint32_t txtime,uint64_t nValue,uint256 txid,int32_t vout,char *address,uint8_t *hashbuf,CScript pk)
ac531095 6295{
6296 uint256 hash; uint32_t segid32; struct komodo_staking *kp;
6297 segid32 = komodo_stakehash(&hash,address,hashbuf,txid,vout);
1273624d 6298 if ( *numkp >= *maxkp )
6299 {
6300 *maxkp += 1000;
6301 array = (struct komodo_staking *)realloc(array,sizeof(*array) * (*maxkp));
6302 }
6303 kp = &array[(*numkp)++];
6304 memset(kp,0,sizeof(*kp));
ac531095 6305 strcpy(kp->address,address);
6306 kp->txid = txid;
6307 kp->vout = vout;
6308 kp->hashval = UintToArith256(hash);
6309 kp->txtime = txtime;
6310 kp->segid32 = segid32;
6311 kp->nValue = nValue;
6312 kp->scriptPubKey = pk;
6313 return(array);
6314}
6315
6316arith_uint256 _komodo_eligible(struct komodo_staking *kp,arith_uint256 ratio,uint32_t blocktime,int32_t iter,int32_t minage,int32_t segid,int32_t nHeight,uint32_t prevtime)
6317{
6318 int32_t diff; uint64_t coinage; arith_uint256 coinage256,hashval;
6319 diff = (iter + blocktime - kp->txtime - minage);
6320 if ( diff < 0 )
6321 diff = 60;
6322 else if ( diff > 3600*24*30 )
6323 diff = 3600*24*30;
6324 if ( iter > 0 )
6325 diff += segid*2;
6326 coinage = ((uint64_t)kp->nValue/COIN * diff);
0ce374b7 6327 if ( blocktime+iter+segid*2 > prevtime+480 )
6328 coinage *= ((blocktime+iter+segid*2) - (prevtime+400));
6329 //if ( nHeight >= 2500 && blocktime+iter+segid*2 > prevtime+180 )
6330 // coinage *= ((blocktime+iter+segid*2) - (prevtime+60));
ac531095 6331 coinage256 = arith_uint256(coinage+1);
6332 hashval = ratio * (kp->hashval / coinage256);
0ce374b7 6333 //if ( nHeight >= 900 && nHeight < 916 )
6334 // hashval = (hashval / coinage256);
ac531095 6335 return(hashval);
6336}
6337
cca0bdc6 6338uint32_t komodo_eligible(arith_uint256 bnTarget,arith_uint256 ratio,struct komodo_staking *kp,int32_t nHeight,uint32_t blocktime,uint32_t prevtime,int32_t minage,uint8_t *hashbuf)
ac531095 6339{
8e1ca1ad 6340 int32_t maxiters = 600; uint256 hash;
ac531095 6341 int32_t segid,iter,diff; uint64_t coinage; arith_uint256 hashval,coinage256;
cca0bdc6 6342 komodo_stakehash(&hash,kp->address,hashbuf,kp->txid,kp->vout);
6343 kp->hashval = UintToArith256(hash);
ac531095 6344 segid = ((nHeight + kp->segid32) & 0x3f);
6345 hashval = _komodo_eligible(kp,ratio,blocktime,maxiters,minage,segid,nHeight,prevtime);
d3ce166f 6346 //for (int i=32; i>=0; i--)
6347 // fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
6348 //fprintf(stderr," b.%u minage.%d segid.%d ht.%d prev.%u\n",blocktime,minage,segid,nHeight,prevtime);
ac531095 6349 if ( hashval <= bnTarget )
6350 {
6351 for (iter=0; iter<maxiters; iter++)
6352 {
6353 if ( blocktime+iter+segid*2 < kp->txtime+minage )
6354 continue;
37d6294d 6355 hashval = _komodo_eligible(kp,ratio,blocktime,iter,minage,segid,nHeight,prevtime);
ac531095 6356 if ( hashval <= bnTarget )
6357 {
1973dfa0 6358 //fprintf(stderr,"winner %.8f blocktime.%u iter.%d segid.%d\n",(double)kp->nValue/COIN,blocktime,iter,segid);
ac531095 6359 blocktime += iter;
6360 blocktime += segid * 2;
6361 return(blocktime);
6362 }
6363 }
6364 }
6365 return(0);
6366}
6367
d231a6a7 6368int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig)
4c62ef37 6369{
ac531095 6370 static struct komodo_staking *array; static int32_t numkp,maxkp; static uint32_t lasttime;
17839698 6371 set<CBitcoinAddress> setAddress; struct komodo_staking *kp; int32_t winners,segid,minage,nHeight,counter=0,i,m,siglen=0,nMinDepth = 1,nMaxDepth = 99999999; vector<COutput> vecOutputs; uint32_t block_from_future_rejecttime,besttime,eligible,eligible2,earliest = 0; CScript best_scriptPubKey; arith_uint256 mindiff,ratio,bnTarget; CBlockIndex *tipindex,*pindex; CTxDestination address; bool fNegative,fOverflow; uint8_t hashbuf[256]; CTransaction tx; uint256 hashBlock;
357e4ca5 6372 bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
ac531095 6373 mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
6374 ratio = (mindiff / bnTarget);
4c62ef37 6375 assert(pwalletMain != NULL);
6376 LOCK2(cs_main, pwalletMain->cs_wallet);
6377 *utxovaluep = 0;
6378 memset(utxotxidp,0,sizeof(*utxotxidp));
6379 memset(utxovoutp,0,sizeof(*utxovoutp));
6380 memset(utxosig,0,72);
6381 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
55dd6622 6382 if ( (tipindex= chainActive.Tip()) == 0 )
6383 return(0);
4b729ec5 6384 nHeight = tipindex->GetHeight() + 1;
ac531095 6385 if ( (minage= nHeight*3) > 6000 ) // about 100 blocks
6386 minage = 6000;
6387 komodo_segids(hashbuf,nHeight-101,100);
6e7dcf31 6388 if ( *blocktimep > tipindex->nTime+60 )
6389 *blocktimep = tipindex->nTime+60;
2d481115 6390 //fprintf(stderr,"Start scan of utxo for staking %u ht.%d\n",(uint32_t)time(NULL),nHeight);
1973dfa0 6391 if ( time(NULL) > lasttime+600 )
4c62ef37 6392 {
ac531095 6393 if ( array != 0 )
4c62ef37 6394 {
ac531095 6395 free(array);
6396 array = 0;
6397 maxkp = numkp = 0;
817aedba 6398 lasttime = 0;
2e4cc2a2 6399 }
ac531095 6400 BOOST_FOREACH(const COutput& out, vecOutputs)
4c62ef37 6401 {
4b729ec5 6402 if ( (tipindex= chainActive.Tip()) == 0 || tipindex->GetHeight()+1 > nHeight )
2e4cc2a2 6403 {
ac531095 6404 fprintf(stderr,"chain tip changed during staking loop t.%u counter.%d\n",(uint32_t)time(NULL),counter);
6405 return(0);
2e4cc2a2 6406 }
ac531095 6407 counter++;
6408 if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth )
2e4cc2a2 6409 {
ac531095 6410 //fprintf(stderr,"komodo_staked invalid depth %d\n",(int32_t)out.nDepth);
4c62ef37 6411 continue;
2e4cc2a2 6412 }
ac531095 6413 CAmount nValue = out.tx->vout[out.i].nValue;
6414 if ( nValue < COIN || !out.fSpendable )
4c62ef37 6415 continue;
ac531095 6416 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
6417 if ( ExtractDestination(pk,address) != 0 )
4c62ef37 6418 {
ac531095 6419 if ( IsMine(*pwalletMain,address) == 0 )
6420 continue;
458bfcab 6421 if ( GetTransaction(out.tx->GetHash(),tx,hashBlock,true) != 0 && mapBlockIndex.count(hashBlock) && (pindex= mapBlockIndex[hashBlock]) != 0 )
7b6d6985 6422 {
1273624d 6423 array = komodo_addutxo(array,&numkp,&maxkp,(uint32_t)pindex->nTime,(uint64_t)nValue,out.tx->GetHash(),out.i,(char *)CBitcoinAddress(address).ToString().c_str(),hashbuf,(CScript)pk);
ac531095 6424 }
6425 }
4c62ef37 6426 }
ac531095 6427 lasttime = (uint32_t)time(NULL);
8cbf8d6a 6428 //fprintf(stderr,"finished kp data of utxo for staking %u ht.%d numkp.%d maxkp.%d\n",(uint32_t)time(NULL),nHeight,numkp,maxkp);
ac531095 6429 }
17839698 6430 block_from_future_rejecttime = (uint32_t)GetAdjustedTime() + 57;
2d481115 6431 for (i=winners=0; i<numkp; i++)
ac531095 6432 {
4b729ec5 6433 if ( (tipindex= chainActive.Tip()) == 0 || tipindex->GetHeight()+1 > nHeight )
4c62ef37 6434 {
817aedba 6435 fprintf(stderr,"chain tip changed during staking loop t.%u counter.%d\n",(uint32_t)time(NULL),counter);
6436 return(0);
4c62ef37 6437 }
ac531095 6438 kp = &array[i];
cca0bdc6 6439 if ( (eligible2= komodo_eligible(bnTarget,ratio,kp,nHeight,*blocktimep,(uint32_t)tipindex->nTime+27,minage,hashbuf)) == 0 )
76df25be 6440 continue;
ecae680b 6441 eligible = komodo_stake(0,bnTarget,nHeight,kp->txid,kp->vout,0,(uint32_t)tipindex->nTime+27,kp->address);
1973dfa0 6442 //fprintf(stderr,"i.%d %u vs %u\n",i,eligible2,eligible);
ac531095 6443 if ( eligible > 0 )
4c62ef37 6444 {
ac531095 6445 besttime = m = 0;
6446 if ( eligible == komodo_stake(1,bnTarget,nHeight,kp->txid,kp->vout,eligible,(uint32_t)tipindex->nTime+27,kp->address) )
4c62ef37 6447 {
ac531095 6448 while ( eligible == komodo_stake(1,bnTarget,nHeight,kp->txid,kp->vout,eligible,(uint32_t)tipindex->nTime+27,kp->address) )
7b6d6985 6449 {
ac531095 6450 besttime = eligible;
6451 eligible--;
17839698 6452 if ( eligible < block_from_future_rejecttime ) // nothing gained by going earlier
aa2ef3ab 6453 break;
ac531095 6454 m++;
011b0a24 6455 //fprintf(stderr,"m.%d ht.%d validated winning blocktime %u -> %.8f eligible.%u test prior\n",m,nHeight,*blocktimep,(double)kp->nValue/COIN,eligible);
e005f576 6456 }
4c62ef37 6457 }
ac531095 6458 else
6459 {
aecf5859 6460 fprintf(stderr,"ht.%d error validating winning blocktime %u -> %.8f eligible.%u test prior\n",nHeight,*blocktimep,(double)kp->nValue/COIN,eligible);
ac531095 6461 continue;
6462 }
6463 eligible = besttime;
2d481115 6464 winners++;
6465 //fprintf(stderr,"ht.%d validated winning [%d] -> %.8f eligible.%u test prior\n",nHeight,(int32_t)(eligible - tipindex->nTime),(double)kp->nValue/COIN,eligible);
aecf5859 6466 if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || kp->nValue < *utxovaluep)) )
ac531095 6467 {
6468 earliest = eligible;
6469 best_scriptPubKey = kp->scriptPubKey; //out.tx->vout[out.i].scriptPubKey;
6470 *utxovaluep = (uint64_t)kp->nValue;
6471 //decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str());
6472 decode_hex((uint8_t *)utxotxidp,32,(char *)kp->txid.GetHex().c_str());
6473 *utxovoutp = kp->vout;
6474 *txtimep = kp->txtime;//(uint32_t)out.tx->nLockTime;
779b7b3a 6475 fprintf(stderr,"ht.%d earliest.%u [%d].%d (%s) nValue %.8f locktime.%u counter.%d winners.%d\n",nHeight,earliest,(int32_t)(earliest - tipindex->nTime),m,kp->address,(double)kp->nValue/COIN,*txtimep,counter,winners);
ac531095 6476 }
6477 } //else fprintf(stderr,"utxo not eligible\n");
6478 } //else fprintf(stderr,"no tipindex\n");
2d481115 6479 if ( numkp < 10000 && array != 0 )
011b0a24 6480 {
6481 free(array);
6482 array = 0;
6483 maxkp = numkp = 0;
817aedba 6484 lasttime = 0;
8c218b48 6485 }
6486 if ( earliest != 0 )
6487 {
6488 bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid;
6489 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
6490 const CKeyStore& keystore = *pwalletMain;
8c218b48 6491 txNew.vin.resize(1);
6492 txNew.vout.resize(1);
6493 txfee = 0;
6494 for (i=0; i<32; i++)
6495 ((uint8_t *)&revtxid)[i] = ((uint8_t *)utxotxidp)[31 - i];
6496 txNew.vin[0].prevout.hash = revtxid;
6497 txNew.vin[0].prevout.n = *utxovoutp;
4d068367 6498 txNew.vout[0].scriptPubKey = best_scriptPubKey;// CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG;
3c3e04c4 6499 txNew.vout[0].nValue = *utxovaluep - txfee;
09cde8ab 6500 txNew.nLockTime = earliest;
8c218b48 6501 CTransaction txNewConst(txNew);
3c3e04c4 6502 signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, *utxovaluep, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId);
8c218b48 6503 if (!signSuccess)
6504 fprintf(stderr,"failed to create signature\n");
6505 else
4c62ef37 6506 {
d231a6a7 6507 UpdateTransaction(txNew,0,sigdata);
9feb4b9e 6508 ptr = (uint8_t *)&sigdata.scriptSig[0];
8c218b48 6509 siglen = sigdata.scriptSig.size();
6510 for (i=0; i<siglen; i++)
6511 utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]);
6512 //fprintf(stderr," siglen.%d\n",siglen);
ba1587fd 6513 //fprintf(stderr,"best %u from %u, gap %d lag.%d\n",earliest,*blocktimep,(int32_t)(earliest - *blocktimep),(int32_t)(time(NULL) - *blocktimep));
09cde8ab 6514 *blocktimep = earliest;
4c62ef37 6515 }
2b72340d 6516 } //else fprintf(stderr,"no earliest utxo for staking\n");
8cbf8d6a 6517 //fprintf(stderr,"end scan of utxo for staking t.%u counter.%d numkp.%d winners.%d\n",(uint32_t)time(NULL),counter,numkp,winners);
4c62ef37 6518 return(siglen);
6519}
1f722359 6520
855714b0 6521int32_t verus_staked(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &nBits, arith_uint256 &hashResult, std::vector<unsigned char> &utxosig, CTxDestination &rewardDest)
1f722359 6522{
7695dab4 6523 try
6524 {
855714b0 6525 return pwalletMain->VerusStakeTransaction(pBlock, txNew, nBits, hashResult, utxosig, rewardDest);
7695dab4 6526 }
6527 catch(const std::exception& e)
6528 {
6529 printf("ERROR: %s exception in staking\n", e.what());
6530 LogPrintf("ERROR: %s exception in staking\n", e.what());
6531 }
6532 return 0;
1f722359 6533}
5034d1c1 6534
e10def86 6535int32_t ensure_CCrequirements()
6536{
efa4ed1f 6537 extern uint8_t NOTARY_PUBKEY33[];
eafcb941 6538 CCerror = "";
e10def86 6539 if ( NOTARY_PUBKEY33[0] == 0 )
6540 return(-1);
6541 else if ( GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX) == 0 )
6542 return(-1);
6deb8c09 6543 else if ( GetBoolArg("-spentindex", DEFAULT_SPENTINDEX) == 0 )
6544 return(-1);
e10def86 6545 else return(0);
6546}
6547
7c766994 6548#include "../cc/CCfaucet.h"
6549#include "../cc/CCassets.h"
287efad4 6550#include "../cc/CCrewards.h"
cfea7a46 6551#include "../cc/CCdice.h"
7137a022 6552#include "../cc/CCfsm.h"
eca34fd9 6553#include "../cc/CCauction.h"
6554#include "../cc/CClotto.h"
810f6366 6555#include "../cc/CCchannels.h"
3d6ee3e0 6556#include "../cc/CCOracles.h"
98a1f520 6557#include "../cc/CCGateways.h"
e37d99ce 6558
cfea7a46 6559UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector<unsigned char> &pubkey)
e37d99ce 6560{
b3965baa 6561 UniValue result(UniValue::VOBJ); char destaddr[64],str[64]; CPubKey pk;
6562 pk = GetUnspendable(cp,0);
6563 GetCCaddress(cp,destaddr,pk);
6564 if ( strcmp(destaddr,cp->unspendableCCaddr) != 0 )
6565 {
6566 uint8_t priv[32];
aed3f987 6567 Myprivkey(priv); // it is assumed the CC's normal address'es -pubkey was used
b3965baa 6568 fprintf(stderr,"fix mismatched CCaddr %s -> %s\n",cp->unspendableCCaddr,destaddr);
6569 strcpy(cp->unspendableCCaddr,destaddr);
6570 }
e37d99ce 6571 result.push_back(Pair("result", "success"));
cfea7a46 6572 sprintf(str,"%sCCaddress",name);
1702dcef 6573 result.push_back(Pair(str,cp->unspendableCCaddr));
6574 sprintf(str,"%smarker",name);
6575 result.push_back(Pair(str,cp->normaladdr));
e5a5dadb 6576 result.push_back(Pair("GatewaysPubkey","03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40"));
3515c101 6577 if ( _GetCCaddress(destaddr,EVAL_ASSETS,pubkey2pk(pubkey)) > 0 )
6578 {
6579 sprintf(str,"%sCCassets",name);
cfea7a46 6580 result.push_back(Pair(str,destaddr));
3515c101 6581 }
cfea7a46 6582 if ( pubkey.size() == 33 )
e37d99ce 6583 {
e04b5c08 6584 if ( GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0 )
e37d99ce 6585 result.push_back(Pair("CCaddress",destaddr));
8bbfc238 6586 }
e04b5c08 6587 if ( GetCCaddress(cp,destaddr,pubkey2pk(Mypubkey())) != 0 )
e37d99ce 6588 result.push_back(Pair("myCCaddress",destaddr));
e09492b4 6589 if ( Getscriptaddress(destaddr,(CScript() << Mypubkey() << OP_CHECKSIG)) != 0 )
939cd4b6 6590 result.push_back(Pair("myaddress",destaddr));
e37d99ce 6591 return(result);
6592}
6593
810f6366 6594UniValue channelsaddress(const UniValue& params, bool fHelp)
6595{
6596 UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::vector<unsigned char> destpubkey; CPubKey pk,pk2; char destaddr[64];
6597 cp = CCinit(&C,EVAL_CHANNELS);
6598 if ( fHelp || params.size() != 1 )
6599 throw runtime_error("channelsaddress destpubkey\n");
6600 if ( ensure_CCrequirements() < 0 )
6601 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6602 destpubkey = ParseHex(params[0].get_str().c_str());
6603 pk = pubkey2pk(Mypubkey());
6604 pk2 = pubkey2pk(destpubkey);
cafa63fb 6605 result = CCaddress(cp,(char *)"Channels",destpubkey);
810f6366 6606 result.push_back(Pair("otherpubkey", params[0].get_str()));
6607 GetCCaddress1of2(cp,destaddr,pk,pk2);
54690bb0 6608 result.push_back(Pair("channeladdress",destaddr));
810f6366 6609 return(result);
6610}
6611
c926780f 6612UniValue oraclesaddress(const UniValue& params, bool fHelp)
6613{
6614 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6615 cp = CCinit(&C,EVAL_ORACLES);
6616 if ( fHelp || params.size() > 1 )
6617 throw runtime_error("oraclesaddress [pubkey]\n");
6618 if ( ensure_CCrequirements() < 0 )
6619 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6620 if ( params.size() == 1 )
6621 pubkey = ParseHex(params[0].get_str().c_str());
6622 return(CCaddress(cp,(char *)"Oracles",pubkey));
6623}
6624
6625UniValue pricesaddress(const UniValue& params, bool fHelp)
6626{
6627 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6628 cp = CCinit(&C,EVAL_PRICES);
6629 if ( fHelp || params.size() > 1 )
6630 throw runtime_error("pricesaddress [pubkey]\n");
6631 if ( ensure_CCrequirements() < 0 )
6632 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6633 if ( params.size() == 1 )
6634 pubkey = ParseHex(params[0].get_str().c_str());
6635 return(CCaddress(cp,(char *)"Prices",pubkey));
6636}
6637
6638UniValue pegsaddress(const UniValue& params, bool fHelp)
6639{
6640 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6641 cp = CCinit(&C,EVAL_PEGS);
6642 if ( fHelp || params.size() > 1 )
6643 throw runtime_error("pegssaddress [pubkey]\n");
6644 if ( ensure_CCrequirements() < 0 )
6645 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6646 if ( params.size() == 1 )
6647 pubkey = ParseHex(params[0].get_str().c_str());
6648 return(CCaddress(cp,(char *)"Pegs",pubkey));
6649}
6650
6651UniValue triggersaddress(const UniValue& params, bool fHelp)
6652{
6653 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6654 cp = CCinit(&C,EVAL_TRIGGERS);
6655 if ( fHelp || params.size() > 1 )
6656 throw runtime_error("triggersaddress [pubkey]\n");
6657 if ( ensure_CCrequirements() < 0 )
6658 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6659 if ( params.size() == 1 )
6660 pubkey = ParseHex(params[0].get_str().c_str());
6661 return(CCaddress(cp,(char *)"Triggers",pubkey));
6662}
6663
6664UniValue paymentsaddress(const UniValue& params, bool fHelp)
6665{
6666 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6667 cp = CCinit(&C,EVAL_PAYMENTS);
6668 if ( fHelp || params.size() > 1 )
6669 throw runtime_error("paymentsaddress [pubkey]\n");
6670 if ( ensure_CCrequirements() < 0 )
6671 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6672 if ( params.size() == 1 )
6673 pubkey = ParseHex(params[0].get_str().c_str());
6674 return(CCaddress(cp,(char *)"Payments",pubkey));
6675}
6676
6677UniValue gatewaysaddress(const UniValue& params, bool fHelp)
6678{
6679 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6680 cp = CCinit(&C,EVAL_GATEWAYS);
6681 if ( fHelp || params.size() > 1 )
6682 throw runtime_error("gatewaysaddress [pubkey]\n");
6683 if ( ensure_CCrequirements() < 0 )
6684 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6685 if ( params.size() == 1 )
6686 pubkey = ParseHex(params[0].get_str().c_str());
6687 return(CCaddress(cp,(char *)"Gateways",pubkey));
6688}
6689
da629dfe 6690UniValue mofnaddress(const UniValue& params, bool fHelp)
6691{
6692 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6693 cp = CCinit(&C,EVAL_MOFN);
6694 if ( fHelp || params.size() > 1 )
6695 throw runtime_error("mofnaddress [pubkey]\n");
6696 if ( ensure_CCrequirements() < 0 )
6697 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6698 if ( params.size() == 1 )
6699 pubkey = ParseHex(params[0].get_str().c_str());
b3965baa 6700 return(CCaddress(cp,(char *)"MofN",pubkey));
da629dfe 6701}
6702
eca34fd9 6703UniValue lottoaddress(const UniValue& params, bool fHelp)
6704{
6705 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6706 cp = CCinit(&C,EVAL_LOTTO);
6707 if ( fHelp || params.size() > 1 )
6708 throw runtime_error("lottoaddress [pubkey]\n");
6709 if ( ensure_CCrequirements() < 0 )
6710 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6711 if ( params.size() == 1 )
6712 pubkey = ParseHex(params[0].get_str().c_str());
6713 return(CCaddress(cp,(char *)"Lotto",pubkey));
6714}
6715
7137a022 6716UniValue FSMaddress(const UniValue& params, bool fHelp)
eca34fd9 6717{
6718 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
7137a022 6719 cp = CCinit(&C,EVAL_FSM);
eca34fd9 6720 if ( fHelp || params.size() > 1 )
7137a022 6721 throw runtime_error("FSMaddress [pubkey]\n");
eca34fd9 6722 if ( ensure_CCrequirements() < 0 )
6723 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6724 if ( params.size() == 1 )
6725 pubkey = ParseHex(params[0].get_str().c_str());
7137a022 6726 return(CCaddress(cp,(char *)"FSM",pubkey));
eca34fd9 6727}
6728
6729UniValue auctionaddress(const UniValue& params, bool fHelp)
6730{
6731 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
b935ab65 6732 cp = CCinit(&C,EVAL_AUCTION);
eca34fd9 6733 if ( fHelp || params.size() > 1 )
6734 throw runtime_error("auctionaddress [pubkey]\n");
6735 if ( ensure_CCrequirements() < 0 )
6736 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6737 if ( params.size() == 1 )
6738 pubkey = ParseHex(params[0].get_str().c_str());
6739 return(CCaddress(cp,(char *)"Auction",pubkey));
6740}
6741
cfea7a46 6742UniValue diceaddress(const UniValue& params, bool fHelp)
6743{
6744 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
b2b7d05b 6745 cp = CCinit(&C,EVAL_DICE);
cfea7a46 6746 if ( fHelp || params.size() > 1 )
6747 throw runtime_error("diceaddress [pubkey]\n");
6748 if ( ensure_CCrequirements() < 0 )
6749 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6750 if ( params.size() == 1 )
6751 pubkey = ParseHex(params[0].get_str().c_str());
f0f5f6c0 6752 return(CCaddress(cp,(char *)"Dice",pubkey));
cfea7a46 6753}
6754
6755UniValue faucetaddress(const UniValue& params, bool fHelp)
6756{
6757 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
c8c684e9 6758 int32_t errnum;
b2b7d05b 6759 cp = CCinit(&C,EVAL_FAUCET);
cfea7a46 6760 if ( fHelp || params.size() > 1 )
6761 throw runtime_error("faucetaddress [pubkey]\n");
c8c684e9 6762 errnum = ensure_CCrequirements();
6763 if ( errnum < 0 )
6764 throw runtime_error(strprintf("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet. ERR=%d\n", errnum));
cfea7a46 6765 if ( params.size() == 1 )
6766 pubkey = ParseHex(params[0].get_str().c_str());
f0f5f6c0 6767 return(CCaddress(cp,(char *)"Faucet",pubkey));
cfea7a46 6768}
6769
6770UniValue rewardsaddress(const UniValue& params, bool fHelp)
6771{
6772 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
6773 cp = CCinit(&C,EVAL_REWARDS);
6774 if ( fHelp || params.size() > 1 )
6775 throw runtime_error("rewardsaddress [pubkey]\n");
6776 if ( ensure_CCrequirements() < 0 )
6777 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6778 if ( params.size() == 1 )
6779 pubkey = ParseHex(params[0].get_str().c_str());
f0f5f6c0 6780 return(CCaddress(cp,(char *)"Rewards",pubkey));
cfea7a46 6781}
6782
6783UniValue tokenaddress(const UniValue& params, bool fHelp)
6784{
6785 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
b2b7d05b 6786 cp = CCinit(&C,EVAL_ASSETS);
cfea7a46 6787 if ( fHelp || params.size() > 1 )
6788 throw runtime_error("tokenaddress [pubkey]\n");
6789 if ( ensure_CCrequirements() < 0 )
6790 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6791 if ( params.size() == 1 )
6792 pubkey = ParseHex(params[0].get_str().c_str());
f0f5f6c0 6793 return(CCaddress(cp,(char *)"Assets",pubkey));
cfea7a46 6794}
6795
54690bb0 6796UniValue channelsinfo(const UniValue& params, bool fHelp)
6797{
6798 if ( fHelp || params.size() != 0 )
6799 throw runtime_error("channelsinfo\n");
6800 if ( ensure_CCrequirements() < 0 )
6801 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6802 return(ChannelsInfo());
6803}
6804
810f6366 6805UniValue channelsopen(const UniValue& params, bool fHelp)
6806{
02da4225 6807 UniValue result(UniValue::VOBJ); int32_t numpayments; int64_t payment; std::vector<unsigned char> destpub; struct CCcontract_info *cp,C; std::string hex;
810f6366 6808 cp = CCinit(&C,EVAL_CHANNELS);
6809 if ( fHelp || params.size() != 3 )
6810 throw runtime_error("channelsopen destpubkey numpayments payment\n");
6811 if ( ensure_CCrequirements() < 0 )
6812 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6813 LOCK(cs_main);
6814 destpub = ParseHex(params[0].get_str().c_str());
6815 numpayments = atoi(params[1].get_str().c_str());
11020cf2 6816 payment = atol(params[2].get_str().c_str());
810f6366 6817 hex = ChannelOpen(0,pubkey2pk(destpub),numpayments,payment);
6818 if ( hex.size() > 0 )
6819 {
6820 result.push_back(Pair("result", "success"));
6821 result.push_back(Pair("hex", hex));
6822 } else ERR_RESULT("couldnt create channelsopen transaction");
6823 return(result);
6824}
6825
02da4225 6826UniValue channelsstop(const UniValue& params, bool fHelp)
6827{
6828 UniValue result(UniValue::VOBJ); std::vector<unsigned char> destpub; struct CCcontract_info *cp,C; std::string hex; uint256 origtxid;
6829 cp = CCinit(&C,EVAL_CHANNELS);
6830 if ( fHelp || params.size() != 2 )
6831 throw runtime_error("channelsstop destpubkey origtxid\n");
6832 if ( ensure_CCrequirements() < 0 )
6833 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6834 LOCK(cs_main);
6835 destpub = ParseHex(params[0].get_str().c_str());
6836 origtxid = Parseuint256((char *)params[1].get_str().c_str());
6837 hex = ChannelStop(0,pubkey2pk(destpub),origtxid);
6838 if ( hex.size() > 0 )
6839 {
6840 result.push_back(Pair("result", "success"));
6841 result.push_back(Pair("hex", hex));
6842 } else ERR_RESULT("couldnt create channelsstop transaction");
6843 return(result);
6844}
6845
6846UniValue channelspayment(const UniValue& params, bool fHelp)
6847{
6848 UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 origtxid,prevtxid; int32_t n; int64_t amount;
6849 cp = CCinit(&C,EVAL_CHANNELS);
6850 if ( fHelp || params.size() != 4 )
6851 throw runtime_error("channelspayment prevtxid origtxid n amount\n");
6852 if ( ensure_CCrequirements() < 0 )
6853 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6854 LOCK(cs_main);
6855 prevtxid = Parseuint256((char *)params[0].get_str().c_str());
6856 origtxid = Parseuint256((char *)params[1].get_str().c_str());
6857 n = atoi((char *)params[2].get_str().c_str());
6858 amount = atoi((char *)params[3].get_str().c_str());
2b349eff 6859 hex = ChannelPayment(0,prevtxid,origtxid,n,amount);
02da4225 6860 if ( hex.size() > 0 )
6861 {
6862 result.push_back(Pair("result", "success"));
6863 result.push_back(Pair("hex", hex));
6864 } else ERR_RESULT("couldnt create channelspayment transaction");
6865 return(result);
6866}
6867
6868UniValue channelscollect(const UniValue& params, bool fHelp)
6869{
3737d456 6870 UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 origtxid,paytxid; int32_t n; int64_t amount;
02da4225 6871 cp = CCinit(&C,EVAL_CHANNELS);
6872 if ( fHelp || params.size() != 4 )
3737d456 6873 throw runtime_error("channelscollect paytxid origtxid n amount\n");
02da4225 6874 if ( ensure_CCrequirements() < 0 )
6875 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6876 LOCK(cs_main);
3737d456 6877 paytxid = Parseuint256((char *)params[0].get_str().c_str());
02da4225 6878 origtxid = Parseuint256((char *)params[1].get_str().c_str());
6879 n = atoi((char *)params[2].get_str().c_str());
6880 amount = atoi((char *)params[3].get_str().c_str());
3737d456 6881 hex = ChannelCollect(0,paytxid,origtxid,n,amount);
02da4225 6882 if ( hex.size() > 0 )
6883 {
6884 result.push_back(Pair("result", "success"));
6885 result.push_back(Pair("hex", hex));
6886 } else ERR_RESULT("couldnt create channelscollect transaction");
6887 return(result);
6888}
6889
6890UniValue channelsrefund(const UniValue& params, bool fHelp)
6891{
6892 UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 origtxid,stoptxid;
6893 cp = CCinit(&C,EVAL_CHANNELS);
6894 if ( fHelp || params.size() != 2 )
6895 throw runtime_error("channelsrefund stoptxid origtxid\n");
6896 if ( ensure_CCrequirements() < 0 )
6897 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6898 LOCK(cs_main);
6899 stoptxid = Parseuint256((char *)params[0].get_str().c_str());
6900 origtxid = Parseuint256((char *)params[1].get_str().c_str());
6901 hex = ChannelRefund(0,stoptxid,origtxid);
6902 if ( hex.size() > 0 )
6903 {
6904 result.push_back(Pair("result", "success"));
6905 result.push_back(Pair("hex", hex));
6906 } else ERR_RESULT("couldnt create channelsrefund transaction");
6907 return(result);
6908}
6909
e95b9582 6910UniValue rewardscreatefunding(const UniValue& params, bool fHelp)
e37d99ce 6911{
a03146b3 6912 UniValue result(UniValue::VOBJ); char *name; int64_t funds,APR,minseconds,maxseconds,mindeposit; std::string hex;
f0f5f6c0 6913 if ( fHelp || params.size() > 6 || params.size() < 2 )
eac2c15e 6914 throw runtime_error("rewardscreatefunding name amount APR mindays maxdays mindeposit\n");
e37d99ce 6915 if ( ensure_CCrequirements() < 0 )
6916 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 6917 const CKeyStore& keystore = *pwalletMain;
6918 LOCK2(cs_main, pwalletMain->cs_wallet);
6919 // default to OOT params
e37d99ce 6920 APR = 5 * COIN;
6921 minseconds = maxseconds = 60 * 3600 * 24;
6922 mindeposit = 100 * COIN;
11787469 6923 name = (char *)params[0].get_str().c_str();
f0f5f6c0 6924 funds = atof(params[1].get_str().c_str()) * COIN;
a03146b3 6925
bad5d1c3
AL
6926 if (!VALID_PLAN_NAME(name)) {
6927 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
6928 return(result);
6929 }
6930
a03146b3
JDL
6931 if ( funds <= 0 ) {
6932 ERR_RESULT("funds must be positive");
6933 return result;
6934 }
f0f5f6c0 6935 if ( params.size() > 2 )
e37d99ce 6936 {
f0f5f6c0 6937 APR = atof(params[2].get_str().c_str()) * COIN;
a03146b3
JDL
6938 if ( APR > REWARDSCC_MAXAPR )
6939 {
6940 ERR_RESULT("25% APR is maximum");
6941 return result;
6942 }
f0f5f6c0 6943 if ( params.size() > 3 )
e37d99ce 6944 {
f0f5f6c0 6945 minseconds = atol(params[3].get_str().c_str()) * 3600 * 24;
a03146b3
JDL
6946 if ( minseconds < 0 ) {
6947 ERR_RESULT("mindays must be non-negative");
6948 return result;
6949 }
f0f5f6c0 6950 if ( params.size() > 4 )
e37d99ce 6951 {
f0f5f6c0 6952 maxseconds = atol(params[4].get_str().c_str()) * 3600 * 24;
a03146b3
JDL
6953 if ( maxseconds <= 0 ) {
6954 ERR_RESULT("maxdays must be positive");
6955 return result;
6956 }
6957 if ( maxseconds < minseconds ) {
6958 ERR_RESULT("maxdays must be greater than mindays");
6959 return result;
6960 }
f0f5f6c0 6961 if ( params.size() > 5 )
6962 mindeposit = atof(params[5].get_str().c_str()) * COIN;
a03146b3
JDL
6963 if ( mindeposit <= 0 ) {
6964 ERR_RESULT("mindeposit must be positive");
6965 return result;
6966 }
e37d99ce 6967 }
6968 }
6969 }
4f394f44 6970 hex = RewardsCreateFunding(0,name,funds,APR,minseconds,maxseconds,mindeposit);
e37d99ce 6971 if ( hex.size() > 0 )
6972 {
6973 result.push_back(Pair("result", "success"));
6974 result.push_back(Pair("hex", hex));
8a3e1884 6975 } else ERR_RESULT("couldnt create rewards funding transaction");
e37d99ce 6976 return(result);
6977}
6978
6979UniValue rewardslock(const UniValue& params, bool fHelp)
6980{
66027c02 6981 UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid; int64_t amount; std::string hex;
c4e7f616 6982 if ( fHelp || params.size() != 3 )
6983 throw runtime_error("rewardslock name fundingtxid amount\n");
e37d99ce 6984 if ( ensure_CCrequirements() < 0 )
6985 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 6986 const CKeyStore& keystore = *pwalletMain;
6987 LOCK2(cs_main, pwalletMain->cs_wallet);
f0f5f6c0 6988 name = (char *)params[0].get_str().c_str();
c4e7f616 6989 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
6990 amount = atof(params[2].get_str().c_str()) * COIN;
6991 hex = RewardsLock(0,name,fundingtxid,amount);
bad5d1c3
AL
6992
6993 if (!VALID_PLAN_NAME(name)) {
6994 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
6995 return(result);
6996 }
a03146b3
JDL
6997 if ( CCerror != "" ){
6998 ERR_RESULT(CCerror);
6999 } else if ( amount > 0 ) {
66027c02
JDL
7000 if ( hex.size() > 0 )
7001 {
7002 result.push_back(Pair("result", "success"));
7003 result.push_back(Pair("hex", hex));
8a3e1884
JDL
7004 } else ERR_RESULT( "couldnt create rewards lock transaction");
7005 } else ERR_RESULT("amount must be positive");
c4e7f616 7006 return(result);
7007}
7008
7009UniValue rewardsaddfunding(const UniValue& params, bool fHelp)
7010{
88e71457 7011 UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid; int64_t amount; std::string hex;
c4e7f616 7012 if ( fHelp || params.size() != 3 )
7013 throw runtime_error("rewardsaddfunding name fundingtxid amount\n");
7014 if ( ensure_CCrequirements() < 0 )
7015 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7016 const CKeyStore& keystore = *pwalletMain;
7017 LOCK2(cs_main, pwalletMain->cs_wallet);
c4e7f616 7018 name = (char *)params[0].get_str().c_str();
7019 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
7020 amount = atof(params[2].get_str().c_str()) * COIN;
e95b9582 7021 hex = RewardsAddfunding(0,name,fundingtxid,amount);
bad5d1c3
AL
7022
7023 if (!VALID_PLAN_NAME(name)) {
7024 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
7025 return(result);
7026 }
a03146b3
JDL
7027 if (CCerror != "") {
7028 ERR_RESULT(CCerror);
7029 } else if (amount > 0) {
88e71457
JDL
7030 if ( hex.size() > 0 )
7031 {
7032 result.push_back(Pair("result", "success"));
7033 result.push_back(Pair("hex", hex));
7034 } else {
7035 result.push_back(Pair("result", "error"));
7036 result.push_back(Pair("error", "couldnt create rewards addfunding transaction"));
7037 }
7038 } else {
a03146b3 7039 ERR_RESULT("funding amount must be positive");
88e71457 7040 }
e37d99ce 7041 return(result);
7042}
7043
7044UniValue rewardsunlock(const UniValue& params, bool fHelp)
7045{
c4e7f616 7046 UniValue result(UniValue::VOBJ); std::string hex; char *name; uint256 fundingtxid,txid;
81915d9f 7047 if ( fHelp || params.size() > 3 || params.size() < 2 )
c4e7f616 7048 throw runtime_error("rewardsunlock name fundingtxid [txid]\n");
e37d99ce 7049 if ( ensure_CCrequirements() < 0 )
7050 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7051 const CKeyStore& keystore = *pwalletMain;
7052 LOCK2(cs_main, pwalletMain->cs_wallet);
f0f5f6c0 7053 name = (char *)params[0].get_str().c_str();
c4e7f616 7054 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
bad5d1c3
AL
7055
7056 if (!VALID_PLAN_NAME(name)) {
7057 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
7058 return(result);
7059 }
c4e7f616 7060 if ( params.size() > 2 )
7061 txid = Parseuint256((char *)params[2].get_str().c_str());
f0f5f6c0 7062 else memset(&txid,0,sizeof(txid));
c4e7f616 7063 hex = RewardsUnlock(0,name,fundingtxid,txid);
8e0ff2b7 7064 if (CCerror != "") {
8a3e1884
JDL
7065 ERR_RESULT(CCerror);
7066 } else if ( hex.size() > 0 ) {
e37d99ce 7067 result.push_back(Pair("result", "success"));
7068 result.push_back(Pair("hex", hex));
8a3e1884 7069 } else ERR_RESULT("couldnt create rewards unlock transaction");
e37d99ce 7070 return(result);
7071}
7072
c857567a 7073UniValue rewardslist(const UniValue& params, bool fHelp)
7074{
c857567a 7075 if ( fHelp || params.size() > 0 )
7076 throw runtime_error("rewardslist\n");
7077 if ( ensure_CCrequirements() < 0 )
7078 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7079 return(RewardsList());
7080}
7081
7082UniValue rewardsinfo(const UniValue& params, bool fHelp)
7083{
7084 uint256 fundingtxid;
7085 if ( fHelp || params.size() != 1 )
7086 throw runtime_error("rewardsinfo fundingtxid\n");
7087 if ( ensure_CCrequirements() < 0 )
7088 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7089 fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
7090 return(RewardsInfo(fundingtxid));
7091}
7092
3515c101 7093UniValue gatewayslist(const UniValue& params, bool fHelp)
6ff08712 7094{
3515c101 7095 if ( fHelp || params.size() > 0 )
7096 throw runtime_error("gatewayslist\n");
6ff08712 7097 if ( ensure_CCrequirements() < 0 )
7098 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
3515c101 7099 return(GatewaysList());
7100}
7101
7102UniValue gatewaysinfo(const UniValue& params, bool fHelp)
7103{
7104 uint256 txid;
7105 if ( fHelp || params.size() != 1 )
7106 throw runtime_error("gatewaysinfo bindtxid\n");
7107 if ( ensure_CCrequirements() < 0 )
7108 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7109 txid = Parseuint256((char *)params[0].get_str().c_str());
7110 return(GatewaysInfo(txid));
7111}
7112
7113UniValue gatewaysbind(const UniValue& params, bool fHelp)
7114{
dbf8484e 7115 UniValue result(UniValue::VOBJ); uint256 tokenid,oracletxid; int32_t i; int64_t totalsupply; std::vector<CPubKey> pubkeys; uint8_t M,N; std::string hex,coin; std::vector<unsigned char> pubkey;
7116 if ( fHelp || params.size() < 6 )
7117 throw runtime_error("gatewaysbind tokenid oracletxid coin tokensupply M N pubkey(s)\n");
3515c101 7118 if ( ensure_CCrequirements() < 0 )
7119 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7120 tokenid = Parseuint256((char *)params[0].get_str().c_str());
dbf8484e 7121 oracletxid = Parseuint256((char *)params[1].get_str().c_str());
7122 coin = params[2].get_str();
7123 totalsupply = atol((char *)params[3].get_str().c_str());
7124 M = atoi((char *)params[4].get_str().c_str());
7125 N = atoi((char *)params[5].get_str().c_str());
98a1f520 7126 if ( M > N || N == 0 || N > 15 || totalsupply < COIN/100 || tokenid == zeroid )
3515c101 7127 throw runtime_error("illegal M or N > 15 or tokensupply or invalid tokenid\n");
3515c101 7128 for (i=0; i<N; i++)
7129 {
77fad432 7130 if ( params.size() < 6+i+1 )
3515c101 7131 throw runtime_error("not enough parameters for N pubkeys\n");
77fad432 7132 pubkey = ParseHex(params[6+i].get_str().c_str());
3515c101 7133 pubkeys.push_back(pubkey2pk(pubkey));
7134 }
dbf8484e 7135 hex = GatewaysBind(0,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys);
cfea7a46 7136 if ( hex.size() > 0 )
6ff08712 7137 {
cfea7a46 7138 result.push_back(Pair("result", "success"));
7139 result.push_back(Pair("hex", hex));
3515c101 7140 } else ERR_RESULT("couldnt gatewaysbind");
6ff08712 7141 return(result);
7142}
7143
3515c101 7144UniValue gatewaysdeposit(const UniValue& params, bool fHelp)
cfea7a46 7145{
e5a5dadb 7146 UniValue result(UniValue::VOBJ); int32_t i,claimvout,height; int64_t amount; std::string hex,coin,deposithex; uint256 bindtxid,cointxid; std::vector<uint8_t>proof,destpub,pubkey;
7147 if ( fHelp || params.size() != 9 )
7148 throw runtime_error("gatewaysdeposit bindtxid height coin cointxid claimvout deposithex proof destpub amount\n");
cfea7a46 7149 if ( ensure_CCrequirements() < 0 )
7150 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
d73f18f5 7151 bindtxid = Parseuint256((char *)params[0].get_str().c_str());
7152 height = atoi((char *)params[1].get_str().c_str());
7153 coin = params[2].get_str();
7154 cointxid = Parseuint256((char *)params[3].get_str().c_str());
7155 claimvout = atoi((char *)params[4].get_str().c_str());
7156 deposithex = params[5].get_str();
7157 proof = ParseHex(params[6].get_str());
7f9283e5 7158 destpub = ParseHex(params[7].get_str());
d73f18f5 7159 amount = atof((char *)params[8].get_str().c_str()) * COIN;
a5ea3ded 7160 if ( amount <= 0 || claimvout < 0 )
d73f18f5 7161 throw runtime_error("invalid param: amount, numpks or claimvout\n");
e5a5dadb 7162 hex = GatewaysDeposit(0,bindtxid,height,coin,cointxid,claimvout,deposithex,proof,pubkey2pk(destpub),amount);
cfea7a46 7163 if ( hex.size() > 0 )
7164 {
7165 result.push_back(Pair("result", "success"));
7166 result.push_back(Pair("hex", hex));
3515c101 7167 } else ERR_RESULT("couldnt gatewaysdeposit");
cfea7a46 7168 return(result);
7169}
7170
3515c101 7171UniValue gatewaysclaim(const UniValue& params, bool fHelp)
65a961ff 7172{
7f9283e5 7173 UniValue result(UniValue::VOBJ); std::string hex,coin; uint256 bindtxid,deposittxid; std::vector<uint8_t>destpub; int64_t amount;
72e3df01 7174 if ( fHelp || params.size() != 5 )
3f4351c9 7175 throw runtime_error("gatewaysclaim bindtxid coin deposittxid destpub amount\n");
e10def86 7176 if ( ensure_CCrequirements() < 0 )
7177 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
f81291ae 7178 bindtxid = Parseuint256((char *)params[0].get_str().c_str());
7179 coin = params[1].get_str();
72e3df01 7180 deposittxid = Parseuint256((char *)params[2].get_str().c_str());
7f9283e5 7181 destpub = ParseHex(params[3].get_str());
72e3df01 7182 amount = atof((char *)params[4].get_str().c_str()) * COIN;
7f9283e5 7183 hex = GatewaysClaim(0,bindtxid,coin,deposittxid,pubkey2pk(destpub),amount);
9e6c9706 7184 if ( hex.size() > 0 )
65a961ff 7185 {
7186 result.push_back(Pair("result", "success"));
7187 result.push_back(Pair("hex", hex));
3515c101 7188 } else ERR_RESULT("couldnt gatewaysclaim");
65a961ff 7189 return(result);
7190}
7191
3515c101 7192UniValue gatewayswithdraw(const UniValue& params, bool fHelp)
587e715d 7193{
3f4351c9 7194 UniValue result(UniValue::VOBJ); uint256 bindtxid; int64_t amount; std::string hex,coin; std::vector<uint8_t> withdrawpub;
9d860bd9 7195 if ( fHelp || params.size() != 4 )
3f4351c9 7196 throw runtime_error("gatewayswithdraw bindtxid coin withdrawpub amount\n");
587e715d 7197 if ( ensure_CCrequirements() < 0 )
7198 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
3f4351c9 7199 bindtxid = Parseuint256((char *)params[0].get_str().c_str());
7200 coin = params[1].get_str();
7201 withdrawpub = ParseHex(params[2].get_str());
7202 amount = atof((char *)params[3].get_str().c_str()) * COIN;
7203 hex = GatewaysWithdraw(0,bindtxid,coin,withdrawpub,amount);
587e715d 7204 if ( hex.size() > 0 )
7205 {
7206 result.push_back(Pair("result", "success"));
7207 result.push_back(Pair("hex", hex));
3515c101 7208 } else ERR_RESULT("couldnt gatewayswithdraw");
587e715d 7209 return(result);
7210}
7211
6bde696a 7212UniValue gatewaysmarkdone(const UniValue& params, bool fHelp)
65a961ff 7213{
6bde696a 7214 UniValue result(UniValue::VOBJ); uint256 withdrawtxid; std::string hex;
7215 if ( fHelp || params.size() != 1 )
7216 throw runtime_error("gatewaysmarkdone withdrawtxid\n");
e10def86 7217 if ( ensure_CCrequirements() < 0 )
7218 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
6bde696a 7219 withdrawtxid = Parseuint256((char *)params[0].get_str().c_str());
7220 hex = GatewaysMarkdone(0,withdrawtxid);
65a961ff 7221 if ( hex.size() > 0 )
7222 {
7223 result.push_back(Pair("result", "success"));
7224 result.push_back(Pair("hex", hex));
6bde696a 7225 } else ERR_RESULT("couldnt gatewaysmarkdone");
65a961ff 7226 return(result);
7227}
7228
5955955d 7229UniValue gatewayspending(const UniValue& params, bool fHelp)
fdd22810 7230{
5955955d 7231 uint256 bindtxid; std::string coin;
7232 if ( fHelp || params.size() != 2 )
7233 throw runtime_error("gatewayspending bindtxid coin\n");
fdd22810 7234 if ( ensure_CCrequirements() < 0 )
7235 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5955955d 7236 bindtxid = Parseuint256((char *)params[0].get_str().c_str());
7237 coin = params[1].get_str();
7238 return(GatewaysPendingWithdraws(bindtxid,coin));
fdd22810 7239}
7240
366625ca 7241UniValue oracleslist(const UniValue& params, bool fHelp)
fdd22810 7242{
366625ca 7243 if ( fHelp || params.size() > 0 )
7244 throw runtime_error("oracleslist\n");
fdd22810 7245 if ( ensure_CCrequirements() < 0 )
7246 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
366625ca 7247 return(OraclesList());
fdd22810 7248}
7249
366625ca 7250UniValue oraclesinfo(const UniValue& params, bool fHelp)
c66eb36d 7251{
366625ca 7252 uint256 txid;
7253 if ( fHelp || params.size() != 1 )
7254 throw runtime_error("oraclesinfo oracletxid\n");
c66eb36d 7255 if ( ensure_CCrequirements() < 0 )
7256 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
366625ca 7257 txid = Parseuint256((char *)params[0].get_str().c_str());
7258 return(OracleInfo(txid));
7259}
7260
7261UniValue oraclesregister(const UniValue& params, bool fHelp)
7262{
3d6ee3e0 7263 UniValue result(UniValue::VOBJ); uint256 txid; int64_t datafee; std::string hex;
366625ca 7264 if ( fHelp || params.size() != 2 )
7265 throw runtime_error("oraclesregister oracletxid datafee\n");
7266 if ( ensure_CCrequirements() < 0 )
7267 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7268 txid = Parseuint256((char *)params[0].get_str().c_str());
7269 datafee = atol((char *)params[1].get_str().c_str());
7270 hex = OracleRegister(0,txid,datafee);
7271 if ( hex.size() > 0 )
7272 {
7273 result.push_back(Pair("result", "success"));
7274 result.push_back(Pair("hex", hex));
7275 } else ERR_RESULT("couldnt register with oracle txid");
7276 return(result);
7277}
7278
7279UniValue oraclessubscribe(const UniValue& params, bool fHelp)
7280{
3d6ee3e0 7281 UniValue result(UniValue::VOBJ); uint256 txid; int64_t amount; std::string hex; std::vector<unsigned char> pubkey;
366625ca 7282 if ( fHelp || params.size() != 3 )
d95908b8 7283 throw runtime_error("oraclessubscribe oracletxid publisher amount\n");
366625ca 7284 if ( ensure_CCrequirements() < 0 )
7285 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7286 txid = Parseuint256((char *)params[0].get_str().c_str());
7287 pubkey = ParseHex(params[1].get_str().c_str());
d95908b8 7288 amount = atof((char *)params[2].get_str().c_str()) * COIN;
366625ca 7289 hex = OracleSubscribe(0,txid,pubkey2pk(pubkey),amount);
7290 if ( hex.size() > 0 )
7291 {
7292 result.push_back(Pair("result", "success"));
7293 result.push_back(Pair("hex", hex));
26ca942e 7294 } else ERR_RESULT("couldnt subscribe with oracle txid");
7295 return(result);
7296}
7297
7298UniValue oraclessamples(const UniValue& params, bool fHelp)
7299{
a82dd70f 7300 UniValue result(UniValue::VOBJ); uint256 txid,batontxid; int32_t num;
26ca942e 7301 if ( fHelp || params.size() != 3 )
7302 throw runtime_error("oraclessamples oracletxid batonutxo num\n");
7303 if ( ensure_CCrequirements() < 0 )
7304 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7305 txid = Parseuint256((char *)params[0].get_str().c_str());
7306 batontxid = Parseuint256((char *)params[1].get_str().c_str());
7307 num = atoi((char *)params[2].get_str().c_str());
a82dd70f 7308 return(OracleDataSamples(txid,batontxid,num));
366625ca 7309}
7310
7311UniValue oraclesdata(const UniValue& params, bool fHelp)
7312{
3d6ee3e0 7313 UniValue result(UniValue::VOBJ); uint256 txid; std::vector<unsigned char> data; std::string hex;
366625ca 7314 if ( fHelp || params.size() != 2 )
7315 throw runtime_error("oraclesdata oracletxid hexstr\n");
7316 if ( ensure_CCrequirements() < 0 )
7317 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7318 txid = Parseuint256((char *)params[0].get_str().c_str());
7319 data = ParseHex(params[1].get_str().c_str());
7320 hex = OracleData(0,txid,data);
7321 if ( hex.size() > 0 )
7322 {
7323 result.push_back(Pair("result", "success"));
7324 result.push_back(Pair("hex", hex));
7325 } else ERR_RESULT("couldnt publish data with oracle txid");
7326 return(result);
7327}
7328
7329UniValue oraclescreate(const UniValue& params, bool fHelp)
7330{
7331 UniValue result(UniValue::VOBJ); std::string name,description,format,hex;
7332 if ( fHelp || params.size() != 3 )
7333 throw runtime_error("oraclescreate name description format\n");
7334 if ( ensure_CCrequirements() < 0 )
7335 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7336 const CKeyStore& keystore = *pwalletMain;
7337 LOCK2(cs_main, pwalletMain->cs_wallet);
7338 name = params[0].get_str();
7339 if ( name.size() == 0 || name.size() > 32)
7340 {
7341 ERR_RESULT("oracles name must not be empty and up to 32 characters");
7342 return(result);
7343 }
7344 description = params[1].get_str();
7345 if ( description.size() > 4096 )
7346 {
7347 ERR_RESULT("oracles description must be <= 4096 characters");
7348 return(result);
7349 }
7350 format = params[2].get_str();
7351 if ( format.size() > 4096 )
7352 {
7353 ERR_RESULT("oracles format must be <= 4096 characters");
7354 return(result);
7355 }
7356 hex = OracleCreate(0,name,description,format);
7357 if ( hex.size() > 0 )
7358 {
7359 result.push_back(Pair("result", "success"));
7360 result.push_back(Pair("hex", hex));
7361 } else ERR_RESULT("couldnt create oracle");
7362 return(result);
7363}
7364
7137a022 7365UniValue FSMcreate(const UniValue& params, bool fHelp)
7366{
7367 UniValue result(UniValue::VOBJ); std::string name,states,hex;
7368 if ( fHelp || params.size() != 2 )
7369 throw runtime_error("FSMcreate name states\n");
7370 if ( ensure_CCrequirements() < 0 )
7371 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7372 const CKeyStore& keystore = *pwalletMain;
7373 LOCK2(cs_main, pwalletMain->cs_wallet);
7374 name = params[0].get_str();
7375 states = params[1].get_str();
d9cf43a5 7376 hex = FSMCreate(0,name,states);
7137a022 7377 if ( hex.size() > 0 )
7378 {
7379 result.push_back(Pair("result", "success"));
7380 result.push_back(Pair("hex", hex));
7381 } else result.push_back(Pair("error", "couldnt create FSM transaction"));
7382 return(result);
7383}
7384
7385UniValue FSMlist(const UniValue& params, bool fHelp)
7386{
7387 uint256 tokenid;
7388 if ( fHelp || params.size() > 0 )
7389 throw runtime_error("FSMlist\n");
7390 if ( ensure_CCrequirements() < 0 )
7391 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7392 return(FSMList());
7393}
7394
7395UniValue FSMinfo(const UniValue& params, bool fHelp)
7396{
7397 uint256 FSMtxid;
7398 if ( fHelp || params.size() != 1 )
7399 throw runtime_error("FSMinfo fundingtxid\n");
7400 if ( ensure_CCrequirements() < 0 )
7401 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
d9cf43a5 7402 FSMtxid = Parseuint256((char *)params[0].get_str().c_str());
7137a022 7403 return(FSMInfo(FSMtxid));
7404}
7405
4608d170 7406UniValue faucetinfo(const UniValue& params, bool fHelp)
7407{
7408 uint256 fundingtxid;
7409 if ( fHelp || params.size() != 0 )
7410 throw runtime_error("faucetinfo\n");
7411 if ( ensure_CCrequirements() < 0 )
7412 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7413 return(FaucetInfo());
7414}
7415
cfea7a46 7416UniValue faucetfund(const UniValue& params, bool fHelp)
6ff08712 7417{
2098a4c9 7418 UniValue result(UniValue::VOBJ); int64_t funds; std::string hex;
6ff08712 7419 if ( fHelp || params.size() > 1 )
cfea7a46 7420 throw runtime_error("faucetfund amount\n");
6ff08712 7421 if ( ensure_CCrequirements() < 0 )
7422 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7423 const CKeyStore& keystore = *pwalletMain;
7424 LOCK2(cs_main, pwalletMain->cs_wallet);
cfea7a46 7425 funds = atof(params[0].get_str().c_str()) * COIN;
700c1fcf 7426 if (funds > 0) {
2098a4c9 7427 hex = FaucetFund(0,(uint64_t) funds);
700c1fcf
JDL
7428 if ( hex.size() > 0 )
7429 {
7430 result.push_back(Pair("result", "success"));
7431 result.push_back(Pair("hex", hex));
8a3e1884
JDL
7432 } else ERR_RESULT("couldnt create faucet funding transaction");
7433 } else ERR_RESULT( "funding amount must be positive");
6ff08712 7434 return(result);
7435}
7436
cfea7a46 7437UniValue faucetget(const UniValue& params, bool fHelp)
7438{
7439 UniValue result(UniValue::VOBJ); std::string hex;
7440 if ( fHelp || params.size() > 0 )
7441 throw runtime_error("faucetget\n");
7442 if ( ensure_CCrequirements() < 0 )
7443 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7444 const CKeyStore& keystore = *pwalletMain;
7445 LOCK2(cs_main, pwalletMain->cs_wallet);
cfea7a46 7446 hex = FaucetGet(0);
8e0ff2b7 7447 if ( hex.size() > 0 ) {
cfea7a46 7448 result.push_back(Pair("result", "success"));
7449 result.push_back(Pair("hex", hex));
8a3e1884 7450 } else ERR_RESULT("couldnt create faucet get transaction");
cfea7a46 7451 return(result);
7452}
7453
7454UniValue dicefund(const UniValue& params, bool fHelp)
65a961ff 7455{
9025093e 7456 UniValue result(UniValue::VOBJ); int64_t funds,minbet,maxbet,maxodds,timeoutblocks; std::string hex; char *name;
5bd03ad7 7457 if ( fHelp || params.size() != 6 )
9025093e 7458 throw runtime_error("dicefund name funds minbet maxbet maxodds timeoutblocks\n");
e10def86 7459 if ( ensure_CCrequirements() < 0 )
7460 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7461 const CKeyStore& keystore = *pwalletMain;
7462 LOCK2(cs_main, pwalletMain->cs_wallet);
5bd03ad7 7463 name = (char *)params[0].get_str().c_str();
7464 funds = atof(params[1].get_str().c_str()) * COIN;
7465 minbet = atof(params[2].get_str().c_str()) * COIN;
7466 maxbet = atof(params[3].get_str().c_str()) * COIN;
7467 maxodds = atol(params[4].get_str().c_str());
9025093e 7468 timeoutblocks = atol(params[5].get_str().c_str());
124819ce
JDL
7469
7470 if (!VALID_PLAN_NAME(name)) {
7471 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
7472 return(result);
7473 }
7474
9025093e 7475 hex = DiceCreateFunding(0,name,funds,minbet,maxbet,maxodds,timeoutblocks);
8e0ff2b7 7476 if (CCerror != "") {
8a3e1884 7477 ERR_RESULT(CCerror);
8e0ff2b7 7478 } else if ( hex.size() > 0 ) {
65a961ff 7479 result.push_back(Pair("result", "success"));
7480 result.push_back(Pair("hex", hex));
8e0ff2b7 7481 } else {
8a3e1884 7482 ERR_RESULT( "couldnt create dice funding transaction");
8e0ff2b7 7483 }
65a961ff 7484 return(result);
7485}
7486
587e715d 7487UniValue diceaddfunds(const UniValue& params, bool fHelp)
7488{
8e0ff2b7 7489 UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid; int64_t amount; std::string hex;
587e715d 7490 if ( fHelp || params.size() != 3 )
7491 throw runtime_error("diceaddfunds name fundingtxid amount\n");
7492 if ( ensure_CCrequirements() < 0 )
7493 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7494 const CKeyStore& keystore = *pwalletMain;
7495 LOCK2(cs_main, pwalletMain->cs_wallet);
587e715d 7496 name = (char *)params[0].get_str().c_str();
7497 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
7498 amount = atof(params[2].get_str().c_str()) * COIN;
124819ce
JDL
7499 if (!VALID_PLAN_NAME(name)) {
7500 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
7501 return(result);
7502 }
8e0ff2b7
JDL
7503 if ( amount > 0 ) {
7504 hex = DiceAddfunding(0,name,fundingtxid,amount);
7505 if (CCerror != "") {
8a3e1884 7506 ERR_RESULT(CCerror);
8e0ff2b7
JDL
7507 } else if ( hex.size() > 0 ) {
7508 result.push_back(Pair("result", "success"));
7509 result.push_back(Pair("hex", hex));
8a3e1884
JDL
7510 } else ERR_RESULT("couldnt create dice addfunding transaction");
7511 } else ERR_RESULT("amount must be positive");
587e715d 7512 return(result);
7513}
7514
cfea7a46 7515UniValue dicebet(const UniValue& params, bool fHelp)
65a961ff 7516{
8e0ff2b7 7517 UniValue result(UniValue::VOBJ); std::string hex; uint256 fundingtxid; int64_t amount,odds; char *name;
135ead85 7518 if ( fHelp || params.size() != 4 )
7d821112 7519 throw runtime_error("dicebet name fundingtxid amount odds\n");
e10def86 7520 if ( ensure_CCrequirements() < 0 )
7521 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7522 const CKeyStore& keystore = *pwalletMain;
7523 LOCK2(cs_main, pwalletMain->cs_wallet);
7d821112 7524 name = (char *)params[0].get_str().c_str();
7525 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
7526 amount = atof(params[2].get_str().c_str()) * COIN;
7527 odds = atol(params[3].get_str().c_str());
124819ce
JDL
7528
7529 if (!VALID_PLAN_NAME(name)) {
7530 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
7531 return(result);
7532 }
8e0ff2b7
JDL
7533 if (amount > 0 && odds > 0) {
7534 hex = DiceBet(0,name,fundingtxid,amount,odds);
7535 if ( hex.size() > 0 )
7536 {
7537 result.push_back(Pair("result", "success"));
7538 result.push_back(Pair("hex", hex));
eb4cf14d 7539 } else ERR_RESULT("couldnt create dice bet transaction. make sure your address has funds");
8e0ff2b7
JDL
7540 } else {
7541 ERR_RESULT("amount and odds must be positive");
7542 }
65a961ff 7543 return(result);
7544}
7545
7e988759 7546UniValue dicefinish(const UniValue& params, bool fHelp)
5d3d3a87 7547{
8e0ff2b7 7548 UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid,bettxid; std::string hex; int32_t r;
5d3d3a87 7549 if ( fHelp || params.size() != 3 )
7e988759 7550 throw runtime_error("dicefinish name fundingtxid bettxid\n");
5d3d3a87 7551 if ( ensure_CCrequirements() < 0 )
7552 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7553 const CKeyStore& keystore = *pwalletMain;
7554 LOCK2(cs_main, pwalletMain->cs_wallet);
5d3d3a87 7555 name = (char *)params[0].get_str().c_str();
124819ce
JDL
7556 if (!VALID_PLAN_NAME(name)) {
7557 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
7558 return(result);
7559 }
5d3d3a87 7560 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
7561 bettxid = Parseuint256((char *)params[2].get_str().c_str());
7e988759 7562 hex = DiceBetFinish(&r,0,name,fundingtxid,bettxid,1);
a03146b3
JDL
7563 if ( CCerror != "" )
7564 {
7565 ERR_RESULT(CCerror);
7566 } else if ( hex.size() > 0 )
5d3d3a87 7567 {
7568 result.push_back(Pair("result", "success"));
7569 result.push_back(Pair("hex", hex));
8a3e1884 7570 } else ERR_RESULT( "couldnt create dicefinish transaction");
5d3d3a87 7571 return(result);
7572}
7573
7e988759 7574UniValue dicestatus(const UniValue& params, bool fHelp)
5d3d3a87 7575{
8e0ff2b7 7576 UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid,bettxid; std::string status; double winnings;
7b44d4c1 7577 if ( fHelp || (params.size() != 2 && params.size() != 3) )
7e988759 7578 throw runtime_error("dicestatus name fundingtxid bettxid\n");
544593c6 7579 if ( ensure_CCrequirements() < 0 )
7580 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7581 const CKeyStore& keystore = *pwalletMain;
7582 LOCK2(cs_main, pwalletMain->cs_wallet);
544593c6 7583 name = (char *)params[0].get_str().c_str();
124819ce
JDL
7584 if (!VALID_PLAN_NAME(name)) {
7585 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
7586 return(result);
7587 }
544593c6 7588 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
75dbd478 7589 memset(&bettxid,0,sizeof(bettxid));
7590 if ( params.size() == 3 )
7591 bettxid = Parseuint256((char *)params[2].get_str().c_str());
4e525e48 7592 winnings = DiceStatus(0,name,fundingtxid,bettxid);
a03146b3
JDL
7593 if (CCerror != "") {
7594 ERR_RESULT(CCerror);
7595 return result;
7596 }
7e988759 7597 result.push_back(Pair("result", "success"));
d74d791a 7598 if ( winnings >= 0. )
544593c6 7599 {
d74d791a 7600 if ( winnings > 0. )
7601 {
096cfeb8 7602 if ( params.size() == 3 )
7603 {
7604 result.push_back(Pair("status", "win"));
7605 result.push_back(Pair("won", winnings));
7606 }
7607 else
7608 {
7609 result.push_back(Pair("status", "finalized"));
7610 result.push_back(Pair("n", (int64_t)winnings));
7611 }
3bb6e233 7612 }
7613 else
7614 {
7615 if ( params.size() == 3 )
7616 result.push_back(Pair("status", "loss"));
7617 else result.push_back(Pair("status", "no pending bets"));
7618 }
6ca2e998 7619 } else result.push_back(Pair("status", "bet still pending"));
544593c6 7620 return(result);
7621}
7622
c857567a 7623UniValue dicelist(const UniValue& params, bool fHelp)
fdd22810 7624{
7625 uint256 tokenid;
7626 if ( fHelp || params.size() > 0 )
c857567a 7627 throw runtime_error("dicelist\n");
fdd22810 7628 if ( ensure_CCrequirements() < 0 )
7629 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
c857567a 7630 return(DiceList());
fdd22810 7631}
7632
c857567a 7633UniValue diceinfo(const UniValue& params, bool fHelp)
fdd22810 7634{
7635 uint256 fundingtxid;
7636 if ( fHelp || params.size() != 1 )
c857567a 7637 throw runtime_error("diceinfo fundingtxid\n");
fdd22810 7638 if ( ensure_CCrequirements() < 0 )
7639 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7640 fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
c857567a 7641 return(DiceInfo(fundingtxid));
fdd22810 7642}
7643
c66eb36d 7644UniValue tokenlist(const UniValue& params, bool fHelp)
7645{
7646 uint256 tokenid;
7647 if ( fHelp || params.size() > 0 )
7648 throw runtime_error("tokenlist\n");
7649 if ( ensure_CCrequirements() < 0 )
7650 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7651 return(AssetList());
7652}
7653
7654UniValue tokeninfo(const UniValue& params, bool fHelp)
7655{
7656 uint256 tokenid;
7657 if ( fHelp || params.size() != 1 )
7658 throw runtime_error("tokeninfo tokenid\n");
7659 if ( ensure_CCrequirements() < 0 )
7660 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
7661 tokenid = Parseuint256((char *)params[0].get_str().c_str());
7662 return(AssetInfo(tokenid));
7663}
7664
143488c8 7665UniValue tokenorders(const UniValue& params, bool fHelp)
7666{
7667 uint256 tokenid;
7668 if ( fHelp || params.size() > 1 )
7669 throw runtime_error("tokenorders [tokenid]\n");
e10def86 7670 if ( ensure_CCrequirements() < 0 )
7671 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
143488c8 7672 if ( params.size() == 1 )
7673 tokenid = Parseuint256((char *)params[0].get_str().c_str());
7674 else memset(&tokenid,0,sizeof(tokenid));
7675 return(AssetOrders(tokenid));
7676}
7677
7678UniValue tokenbalance(const UniValue& params, bool fHelp)
7679{
e04b5c08 7680 UniValue result(UniValue::VOBJ); char destaddr[64]; uint256 tokenid; uint64_t balance; std::vector<unsigned char> pubkey; struct CCcontract_info *cp,C;
7681 cp = CCinit(&C,EVAL_ASSETS);
143488c8 7682 if ( fHelp || params.size() > 2 )
7683 throw runtime_error("tokenbalance tokenid [pubkey]\n");
e10def86 7684 if ( ensure_CCrequirements() < 0 )
7685 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7686 LOCK(cs_main);
143488c8 7687 tokenid = Parseuint256((char *)params[0].get_str().c_str());
7688 if ( params.size() == 2 )
7689 pubkey = ParseHex(params[1].get_str().c_str());
7690 else pubkey = Mypubkey();
7691 result.push_back(Pair("result", "success"));
e04b5c08 7692 if ( GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0 )
143488c8 7693 result.push_back(Pair("CCaddress",destaddr));
bb0c5133 7694 balance = GetAssetBalance(pubkey2pk(pubkey),tokenid);
143488c8 7695 result.push_back(Pair("tokenid", params[0].get_str()));
7696 result.push_back(Pair("balance", (int64_t)balance));
7697 return(result);
7698}
7699
1a02fde9 7700UniValue tokencreate(const UniValue& params, bool fHelp)
7701{
7702 UniValue result(UniValue::VOBJ); std::string name,description,hex; uint64_t supply;
7703 if ( fHelp || params.size() > 3 || params.size() < 2 )
9a579b30 7704 throw runtime_error("tokencreate name supply description\n");
e10def86 7705 if ( ensure_CCrequirements() < 0 )
7706 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7707 const CKeyStore& keystore = *pwalletMain;
7708 LOCK2(cs_main, pwalletMain->cs_wallet);
246ea3c3 7709 name = params[0].get_str();
1a02fde9 7710 supply = atof(params[1].get_str().c_str()) * COIN;
124819ce 7711 if ( name.size() == 0 || name.size() > 32)
4d47fcb9 7712 {
124819ce
JDL
7713 ERR_RESULT("Token name must not be empty and up to 32 characters");
7714 return(result);
7715 }
7716 if ( supply <= 0 )
7717 {
7718 ERR_RESULT("Token supply must be positive");
4d47fcb9 7719 return(result);
7720 }
1a02fde9 7721 if ( params.size() == 3 )
6ca2e998 7722 {
1a02fde9 7723 description = params[2].get_str();
6ca2e998 7724 if ( description.size() > 4096 )
7725 {
124819ce 7726 ERR_RESULT("Token description must be <= 4096 characters");
6ca2e998 7727 return(result);
7728 }
7729 }
5963c84f 7730 hex = CreateAsset(0,supply,name,description);
1a02fde9 7731 if ( hex.size() > 0 )
7732 {
7733 result.push_back(Pair("result", "success"));
7734 result.push_back(Pair("hex", hex));
8a3e1884 7735 } else ERR_RESULT("couldnt create transaction");
246ea3c3 7736 return(result);
1a02fde9 7737}
7738
7739UniValue tokentransfer(const UniValue& params, bool fHelp)
7740{
8e0ff2b7 7741 UniValue result(UniValue::VOBJ); std::string hex; int64_t amount; uint256 tokenid;
e51e9274 7742 if ( fHelp || params.size() != 3 )
7743 throw runtime_error("tokentransfer tokenid destpubkey amount\n");
e10def86 7744 if ( ensure_CCrequirements() < 0 )
7745 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7746 const CKeyStore& keystore = *pwalletMain;
7747 LOCK2(cs_main, pwalletMain->cs_wallet);
e51e9274 7748 tokenid = Parseuint256((char *)params[0].get_str().c_str());
7749 std::vector<unsigned char> pubkey(ParseHex(params[1].get_str().c_str()));
7750 amount = atol(params[2].get_str().c_str());
124819ce 7751 if ( tokenid == zeroid )
e51e9274 7752 {
124819ce
JDL
7753 ERR_RESULT("invalid tokenid");
7754 return(result);
7755 }
7756 if ( amount <= 0 )
7757 {
7758 ERR_RESULT("amount must be positive");
f6160f58 7759 return(result);
7760 }
e51e9274 7761 hex = AssetTransfer(0,tokenid,pubkey,amount);
8e0ff2b7
JDL
7762 if (amount > 0) {
7763 if ( hex.size() > 0 )
7764 {
7765 result.push_back(Pair("result", "success"));
7766 result.push_back(Pair("hex", hex));
8a3e1884 7767 } else ERR_RESULT("couldnt transfer assets");
8e0ff2b7
JDL
7768 } else {
7769 ERR_RESULT("amount must be positive");
7770 }
1a02fde9 7771 return(result);
7772}
7773
7774UniValue tokenbid(const UniValue& params, bool fHelp)
7775{
8e0ff2b7 7776 UniValue result(UniValue::VOBJ); int64_t bidamount,numtokens; std::string hex; double price; uint256 tokenid;
5963c84f 7777 if ( fHelp || params.size() != 3 )
7778 throw runtime_error("tokenbid numtokens tokenid price\n");
e10def86 7779 if ( ensure_CCrequirements() < 0 )
7780 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7781 const CKeyStore& keystore = *pwalletMain;
7782 LOCK2(cs_main, pwalletMain->cs_wallet);
5963c84f 7783 numtokens = atoi(params[0].get_str().c_str());
6a530006 7784 tokenid = Parseuint256((char *)params[1].get_str().c_str());
5963c84f 7785 price = atof(params[2].get_str().c_str());
93e02ad9 7786 bidamount = (price * numtokens) * COIN + 0.0000000049999;
124819ce 7787 if ( price <= 0 )
5963c84f 7788 {
124819ce
JDL
7789 ERR_RESULT("price must be positive");
7790 return(result);
7791 }
7792 if ( tokenid == zeroid )
7793 {
7794 ERR_RESULT("invalid tokenid");
7795 return(result);
7796 }
7797 if ( bidamount <= 0 )
7798 {
7799 ERR_RESULT("bid amount must be positive");
f6160f58 7800 return(result);
7801 }
5963c84f 7802 hex = CreateBuyOffer(0,bidamount,tokenid,numtokens);
8e0ff2b7
JDL
7803 if (price > 0 && numtokens > 0) {
7804 if ( hex.size() > 0 )
7805 {
7806 result.push_back(Pair("result", "success"));
7807 result.push_back(Pair("hex", hex));
124819ce 7808 } else ERR_RESULT("couldnt create bid");
8e0ff2b7
JDL
7809 } else {
7810 ERR_RESULT("price and numtokens must be positive");
7811 }
1a02fde9 7812 return(result);
7813}
7814
7815UniValue tokencancelbid(const UniValue& params, bool fHelp)
7816{
437d6328 7817 UniValue result(UniValue::VOBJ); std::string hex; int32_t i; uint256 tokenid,bidtxid;
7818 if ( fHelp || params.size() != 2 )
7819 throw runtime_error("tokencancelbid tokenid bidtxid\n");
e10def86 7820 if ( ensure_CCrequirements() < 0 )
7821 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7822 const CKeyStore& keystore = *pwalletMain;
7823 LOCK2(cs_main, pwalletMain->cs_wallet);
437d6328 7824 tokenid = Parseuint256((char *)params[0].get_str().c_str());
7825 bidtxid = Parseuint256((char *)params[1].get_str().c_str());
f6160f58 7826 if ( tokenid == zeroid || bidtxid == zeroid )
7827 {
7828 result.push_back(Pair("error", "invalid parameter"));
7829 return(result);
7830 }
437d6328 7831 hex = CancelBuyOffer(0,tokenid,bidtxid);
cf610814 7832 if ( hex.size() > 0 )
7833 {
7834 result.push_back(Pair("result", "success"));
7835 result.push_back(Pair("hex", hex));
8a3e1884 7836 } else ERR_RESULT("couldnt cancel bid");
1a02fde9 7837 return(result);
7838}
7839
7840UniValue tokenfillbid(const UniValue& params, bool fHelp)
7841{
a03146b3 7842 UniValue result(UniValue::VOBJ); int64_t fillamount; std::string hex; uint256 tokenid,bidtxid;
143488c8 7843 if ( fHelp || params.size() != 3 )
7844 throw runtime_error("tokenfillbid tokenid bidtxid fillamount\n");
e10def86 7845 if ( ensure_CCrequirements() < 0 )
7846 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7847 const CKeyStore& keystore = *pwalletMain;
7848 LOCK2(cs_main, pwalletMain->cs_wallet);
143488c8 7849 tokenid = Parseuint256((char *)params[0].get_str().c_str());
7850 bidtxid = Parseuint256((char *)params[1].get_str().c_str());
7851 fillamount = atol(params[2].get_str().c_str());
a03146b3 7852 if ( fillamount <= 0 )
f6160f58 7853 {
a03146b3
JDL
7854 ERR_RESULT("fillamount must be positive");
7855 return(result);
7856 }
7857 if ( tokenid == zeroid || bidtxid == zeroid )
7858 {
7859 ERR_RESULT("must provide tokenid and bidtxid");
f6160f58 7860 return(result);
7861 }
143488c8 7862 hex = FillBuyOffer(0,tokenid,bidtxid,fillamount);
7863 if ( hex.size() > 0 )
7864 {
7865 result.push_back(Pair("result", "success"));
7866 result.push_back(Pair("hex", hex));
8a3e1884 7867 } else ERR_RESULT("couldnt fill bid");
143488c8 7868 return(result);
7869}
7870
7871UniValue tokenask(const UniValue& params, bool fHelp)
7872{
8e0ff2b7 7873 UniValue result(UniValue::VOBJ); int64_t askamount,numtokens; std::string hex; double price; uint256 tokenid;
143488c8 7874 if ( fHelp || params.size() != 3 )
7875 throw runtime_error("tokenask numtokens tokenid price\n");
e10def86 7876 if ( ensure_CCrequirements() < 0 )
7877 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7878 const CKeyStore& keystore = *pwalletMain;
7879 LOCK2(cs_main, pwalletMain->cs_wallet);
143488c8 7880 numtokens = atoi(params[0].get_str().c_str());
7881 tokenid = Parseuint256((char *)params[1].get_str().c_str());
7882 price = atof(params[2].get_str().c_str());
7883 askamount = (price * numtokens) * COIN + 0.0000000049999;
f6160f58 7884 if ( tokenid == zeroid || numtokens <= 0 || price <= 0 || askamount <= 0 )
143488c8 7885 {
a03146b3 7886 ERR_RESULT("invalid parameter");
f6160f58 7887 return(result);
7888 }
fff7c5d2 7889 hex = CreateSell(0,numtokens,tokenid,askamount);
8e0ff2b7
JDL
7890 if (price > 0 && numtokens > 0) {
7891 if ( hex.size() > 0 )
7892 {
7893 result.push_back(Pair("result", "success"));
7894 result.push_back(Pair("hex", hex));
8a3e1884 7895 } else ERR_RESULT("couldnt create ask");
8e0ff2b7
JDL
7896 } else {
7897 ERR_RESULT("price and numtokens must be positive");
7898 }
143488c8 7899 return(result);
7900}
7901
7902UniValue tokenswapask(const UniValue& params, bool fHelp)
7903{
7904 static uint256 zeroid;
8e0ff2b7 7905 UniValue result(UniValue::VOBJ); int64_t askamount,numtokens; std::string hex; double price; uint256 tokenid,otherid;
e78fa189 7906 if ( fHelp || params.size() != 4 )
c0198c14 7907 throw runtime_error("tokenswapask numtokens tokenid otherid price\n");
e10def86 7908 if ( ensure_CCrequirements() < 0 )
7909 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7910 const CKeyStore& keystore = *pwalletMain;
7911 LOCK2(cs_main, pwalletMain->cs_wallet);
143488c8 7912 numtokens = atoi(params[0].get_str().c_str());
7913 tokenid = Parseuint256((char *)params[1].get_str().c_str());
7914 otherid = Parseuint256((char *)params[2].get_str().c_str());
7915 price = atof(params[3].get_str().c_str());
fff7c5d2 7916 askamount = (price * numtokens);
7917 hex = CreateSwap(0,numtokens,tokenid,otherid,askamount);
8e0ff2b7
JDL
7918 if (price > 0 && numtokens > 0) {
7919 if ( hex.size() > 0 )
7920 {
7921 result.push_back(Pair("result", "success"));
7922 result.push_back(Pair("hex", hex));
8a3e1884 7923 } else ERR_RESULT("couldnt create swap");
8e0ff2b7
JDL
7924 } else {
7925 ERR_RESULT("price and numtokens must be positive");
7926 }
143488c8 7927 return(result);
7928}
7929
7930UniValue tokencancelask(const UniValue& params, bool fHelp)
7931{
ef2c8deb 7932 UniValue result(UniValue::VOBJ); std::string hex; int32_t i; uint256 tokenid,asktxid;
143488c8 7933 if ( fHelp || params.size() != 2 )
7934 throw runtime_error("tokencancelask tokenid asktxid\n");
e10def86 7935 if ( ensure_CCrequirements() < 0 )
7936 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7937 const CKeyStore& keystore = *pwalletMain;
7938 LOCK2(cs_main, pwalletMain->cs_wallet);
09c7f7cc 7939 tokenid = Parseuint256((char *)params[0].get_str().c_str());
14708917 7940 asktxid = Parseuint256((char *)params[1].get_str().c_str());
f6160f58 7941 if ( tokenid == zeroid || asktxid == zeroid )
7942 {
7943 result.push_back(Pair("error", "invalid parameter"));
7944 return(result);
7945 }
143488c8 7946 hex = CancelSell(0,tokenid,asktxid);
7947 if ( hex.size() > 0 )
7948 {
7949 result.push_back(Pair("result", "success"));
7950 result.push_back(Pair("hex", hex));
e4f4e63b 7951 } else ERR_RESULT("couldnt cancel ask");
143488c8 7952 return(result);
7953}
7954
7955UniValue tokenfillask(const UniValue& params, bool fHelp)
7956{
a03146b3 7957 UniValue result(UniValue::VOBJ); int64_t fillunits; std::string hex; uint256 tokenid,asktxid;
143488c8 7958 if ( fHelp || params.size() != 3 )
ba8a98f2 7959 throw runtime_error("tokenfillask tokenid asktxid fillunits\n");
e10def86 7960 if ( ensure_CCrequirements() < 0 )
7961 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 7962 const CKeyStore& keystore = *pwalletMain;
7963 LOCK2(cs_main, pwalletMain->cs_wallet);
143488c8 7964 tokenid = Parseuint256((char *)params[0].get_str().c_str());
7965 asktxid = Parseuint256((char *)params[1].get_str().c_str());
ba8a98f2 7966 fillunits = atol(params[2].get_str().c_str());
a03146b3 7967 if ( fillunits <= 0 )
143488c8 7968 {
a03146b3
JDL
7969 ERR_RESULT("fillunits must be positive");
7970 return(result);
7971 }
7972 if ( tokenid == zeroid || asktxid == zeroid )
f6160f58 7973 {
7974 result.push_back(Pair("error", "invalid parameter"));
7975 return(result);
7976 }
ba8a98f2 7977 hex = FillSell(0,tokenid,zeroid,asktxid,fillunits);
8e0ff2b7 7978 if (fillunits > 0) {
8a3e1884
JDL
7979 if (CCerror != "") {
7980 ERR_RESULT(CCerror);
7981 } else if ( hex.size() > 0) {
8e0ff2b7
JDL
7982 result.push_back(Pair("result", "success"));
7983 result.push_back(Pair("hex", hex));
8a3e1884
JDL
7984 } else {
7985 ERR_RESULT("couldnt fill bid");
7986 }
8e0ff2b7
JDL
7987 } else {
7988 ERR_RESULT("fillunits must be positive");
7989 }
143488c8 7990 return(result);
7991}
7992
7993UniValue tokenfillswap(const UniValue& params, bool fHelp)
7994{
7995 static uint256 zeroid;
8e0ff2b7 7996 UniValue result(UniValue::VOBJ); int64_t fillunits; std::string hex; uint256 tokenid,otherid,asktxid;
143488c8 7997 if ( fHelp || params.size() != 4 )
ba8a98f2 7998 throw runtime_error("tokenfillswap tokenid otherid asktxid fillunits\n");
e10def86 7999 if ( ensure_CCrequirements() < 0 )
8000 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 8001 const CKeyStore& keystore = *pwalletMain;
8002 LOCK2(cs_main, pwalletMain->cs_wallet);
143488c8 8003 tokenid = Parseuint256((char *)params[0].get_str().c_str());
8004 otherid = Parseuint256((char *)params[1].get_str().c_str());
8005 asktxid = Parseuint256((char *)params[2].get_str().c_str());
ba8a98f2 8006 fillunits = atol(params[3].get_str().c_str());
8007 hex = FillSell(0,tokenid,otherid,asktxid,fillunits);
8e0ff2b7
JDL
8008 if (fillunits > 0) {
8009 if ( hex.size() > 0 ) {
8010 result.push_back(Pair("result", "success"));
8011 result.push_back(Pair("hex", hex));
8012 } else ERR_RESULT("couldnt fill bid");
8013 } else {
8014 ERR_RESULT("fillunits must be positive");
8015 }
1a02fde9 8016 return(result);
8017}
8018
4f02fc40 8019UniValue getbalance64(const UniValue& params, bool fHelp)
8020{
8021 set<CBitcoinAddress> setAddress; vector<COutput> vecOutputs;
5e0b330d 8022 UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR),b(UniValue::VARR); CTxDestination address;
4f02fc40 8023 const CKeyStore& keystore = *pwalletMain;
8024 CAmount nValues[64],nValues2[64],nValue,total,total2; int32_t i,segid;
4c8293dc 8025 if (!EnsureWalletIsAvailable(fHelp))
8026 return NullUniValue;
8027 if (params.size() > 0)
4f02fc40 8028 throw runtime_error("getbalance64\n");
8029 total = total2 = 0;
8030 memset(nValues,0,sizeof(nValues));
8031 memset(nValues2,0,sizeof(nValues2));
8032 LOCK2(cs_main, pwalletMain->cs_wallet);
8033 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
8034 BOOST_FOREACH(const COutput& out, vecOutputs)
8035 {
8036 nValue = out.tx->vout[out.i].nValue;
5e0b330d 8037 if ( ExtractDestination(out.tx->vout[out.i].scriptPubKey, address) )
4f02fc40 8038 {
ca76a7df 8039 segid = (komodo_segid32((char *)CBitcoinAddress(address).ToString().c_str()) & 0x3f);
4f02fc40 8040 if ( out.nDepth < 100 )
8041 nValues2[segid] += nValue, total2 += nValue;
8042 else nValues[segid] += nValue, total += nValue;
d979952f 8043 //fprintf(stderr,"%s %.8f depth.%d segid.%d\n",(char *)CBitcoinAddress(address).ToString().c_str(),(double)nValue/COIN,(int32_t)out.nDepth,segid);
5e0b330d 8044 } else fprintf(stderr,"no destination\n");
4f02fc40 8045 }
5e0b330d 8046 ret.push_back(Pair("mature",(double)total/COIN));
4f02fc40 8047 ret.push_back(Pair("immature",(double)total2/COIN));
8048 for (i=0; i<64; i++)
8049 {
5e0b330d 8050 a.push_back((uint64_t)nValues[i]);
8051 b.push_back((uint64_t)nValues2[i]);
4f02fc40 8052 }
8053 ret.push_back(Pair("staking", a));
5e0b330d 8054 ret.push_back(Pair("notstaking", b));
4f02fc40 8055 return ret;
8056}
9feb4b9e 8057
34aca1b0
JS
8058extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp
8059extern UniValue importprivkey(const UniValue& params, bool fHelp);
8060extern UniValue importaddress(const UniValue& params, bool fHelp);
8061extern UniValue dumpwallet(const UniValue& params, bool fHelp);
8062extern UniValue importwallet(const UniValue& params, bool fHelp);
8063extern UniValue z_exportkey(const UniValue& params, bool fHelp);
8064extern UniValue z_importkey(const UniValue& params, bool fHelp);
8065extern UniValue z_exportviewingkey(const UniValue& params, bool fHelp);
8066extern UniValue z_importviewingkey(const UniValue& params, bool fHelp);
8067extern UniValue z_exportwallet(const UniValue& params, bool fHelp);
8068extern UniValue z_importwallet(const UniValue& params, bool fHelp);
8069
8070extern UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp); // in rpcdisclosure.cpp
8071extern UniValue z_validatepaymentdisclosure(const UniValue &params, bool fHelp);
8072
a9496b08 8073static const CRPCCommand commands[] =
34aca1b0
JS
8074{ // category name actor (function) okSafeMode
8075 // --------------------- ------------------------ ----------------------- ----------
8076 { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false },
8077 { "hidden", "resendwallettransactions", &resendwallettransactions, true },
8078 { "wallet", "addmultisigaddress", &addmultisigaddress, true },
8079 { "wallet", "backupwallet", &backupwallet, true },
8080 { "wallet", "dumpprivkey", &dumpprivkey, true },
8081 { "wallet", "dumpwallet", &dumpwallet, true },
8082 { "wallet", "encryptwallet", &encryptwallet, true },
8083 { "wallet", "getaccountaddress", &getaccountaddress, true },
8084 { "wallet", "getaccount", &getaccount, true },
8085 { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true },
8086 { "wallet", "getbalance", &getbalance, false },
757a6ada 8087 { "wallet", "getcurrencybalance", &getcurrencybalance, false },
34aca1b0
JS
8088 { "wallet", "getnewaddress", &getnewaddress, true },
8089 { "wallet", "getrawchangeaddress", &getrawchangeaddress, true },
8090 { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false },
8091 { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false },
8092 { "wallet", "gettransaction", &gettransaction, false },
8093 { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false },
8094 { "wallet", "getwalletinfo", &getwalletinfo, false },
5efcf33b 8095 { "wallet", "convertpassphrase", &convertpassphrase, true },
34aca1b0
JS
8096 { "wallet", "importprivkey", &importprivkey, true },
8097 { "wallet", "importwallet", &importwallet, true },
8098 { "wallet", "importaddress", &importaddress, true },
8099 { "wallet", "keypoolrefill", &keypoolrefill, true },
8100 { "wallet", "listaccounts", &listaccounts, false },
8101 { "wallet", "listaddressgroupings", &listaddressgroupings, false },
8102 { "wallet", "listlockunspent", &listlockunspent, false },
8103 { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false },
8104 { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false },
8105 { "wallet", "listsinceblock", &listsinceblock, false },
8106 { "wallet", "listtransactions", &listtransactions, false },
8107 { "wallet", "listunspent", &listunspent, false },
8108 { "wallet", "lockunspent", &lockunspent, true },
8109 { "wallet", "move", &movecmd, false },
8110 { "wallet", "sendfrom", &sendfrom, false },
8111 { "wallet", "sendmany", &sendmany, false },
8112 { "wallet", "sendtoaddress", &sendtoaddress, false },
8113 { "wallet", "setaccount", &setaccount, true },
8114 { "wallet", "settxfee", &settxfee, true },
8115 { "wallet", "signmessage", &signmessage, true },
a5d6c1ec 8116 { "wallet", "signfile", &signfile, true },
b90dccec 8117 { "hidden", "printapis", &printapis, true },
5348b586 8118 // { "hidden", "signhash", &signhash, true }, // disable due to risk of signing something that doesn't contain the content
34aca1b0
JS
8119 { "wallet", "walletlock", &walletlock, true },
8120 { "wallet", "walletpassphrasechange", &walletpassphrasechange, true },
8121 { "wallet", "walletpassphrase", &walletpassphrase, true },
8122 { "wallet", "zcbenchmark", &zc_benchmark, true },
8123 { "wallet", "zcrawkeygen", &zc_raw_keygen, true },
8124 { "wallet", "zcrawjoinsplit", &zc_raw_joinsplit, true },
8125 { "wallet", "zcrawreceive", &zc_raw_receive, true },
8126 { "wallet", "zcsamplejoinsplit", &zc_sample_joinsplit, true },
8127 { "wallet", "z_listreceivedbyaddress", &z_listreceivedbyaddress, false },
8128 { "wallet", "z_listunspent", &z_listunspent, false },
8129 { "wallet", "z_getbalance", &z_getbalance, false },
8130 { "wallet", "z_gettotalbalance", &z_gettotalbalance, false },
8131 { "wallet", "z_mergetoaddress", &z_mergetoaddress, false },
8132 { "wallet", "z_sendmany", &z_sendmany, false },
81a45d69 8133 { "wallet", "z_setmigration", &z_setmigration, false },
6e82d728 8134 { "wallet", "z_getmigrationstatus", &z_getmigrationstatus, false },
34aca1b0
JS
8135 { "wallet", "z_shieldcoinbase", &z_shieldcoinbase, false },
8136 { "wallet", "z_getoperationstatus", &z_getoperationstatus, true },
8137 { "wallet", "z_getoperationresult", &z_getoperationresult, true },
8138 { "wallet", "z_listoperationids", &z_listoperationids, true },
8139 { "wallet", "z_getnewaddress", &z_getnewaddress, true },
8140 { "wallet", "z_listaddresses", &z_listaddresses, true },
8141 { "wallet", "z_exportkey", &z_exportkey, true },
8142 { "wallet", "z_importkey", &z_importkey, true },
8143 { "wallet", "z_exportviewingkey", &z_exportviewingkey, true },
8144 { "wallet", "z_importviewingkey", &z_importviewingkey, true },
8145 { "wallet", "z_exportwallet", &z_exportwallet, true },
8146 { "wallet", "z_importwallet", &z_importwallet, true },
56fe75cb 8147 { "wallet", "z_viewtransaction", &z_viewtransaction, true },
34aca1b0
JS
8148 // TODO: rearrange into another category
8149 { "disclosure", "z_getpaymentdisclosure", &z_getpaymentdisclosure, true },
8150 { "disclosure", "z_validatepaymentdisclosure", &z_validatepaymentdisclosure, true }
8151};
8152
a9496b08 8153void RegisterWalletRPCCommands(CRPCTable &tableRPC)
34aca1b0 8154{
a9496b08
WL
8155 for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
8156 tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
34aca1b0 8157}
This page took 2.596736 seconds and 5 git commands to generate.