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