]> Git Repo - VerusCoin.git/blame - src/wallet/rpcwallet.cpp
gatewaysdeposit rpc
[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"
3d6ee3e0 4859#include "../cc/CCOracles.h"
98a1f520 4860#include "../cc/CCGateways.h"
e37d99ce 4861
cfea7a46 4862UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector<unsigned char> &pubkey)
e37d99ce 4863{
b3965baa 4864 UniValue result(UniValue::VOBJ); char destaddr[64],str[64]; CPubKey pk;
4865 pk = GetUnspendable(cp,0);
4866 GetCCaddress(cp,destaddr,pk);
4867 if ( strcmp(destaddr,cp->unspendableCCaddr) != 0 )
4868 {
4869 uint8_t priv[32];
aed3f987 4870 Myprivkey(priv); // it is assumed the CC's normal address'es -pubkey was used
b3965baa 4871 fprintf(stderr,"fix mismatched CCaddr %s -> %s\n",cp->unspendableCCaddr,destaddr);
4872 strcpy(cp->unspendableCCaddr,destaddr);
4873 }
e37d99ce 4874 result.push_back(Pair("result", "success"));
cfea7a46 4875 sprintf(str,"%sCCaddress",name);
1702dcef 4876 result.push_back(Pair(str,cp->unspendableCCaddr));
4877 sprintf(str,"%smarker",name);
4878 result.push_back(Pair(str,cp->normaladdr));
3515c101 4879 if ( _GetCCaddress(destaddr,EVAL_ASSETS,pubkey2pk(pubkey)) > 0 )
4880 {
4881 sprintf(str,"%sCCassets",name);
4882 result.push_back(Pair(str,destaddr));
4883 }
cfea7a46 4884 if ( pubkey.size() == 33 )
e37d99ce 4885 {
e04b5c08 4886 if ( GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0 )
e37d99ce 4887 result.push_back(Pair("CCaddress",destaddr));
8bbfc238 4888 }
e04b5c08 4889 if ( GetCCaddress(cp,destaddr,pubkey2pk(Mypubkey())) != 0 )
e37d99ce 4890 result.push_back(Pair("myCCaddress",destaddr));
e09492b4 4891 if ( Getscriptaddress(destaddr,(CScript() << Mypubkey() << OP_CHECKSIG)) != 0 )
939cd4b6 4892 result.push_back(Pair("myaddress",destaddr));
e37d99ce 4893 return(result);
4894}
4895
810f6366 4896UniValue channelsaddress(const UniValue& params, bool fHelp)
4897{
4898 UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::vector<unsigned char> destpubkey; CPubKey pk,pk2; char destaddr[64];
4899 cp = CCinit(&C,EVAL_CHANNELS);
4900 if ( fHelp || params.size() != 1 )
4901 throw runtime_error("channelsaddress destpubkey\n");
4902 if ( ensure_CCrequirements() < 0 )
4903 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
4904 destpubkey = ParseHex(params[0].get_str().c_str());
4905 pk = pubkey2pk(Mypubkey());
4906 pk2 = pubkey2pk(destpubkey);
cafa63fb 4907 result = CCaddress(cp,(char *)"Channels",destpubkey);
810f6366 4908 result.push_back(Pair("otherpubkey", params[0].get_str()));
4909 GetCCaddress1of2(cp,destaddr,pk,pk2);
54690bb0 4910 result.push_back(Pair("channeladdress",destaddr));
810f6366 4911 return(result);
4912}
4913
c926780f 4914UniValue oraclesaddress(const UniValue& params, bool fHelp)
4915{
4916 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
4917 cp = CCinit(&C,EVAL_ORACLES);
4918 if ( fHelp || params.size() > 1 )
4919 throw runtime_error("oraclesaddress [pubkey]\n");
4920 if ( ensure_CCrequirements() < 0 )
4921 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
4922 if ( params.size() == 1 )
4923 pubkey = ParseHex(params[0].get_str().c_str());
4924 return(CCaddress(cp,(char *)"Oracles",pubkey));
4925}
4926
4927UniValue pricesaddress(const UniValue& params, bool fHelp)
4928{
4929 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
4930 cp = CCinit(&C,EVAL_PRICES);
4931 if ( fHelp || params.size() > 1 )
4932 throw runtime_error("pricesaddress [pubkey]\n");
4933 if ( ensure_CCrequirements() < 0 )
4934 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
4935 if ( params.size() == 1 )
4936 pubkey = ParseHex(params[0].get_str().c_str());
4937 return(CCaddress(cp,(char *)"Prices",pubkey));
4938}
4939
4940UniValue pegsaddress(const UniValue& params, bool fHelp)
4941{
4942 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
4943 cp = CCinit(&C,EVAL_PEGS);
4944 if ( fHelp || params.size() > 1 )
4945 throw runtime_error("pegssaddress [pubkey]\n");
4946 if ( ensure_CCrequirements() < 0 )
4947 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
4948 if ( params.size() == 1 )
4949 pubkey = ParseHex(params[0].get_str().c_str());
4950 return(CCaddress(cp,(char *)"Pegs",pubkey));
4951}
4952
4953UniValue triggersaddress(const UniValue& params, bool fHelp)
4954{
4955 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
4956 cp = CCinit(&C,EVAL_TRIGGERS);
4957 if ( fHelp || params.size() > 1 )
4958 throw runtime_error("triggersaddress [pubkey]\n");
4959 if ( ensure_CCrequirements() < 0 )
4960 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
4961 if ( params.size() == 1 )
4962 pubkey = ParseHex(params[0].get_str().c_str());
4963 return(CCaddress(cp,(char *)"Triggers",pubkey));
4964}
4965
4966UniValue paymentsaddress(const UniValue& params, bool fHelp)
4967{
4968 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
4969 cp = CCinit(&C,EVAL_PAYMENTS);
4970 if ( fHelp || params.size() > 1 )
4971 throw runtime_error("paymentsaddress [pubkey]\n");
4972 if ( ensure_CCrequirements() < 0 )
4973 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
4974 if ( params.size() == 1 )
4975 pubkey = ParseHex(params[0].get_str().c_str());
4976 return(CCaddress(cp,(char *)"Payments",pubkey));
4977}
4978
4979UniValue gatewaysaddress(const UniValue& params, bool fHelp)
4980{
4981 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
4982 cp = CCinit(&C,EVAL_GATEWAYS);
4983 if ( fHelp || params.size() > 1 )
4984 throw runtime_error("gatewaysaddress [pubkey]\n");
4985 if ( ensure_CCrequirements() < 0 )
4986 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
4987 if ( params.size() == 1 )
4988 pubkey = ParseHex(params[0].get_str().c_str());
4989 return(CCaddress(cp,(char *)"Gateways",pubkey));
4990}
4991
da629dfe 4992UniValue mofnaddress(const UniValue& params, bool fHelp)
4993{
4994 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
4995 cp = CCinit(&C,EVAL_MOFN);
4996 if ( fHelp || params.size() > 1 )
4997 throw runtime_error("mofnaddress [pubkey]\n");
4998 if ( ensure_CCrequirements() < 0 )
4999 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5000 if ( params.size() == 1 )
5001 pubkey = ParseHex(params[0].get_str().c_str());
b3965baa 5002 return(CCaddress(cp,(char *)"MofN",pubkey));
da629dfe 5003}
5004
eca34fd9 5005UniValue lottoaddress(const UniValue& params, bool fHelp)
5006{
5007 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
5008 cp = CCinit(&C,EVAL_LOTTO);
5009 if ( fHelp || params.size() > 1 )
5010 throw runtime_error("lottoaddress [pubkey]\n");
5011 if ( ensure_CCrequirements() < 0 )
5012 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5013 if ( params.size() == 1 )
5014 pubkey = ParseHex(params[0].get_str().c_str());
5015 return(CCaddress(cp,(char *)"Lotto",pubkey));
5016}
5017
7137a022 5018UniValue FSMaddress(const UniValue& params, bool fHelp)
eca34fd9 5019{
5020 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
7137a022 5021 cp = CCinit(&C,EVAL_FSM);
eca34fd9 5022 if ( fHelp || params.size() > 1 )
7137a022 5023 throw runtime_error("FSMaddress [pubkey]\n");
eca34fd9 5024 if ( ensure_CCrequirements() < 0 )
5025 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5026 if ( params.size() == 1 )
5027 pubkey = ParseHex(params[0].get_str().c_str());
7137a022 5028 return(CCaddress(cp,(char *)"FSM",pubkey));
eca34fd9 5029}
5030
5031UniValue auctionaddress(const UniValue& params, bool fHelp)
5032{
5033 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
b935ab65 5034 cp = CCinit(&C,EVAL_AUCTION);
eca34fd9 5035 if ( fHelp || params.size() > 1 )
5036 throw runtime_error("auctionaddress [pubkey]\n");
5037 if ( ensure_CCrequirements() < 0 )
5038 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5039 if ( params.size() == 1 )
5040 pubkey = ParseHex(params[0].get_str().c_str());
5041 return(CCaddress(cp,(char *)"Auction",pubkey));
5042}
5043
cfea7a46 5044UniValue diceaddress(const UniValue& params, bool fHelp)
5045{
5046 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
b2b7d05b 5047 cp = CCinit(&C,EVAL_DICE);
cfea7a46 5048 if ( fHelp || params.size() > 1 )
5049 throw runtime_error("diceaddress [pubkey]\n");
5050 if ( ensure_CCrequirements() < 0 )
5051 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5052 if ( params.size() == 1 )
5053 pubkey = ParseHex(params[0].get_str().c_str());
f0f5f6c0 5054 return(CCaddress(cp,(char *)"Dice",pubkey));
cfea7a46 5055}
5056
5057UniValue faucetaddress(const UniValue& params, bool fHelp)
5058{
5059 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
63583429 5060 int errno;
b2b7d05b 5061 cp = CCinit(&C,EVAL_FAUCET);
cfea7a46 5062 if ( fHelp || params.size() > 1 )
5063 throw runtime_error("faucetaddress [pubkey]\n");
63583429
JDL
5064 errno = ensure_CCrequirements();
5065 if ( errno < 0 )
5066 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 5067 if ( params.size() == 1 )
5068 pubkey = ParseHex(params[0].get_str().c_str());
f0f5f6c0 5069 return(CCaddress(cp,(char *)"Faucet",pubkey));
cfea7a46 5070}
5071
5072UniValue rewardsaddress(const UniValue& params, bool fHelp)
5073{
5074 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
5075 cp = CCinit(&C,EVAL_REWARDS);
5076 if ( fHelp || params.size() > 1 )
5077 throw runtime_error("rewardsaddress [pubkey]\n");
5078 if ( ensure_CCrequirements() < 0 )
5079 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5080 if ( params.size() == 1 )
5081 pubkey = ParseHex(params[0].get_str().c_str());
f0f5f6c0 5082 return(CCaddress(cp,(char *)"Rewards",pubkey));
cfea7a46 5083}
5084
5085UniValue tokenaddress(const UniValue& params, bool fHelp)
5086{
5087 struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
b2b7d05b 5088 cp = CCinit(&C,EVAL_ASSETS);
cfea7a46 5089 if ( fHelp || params.size() > 1 )
5090 throw runtime_error("tokenaddress [pubkey]\n");
5091 if ( ensure_CCrequirements() < 0 )
5092 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5093 if ( params.size() == 1 )
5094 pubkey = ParseHex(params[0].get_str().c_str());
f0f5f6c0 5095 return(CCaddress(cp,(char *)"Assets",pubkey));
cfea7a46 5096}
5097
54690bb0 5098UniValue channelsinfo(const UniValue& params, bool fHelp)
5099{
5100 if ( fHelp || params.size() != 0 )
5101 throw runtime_error("channelsinfo\n");
5102 if ( ensure_CCrequirements() < 0 )
5103 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5104 return(ChannelsInfo());
5105}
5106
810f6366 5107UniValue channelsopen(const UniValue& params, bool fHelp)
5108{
02da4225 5109 UniValue result(UniValue::VOBJ); int32_t numpayments; int64_t payment; std::vector<unsigned char> destpub; struct CCcontract_info *cp,C; std::string hex;
810f6366 5110 cp = CCinit(&C,EVAL_CHANNELS);
5111 if ( fHelp || params.size() != 3 )
5112 throw runtime_error("channelsopen destpubkey numpayments payment\n");
5113 if ( ensure_CCrequirements() < 0 )
5114 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5115 LOCK(cs_main);
5116 destpub = ParseHex(params[0].get_str().c_str());
5117 numpayments = atoi(params[1].get_str().c_str());
11020cf2 5118 payment = atol(params[2].get_str().c_str());
810f6366 5119 hex = ChannelOpen(0,pubkey2pk(destpub),numpayments,payment);
5120 if ( hex.size() > 0 )
5121 {
5122 result.push_back(Pair("result", "success"));
5123 result.push_back(Pair("hex", hex));
5124 } else ERR_RESULT("couldnt create channelsopen transaction");
5125 return(result);
5126}
5127
02da4225 5128UniValue channelsstop(const UniValue& params, bool fHelp)
5129{
5130 UniValue result(UniValue::VOBJ); std::vector<unsigned char> destpub; struct CCcontract_info *cp,C; std::string hex; uint256 origtxid;
5131 cp = CCinit(&C,EVAL_CHANNELS);
5132 if ( fHelp || params.size() != 2 )
5133 throw runtime_error("channelsstop destpubkey origtxid\n");
5134 if ( ensure_CCrequirements() < 0 )
5135 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5136 LOCK(cs_main);
5137 destpub = ParseHex(params[0].get_str().c_str());
5138 origtxid = Parseuint256((char *)params[1].get_str().c_str());
5139 hex = ChannelStop(0,pubkey2pk(destpub),origtxid);
5140 if ( hex.size() > 0 )
5141 {
5142 result.push_back(Pair("result", "success"));
5143 result.push_back(Pair("hex", hex));
5144 } else ERR_RESULT("couldnt create channelsstop transaction");
5145 return(result);
5146}
5147
5148UniValue channelspayment(const UniValue& params, bool fHelp)
5149{
5150 UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 origtxid,prevtxid; int32_t n; int64_t amount;
5151 cp = CCinit(&C,EVAL_CHANNELS);
5152 if ( fHelp || params.size() != 4 )
5153 throw runtime_error("channelspayment prevtxid origtxid n amount\n");
5154 if ( ensure_CCrequirements() < 0 )
5155 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5156 LOCK(cs_main);
5157 prevtxid = Parseuint256((char *)params[0].get_str().c_str());
5158 origtxid = Parseuint256((char *)params[1].get_str().c_str());
5159 n = atoi((char *)params[2].get_str().c_str());
5160 amount = atoi((char *)params[3].get_str().c_str());
2b349eff 5161 hex = ChannelPayment(0,prevtxid,origtxid,n,amount);
02da4225 5162 if ( hex.size() > 0 )
5163 {
5164 result.push_back(Pair("result", "success"));
5165 result.push_back(Pair("hex", hex));
5166 } else ERR_RESULT("couldnt create channelspayment transaction");
5167 return(result);
5168}
5169
5170UniValue channelscollect(const UniValue& params, bool fHelp)
5171{
3737d456 5172 UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 origtxid,paytxid; int32_t n; int64_t amount;
02da4225 5173 cp = CCinit(&C,EVAL_CHANNELS);
5174 if ( fHelp || params.size() != 4 )
3737d456 5175 throw runtime_error("channelscollect paytxid origtxid n amount\n");
02da4225 5176 if ( ensure_CCrequirements() < 0 )
5177 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5178 LOCK(cs_main);
3737d456 5179 paytxid = Parseuint256((char *)params[0].get_str().c_str());
02da4225 5180 origtxid = Parseuint256((char *)params[1].get_str().c_str());
5181 n = atoi((char *)params[2].get_str().c_str());
5182 amount = atoi((char *)params[3].get_str().c_str());
3737d456 5183 hex = ChannelCollect(0,paytxid,origtxid,n,amount);
02da4225 5184 if ( hex.size() > 0 )
5185 {
5186 result.push_back(Pair("result", "success"));
5187 result.push_back(Pair("hex", hex));
5188 } else ERR_RESULT("couldnt create channelscollect transaction");
5189 return(result);
5190}
5191
5192UniValue channelsrefund(const UniValue& params, bool fHelp)
5193{
5194 UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 origtxid,stoptxid;
5195 cp = CCinit(&C,EVAL_CHANNELS);
5196 if ( fHelp || params.size() != 2 )
5197 throw runtime_error("channelsrefund stoptxid origtxid\n");
5198 if ( ensure_CCrequirements() < 0 )
5199 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5200 LOCK(cs_main);
5201 stoptxid = Parseuint256((char *)params[0].get_str().c_str());
5202 origtxid = Parseuint256((char *)params[1].get_str().c_str());
5203 hex = ChannelRefund(0,stoptxid,origtxid);
5204 if ( hex.size() > 0 )
5205 {
5206 result.push_back(Pair("result", "success"));
5207 result.push_back(Pair("hex", hex));
5208 } else ERR_RESULT("couldnt create channelsrefund transaction");
5209 return(result);
5210}
5211
e95b9582 5212UniValue rewardscreatefunding(const UniValue& params, bool fHelp)
e37d99ce 5213{
a03146b3 5214 UniValue result(UniValue::VOBJ); char *name; int64_t funds,APR,minseconds,maxseconds,mindeposit; std::string hex;
f0f5f6c0 5215 if ( fHelp || params.size() > 6 || params.size() < 2 )
eac2c15e 5216 throw runtime_error("rewardscreatefunding name amount APR mindays maxdays mindeposit\n");
e37d99ce 5217 if ( ensure_CCrequirements() < 0 )
5218 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 5219 const CKeyStore& keystore = *pwalletMain;
5220 LOCK2(cs_main, pwalletMain->cs_wallet);
5221 // default to OOT params
e37d99ce 5222 APR = 5 * COIN;
5223 minseconds = maxseconds = 60 * 3600 * 24;
5224 mindeposit = 100 * COIN;
11787469 5225 name = (char *)params[0].get_str().c_str();
f0f5f6c0 5226 funds = atof(params[1].get_str().c_str()) * COIN;
a03146b3 5227
bad5d1c3
AL
5228 if (!VALID_PLAN_NAME(name)) {
5229 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
5230 return(result);
5231 }
5232
a03146b3
JDL
5233 if ( funds <= 0 ) {
5234 ERR_RESULT("funds must be positive");
5235 return result;
5236 }
f0f5f6c0 5237 if ( params.size() > 2 )
e37d99ce 5238 {
f0f5f6c0 5239 APR = atof(params[2].get_str().c_str()) * COIN;
a03146b3
JDL
5240 if ( APR > REWARDSCC_MAXAPR )
5241 {
5242 ERR_RESULT("25% APR is maximum");
5243 return result;
5244 }
f0f5f6c0 5245 if ( params.size() > 3 )
e37d99ce 5246 {
f0f5f6c0 5247 minseconds = atol(params[3].get_str().c_str()) * 3600 * 24;
a03146b3
JDL
5248 if ( minseconds < 0 ) {
5249 ERR_RESULT("mindays must be non-negative");
5250 return result;
5251 }
f0f5f6c0 5252 if ( params.size() > 4 )
e37d99ce 5253 {
f0f5f6c0 5254 maxseconds = atol(params[4].get_str().c_str()) * 3600 * 24;
a03146b3
JDL
5255 if ( maxseconds <= 0 ) {
5256 ERR_RESULT("maxdays must be positive");
5257 return result;
5258 }
5259 if ( maxseconds < minseconds ) {
5260 ERR_RESULT("maxdays must be greater than mindays");
5261 return result;
5262 }
f0f5f6c0 5263 if ( params.size() > 5 )
5264 mindeposit = atof(params[5].get_str().c_str()) * COIN;
a03146b3
JDL
5265 if ( mindeposit <= 0 ) {
5266 ERR_RESULT("mindeposit must be positive");
5267 return result;
5268 }
e37d99ce 5269 }
5270 }
5271 }
4f394f44 5272 hex = RewardsCreateFunding(0,name,funds,APR,minseconds,maxseconds,mindeposit);
e37d99ce 5273 if ( hex.size() > 0 )
5274 {
5275 result.push_back(Pair("result", "success"));
5276 result.push_back(Pair("hex", hex));
8a3e1884 5277 } else ERR_RESULT("couldnt create rewards funding transaction");
e37d99ce 5278 return(result);
5279}
5280
5281UniValue rewardslock(const UniValue& params, bool fHelp)
5282{
66027c02 5283 UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid; int64_t amount; std::string hex;
c4e7f616 5284 if ( fHelp || params.size() != 3 )
5285 throw runtime_error("rewardslock name fundingtxid amount\n");
e37d99ce 5286 if ( ensure_CCrequirements() < 0 )
5287 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 5288 const CKeyStore& keystore = *pwalletMain;
5289 LOCK2(cs_main, pwalletMain->cs_wallet);
f0f5f6c0 5290 name = (char *)params[0].get_str().c_str();
c4e7f616 5291 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
5292 amount = atof(params[2].get_str().c_str()) * COIN;
5293 hex = RewardsLock(0,name,fundingtxid,amount);
bad5d1c3
AL
5294
5295 if (!VALID_PLAN_NAME(name)) {
5296 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
5297 return(result);
5298 }
a03146b3
JDL
5299 if ( CCerror != "" ){
5300 ERR_RESULT(CCerror);
5301 } else if ( amount > 0 ) {
66027c02
JDL
5302 if ( hex.size() > 0 )
5303 {
5304 result.push_back(Pair("result", "success"));
5305 result.push_back(Pair("hex", hex));
8a3e1884
JDL
5306 } else ERR_RESULT( "couldnt create rewards lock transaction");
5307 } else ERR_RESULT("amount must be positive");
c4e7f616 5308 return(result);
5309}
5310
5311UniValue rewardsaddfunding(const UniValue& params, bool fHelp)
5312{
88e71457 5313 UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid; int64_t amount; std::string hex;
c4e7f616 5314 if ( fHelp || params.size() != 3 )
5315 throw runtime_error("rewardsaddfunding name fundingtxid amount\n");
5316 if ( ensure_CCrequirements() < 0 )
5317 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 5318 const CKeyStore& keystore = *pwalletMain;
5319 LOCK2(cs_main, pwalletMain->cs_wallet);
c4e7f616 5320 name = (char *)params[0].get_str().c_str();
5321 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
5322 amount = atof(params[2].get_str().c_str()) * COIN;
e95b9582 5323 hex = RewardsAddfunding(0,name,fundingtxid,amount);
bad5d1c3
AL
5324
5325 if (!VALID_PLAN_NAME(name)) {
5326 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
5327 return(result);
5328 }
a03146b3
JDL
5329 if (CCerror != "") {
5330 ERR_RESULT(CCerror);
5331 } else if (amount > 0) {
88e71457
JDL
5332 if ( hex.size() > 0 )
5333 {
5334 result.push_back(Pair("result", "success"));
5335 result.push_back(Pair("hex", hex));
5336 } else {
5337 result.push_back(Pair("result", "error"));
5338 result.push_back(Pair("error", "couldnt create rewards addfunding transaction"));
5339 }
5340 } else {
a03146b3 5341 ERR_RESULT("funding amount must be positive");
88e71457 5342 }
e37d99ce 5343 return(result);
5344}
5345
5346UniValue rewardsunlock(const UniValue& params, bool fHelp)
5347{
c4e7f616 5348 UniValue result(UniValue::VOBJ); std::string hex; char *name; uint256 fundingtxid,txid;
81915d9f 5349 if ( fHelp || params.size() > 3 || params.size() < 2 )
c4e7f616 5350 throw runtime_error("rewardsunlock name fundingtxid [txid]\n");
e37d99ce 5351 if ( ensure_CCrequirements() < 0 )
5352 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 5353 const CKeyStore& keystore = *pwalletMain;
5354 LOCK2(cs_main, pwalletMain->cs_wallet);
f0f5f6c0 5355 name = (char *)params[0].get_str().c_str();
c4e7f616 5356 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
bad5d1c3
AL
5357
5358 if (!VALID_PLAN_NAME(name)) {
5359 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
5360 return(result);
5361 }
c4e7f616 5362 if ( params.size() > 2 )
5363 txid = Parseuint256((char *)params[2].get_str().c_str());
f0f5f6c0 5364 else memset(&txid,0,sizeof(txid));
c4e7f616 5365 hex = RewardsUnlock(0,name,fundingtxid,txid);
8e0ff2b7 5366 if (CCerror != "") {
8a3e1884
JDL
5367 ERR_RESULT(CCerror);
5368 } else if ( hex.size() > 0 ) {
e37d99ce 5369 result.push_back(Pair("result", "success"));
5370 result.push_back(Pair("hex", hex));
8a3e1884 5371 } else ERR_RESULT("couldnt create rewards unlock transaction");
e37d99ce 5372 return(result);
5373}
5374
c857567a 5375UniValue rewardslist(const UniValue& params, bool fHelp)
5376{
c857567a 5377 if ( fHelp || params.size() > 0 )
5378 throw runtime_error("rewardslist\n");
5379 if ( ensure_CCrequirements() < 0 )
5380 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5381 return(RewardsList());
5382}
5383
5384UniValue rewardsinfo(const UniValue& params, bool fHelp)
5385{
5386 uint256 fundingtxid;
5387 if ( fHelp || params.size() != 1 )
5388 throw runtime_error("rewardsinfo fundingtxid\n");
5389 if ( ensure_CCrequirements() < 0 )
5390 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5391 fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
5392 return(RewardsInfo(fundingtxid));
5393}
5394
3515c101 5395UniValue gatewayslist(const UniValue& params, bool fHelp)
5396{
5397 if ( fHelp || params.size() > 0 )
5398 throw runtime_error("gatewayslist\n");
5399 if ( ensure_CCrequirements() < 0 )
5400 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5401 return(GatewaysList());
5402}
5403
5404UniValue gatewaysinfo(const UniValue& params, bool fHelp)
5405{
5406 uint256 txid;
5407 if ( fHelp || params.size() != 1 )
5408 throw runtime_error("gatewaysinfo bindtxid\n");
5409 if ( ensure_CCrequirements() < 0 )
5410 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5411 txid = Parseuint256((char *)params[0].get_str().c_str());
5412 return(GatewaysInfo(txid));
5413}
5414
5415UniValue gatewaysbind(const UniValue& params, bool fHelp)
5416{
dbf8484e 5417 UniValue result(UniValue::VOBJ); uint256 tokenid,oracletxid; int32_t i; int64_t totalsupply; std::vector<CPubKey> pubkeys; uint8_t M,N; std::string hex,coin; std::vector<unsigned char> pubkey;
5418 if ( fHelp || params.size() < 6 )
5419 throw runtime_error("gatewaysbind tokenid oracletxid coin tokensupply M N pubkey(s)\n");
3515c101 5420 if ( ensure_CCrequirements() < 0 )
5421 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5422 tokenid = Parseuint256((char *)params[0].get_str().c_str());
dbf8484e 5423 oracletxid = Parseuint256((char *)params[1].get_str().c_str());
5424 coin = params[2].get_str();
5425 totalsupply = atol((char *)params[3].get_str().c_str());
5426 M = atoi((char *)params[4].get_str().c_str());
5427 N = atoi((char *)params[5].get_str().c_str());
98a1f520 5428 if ( M > N || N == 0 || N > 15 || totalsupply < COIN/100 || tokenid == zeroid )
3515c101 5429 throw runtime_error("illegal M or N > 15 or tokensupply or invalid tokenid\n");
3515c101 5430 for (i=0; i<N; i++)
5431 {
77fad432 5432 if ( params.size() < 6+i+1 )
3515c101 5433 throw runtime_error("not enough parameters for N pubkeys\n");
77fad432 5434 pubkey = ParseHex(params[6+i].get_str().c_str());
3515c101 5435 pubkeys.push_back(pubkey2pk(pubkey));
5436 }
dbf8484e 5437 hex = GatewaysBind(0,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys);
3515c101 5438 if ( hex.size() > 0 )
5439 {
5440 result.push_back(Pair("result", "success"));
5441 result.push_back(Pair("hex", hex));
5442 } else ERR_RESULT("couldnt gatewaysbind");
5443 return(result);
5444}
5445
5446UniValue gatewaysdeposit(const UniValue& params, bool fHelp)
5447{
d73f18f5 5448 UniValue result(UniValue::VOBJ); int32_t i,claimvout,height,numpks; int64_t amount; std::string hex,coin,deposithex; uint256 bindtxid,cointxid; std::vector<CPubKey>pubkeys; std::vector<uint256>proof,redeemscript;
5449 if ( fHelp || params.size() != 11 )
5450 throw runtime_error("gatewaysdeposit bindtxid height coin cointxid claimvout deposithex proof redeemscript amount numpks oraclepks\n");
5451 if ( ensure_CCrequirements() < 0 )
5452 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5453 bindtxid = Parseuint256((char *)params[0].get_str().c_str());
5454 height = atoi((char *)params[1].get_str().c_str());
5455 coin = params[2].get_str();
5456 cointxid = Parseuint256((char *)params[3].get_str().c_str());
5457 claimvout = atoi((char *)params[4].get_str().c_str());
5458 deposithex = params[5].get_str();
5459 proof = ParseHex(params[6].get_str());
5460 redeemscript = ParseHex(params[7].get_str());
5461 amount = atof((char *)params[8].get_str().c_str()) * COIN;
5462 numpks = atoi((char *)params[9].get_str().c_str());
5463 if ( amount <= 0 || numpks <= 0 || claimvout < 0 )
5464 throw runtime_error("invalid param: amount, numpks or claimvout\n");
5465 for (i=0; i<numpks; i++)
5466 {
5467 if ( params.size() < 10+i+1 )
5468 throw runtime_error("not enough parameters for numpks oraclepubkeys\n");
5469 pubkey = ParseHex(params[10+i].get_str().c_str());
5470 pubkeys.push_back(pubkey2pk(pubkey));
5471 }
5472 hex = GatewaysDeposit(0,bindtxid,pubkeys,height,coin,cointxid,claimvout,deposithex,proof,redeemscript,amount);
3515c101 5473 if ( hex.size() > 0 )
5474 {
5475 result.push_back(Pair("result", "success"));
5476 result.push_back(Pair("hex", hex));
5477 } else ERR_RESULT("couldnt gatewaysdeposit");
5478 return(result);
5479}
5480
5481UniValue gatewaysclaim(const UniValue& params, bool fHelp)
5482{
98a1f520 5483 UniValue result(UniValue::VOBJ); std::string hex;
3515c101 5484 // std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string coin,uint256 deposittxid,std::string claimaddr,int64_t amount)
5485 if ( hex.size() > 0 )
5486 {
5487 result.push_back(Pair("result", "success"));
5488 result.push_back(Pair("hex", hex));
5489 } else ERR_RESULT("couldnt gatewaysclaim");
5490 return(result);
5491}
5492
5493UniValue gatewayswithdraw(const UniValue& params, bool fHelp)
5494{
98a1f520 5495 UniValue result(UniValue::VOBJ); std::string hex;
3515c101 5496 // std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,std::vector<uint8_t> withdrawpub,int64_t amount)
5497 if ( hex.size() > 0 )
5498 {
5499 result.push_back(Pair("result", "success"));
5500 result.push_back(Pair("hex", hex));
5501 } else ERR_RESULT("couldnt gatewayswithdraw");
5502 return(result);
5503}
5504
366625ca 5505UniValue oracleslist(const UniValue& params, bool fHelp)
5506{
5507 if ( fHelp || params.size() > 0 )
5508 throw runtime_error("oracleslist\n");
5509 if ( ensure_CCrequirements() < 0 )
5510 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5511 return(OraclesList());
5512}
5513
5514UniValue oraclesinfo(const UniValue& params, bool fHelp)
5515{
5516 uint256 txid;
5517 if ( fHelp || params.size() != 1 )
5518 throw runtime_error("oraclesinfo oracletxid\n");
5519 if ( ensure_CCrequirements() < 0 )
5520 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5521 txid = Parseuint256((char *)params[0].get_str().c_str());
5522 return(OracleInfo(txid));
5523}
5524
5525UniValue oraclesregister(const UniValue& params, bool fHelp)
5526{
3d6ee3e0 5527 UniValue result(UniValue::VOBJ); uint256 txid; int64_t datafee; std::string hex;
366625ca 5528 if ( fHelp || params.size() != 2 )
5529 throw runtime_error("oraclesregister oracletxid datafee\n");
5530 if ( ensure_CCrequirements() < 0 )
5531 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5532 txid = Parseuint256((char *)params[0].get_str().c_str());
5533 datafee = atol((char *)params[1].get_str().c_str());
5534 hex = OracleRegister(0,txid,datafee);
5535 if ( hex.size() > 0 )
5536 {
5537 result.push_back(Pair("result", "success"));
5538 result.push_back(Pair("hex", hex));
5539 } else ERR_RESULT("couldnt register with oracle txid");
5540 return(result);
5541}
5542
5543UniValue oraclessubscribe(const UniValue& params, bool fHelp)
5544{
3d6ee3e0 5545 UniValue result(UniValue::VOBJ); uint256 txid; int64_t amount; std::string hex; std::vector<unsigned char> pubkey;
366625ca 5546 if ( fHelp || params.size() != 3 )
d95908b8 5547 throw runtime_error("oraclessubscribe oracletxid publisher amount\n");
366625ca 5548 if ( ensure_CCrequirements() < 0 )
5549 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5550 txid = Parseuint256((char *)params[0].get_str().c_str());
5551 pubkey = ParseHex(params[1].get_str().c_str());
d95908b8 5552 amount = atof((char *)params[2].get_str().c_str()) * COIN;
366625ca 5553 hex = OracleSubscribe(0,txid,pubkey2pk(pubkey),amount);
5554 if ( hex.size() > 0 )
5555 {
5556 result.push_back(Pair("result", "success"));
5557 result.push_back(Pair("hex", hex));
26ca942e 5558 } else ERR_RESULT("couldnt subscribe with oracle txid");
5559 return(result);
5560}
5561
5562UniValue oraclessamples(const UniValue& params, bool fHelp)
5563{
a82dd70f 5564 UniValue result(UniValue::VOBJ); uint256 txid,batontxid; int32_t num;
26ca942e 5565 if ( fHelp || params.size() != 3 )
5566 throw runtime_error("oraclessamples oracletxid batonutxo num\n");
5567 if ( ensure_CCrequirements() < 0 )
5568 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5569 txid = Parseuint256((char *)params[0].get_str().c_str());
5570 batontxid = Parseuint256((char *)params[1].get_str().c_str());
5571 num = atoi((char *)params[2].get_str().c_str());
a82dd70f 5572 return(OracleDataSamples(txid,batontxid,num));
366625ca 5573}
5574
5575UniValue oraclesdata(const UniValue& params, bool fHelp)
5576{
3d6ee3e0 5577 UniValue result(UniValue::VOBJ); uint256 txid; std::vector<unsigned char> data; std::string hex;
366625ca 5578 if ( fHelp || params.size() != 2 )
5579 throw runtime_error("oraclesdata oracletxid hexstr\n");
5580 if ( ensure_CCrequirements() < 0 )
5581 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5582 txid = Parseuint256((char *)params[0].get_str().c_str());
5583 data = ParseHex(params[1].get_str().c_str());
5584 hex = OracleData(0,txid,data);
5585 if ( hex.size() > 0 )
5586 {
5587 result.push_back(Pair("result", "success"));
5588 result.push_back(Pair("hex", hex));
5589 } else ERR_RESULT("couldnt publish data with oracle txid");
5590 return(result);
5591}
5592
5593UniValue oraclescreate(const UniValue& params, bool fHelp)
5594{
5595 UniValue result(UniValue::VOBJ); std::string name,description,format,hex;
5596 if ( fHelp || params.size() != 3 )
5597 throw runtime_error("oraclescreate name description format\n");
5598 if ( ensure_CCrequirements() < 0 )
5599 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5600 const CKeyStore& keystore = *pwalletMain;
5601 LOCK2(cs_main, pwalletMain->cs_wallet);
5602 name = params[0].get_str();
5603 if ( name.size() == 0 || name.size() > 32)
5604 {
5605 ERR_RESULT("oracles name must not be empty and up to 32 characters");
5606 return(result);
5607 }
5608 description = params[1].get_str();
5609 if ( description.size() > 4096 )
5610 {
5611 ERR_RESULT("oracles description must be <= 4096 characters");
5612 return(result);
5613 }
5614 format = params[2].get_str();
5615 if ( format.size() > 4096 )
5616 {
5617 ERR_RESULT("oracles format must be <= 4096 characters");
5618 return(result);
5619 }
5620 hex = OracleCreate(0,name,description,format);
5621 if ( hex.size() > 0 )
5622 {
5623 result.push_back(Pair("result", "success"));
5624 result.push_back(Pair("hex", hex));
5625 } else ERR_RESULT("couldnt create oracle");
5626 return(result);
5627}
5628
7137a022 5629UniValue FSMcreate(const UniValue& params, bool fHelp)
5630{
5631 UniValue result(UniValue::VOBJ); std::string name,states,hex;
5632 if ( fHelp || params.size() != 2 )
5633 throw runtime_error("FSMcreate name states\n");
5634 if ( ensure_CCrequirements() < 0 )
5635 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5636 const CKeyStore& keystore = *pwalletMain;
5637 LOCK2(cs_main, pwalletMain->cs_wallet);
5638 name = params[0].get_str();
5639 states = params[1].get_str();
d9cf43a5 5640 hex = FSMCreate(0,name,states);
7137a022 5641 if ( hex.size() > 0 )
5642 {
5643 result.push_back(Pair("result", "success"));
5644 result.push_back(Pair("hex", hex));
5645 } else result.push_back(Pair("error", "couldnt create FSM transaction"));
5646 return(result);
5647}
5648
5649UniValue FSMlist(const UniValue& params, bool fHelp)
5650{
5651 uint256 tokenid;
5652 if ( fHelp || params.size() > 0 )
5653 throw runtime_error("FSMlist\n");
5654 if ( ensure_CCrequirements() < 0 )
5655 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5656 return(FSMList());
5657}
5658
5659UniValue FSMinfo(const UniValue& params, bool fHelp)
5660{
5661 uint256 FSMtxid;
5662 if ( fHelp || params.size() != 1 )
5663 throw runtime_error("FSMinfo fundingtxid\n");
5664 if ( ensure_CCrequirements() < 0 )
5665 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
d9cf43a5 5666 FSMtxid = Parseuint256((char *)params[0].get_str().c_str());
7137a022 5667 return(FSMInfo(FSMtxid));
5668}
5669
4608d170 5670UniValue faucetinfo(const UniValue& params, bool fHelp)
5671{
5672 uint256 fundingtxid;
5673 if ( fHelp || params.size() != 0 )
5674 throw runtime_error("faucetinfo\n");
5675 if ( ensure_CCrequirements() < 0 )
5676 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5677 return(FaucetInfo());
5678}
5679
cfea7a46 5680UniValue faucetfund(const UniValue& params, bool fHelp)
6ff08712 5681{
2098a4c9 5682 UniValue result(UniValue::VOBJ); int64_t funds; std::string hex;
6ff08712 5683 if ( fHelp || params.size() > 1 )
cfea7a46 5684 throw runtime_error("faucetfund amount\n");
6ff08712 5685 if ( ensure_CCrequirements() < 0 )
5686 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 5687 const CKeyStore& keystore = *pwalletMain;
5688 LOCK2(cs_main, pwalletMain->cs_wallet);
cfea7a46 5689 funds = atof(params[0].get_str().c_str()) * COIN;
700c1fcf 5690 if (funds > 0) {
2098a4c9 5691 hex = FaucetFund(0,(uint64_t) funds);
700c1fcf
JDL
5692 if ( hex.size() > 0 )
5693 {
5694 result.push_back(Pair("result", "success"));
5695 result.push_back(Pair("hex", hex));
8a3e1884
JDL
5696 } else ERR_RESULT("couldnt create faucet funding transaction");
5697 } else ERR_RESULT( "funding amount must be positive");
6ff08712 5698 return(result);
5699}
5700
cfea7a46 5701UniValue faucetget(const UniValue& params, bool fHelp)
5702{
5703 UniValue result(UniValue::VOBJ); std::string hex;
5704 if ( fHelp || params.size() > 0 )
5705 throw runtime_error("faucetget\n");
5706 if ( ensure_CCrequirements() < 0 )
5707 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 5708 const CKeyStore& keystore = *pwalletMain;
5709 LOCK2(cs_main, pwalletMain->cs_wallet);
cfea7a46 5710 hex = FaucetGet(0);
8e0ff2b7 5711 if ( hex.size() > 0 ) {
cfea7a46 5712 result.push_back(Pair("result", "success"));
5713 result.push_back(Pair("hex", hex));
8a3e1884 5714 } else ERR_RESULT("couldnt create faucet get transaction");
cfea7a46 5715 return(result);
5716}
5717
5718UniValue dicefund(const UniValue& params, bool fHelp)
65a961ff 5719{
9025093e 5720 UniValue result(UniValue::VOBJ); int64_t funds,minbet,maxbet,maxodds,timeoutblocks; std::string hex; char *name;
5bd03ad7 5721 if ( fHelp || params.size() != 6 )
9025093e 5722 throw runtime_error("dicefund name funds minbet maxbet maxodds timeoutblocks\n");
e10def86 5723 if ( ensure_CCrequirements() < 0 )
5724 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 5725 const CKeyStore& keystore = *pwalletMain;
5726 LOCK2(cs_main, pwalletMain->cs_wallet);
5bd03ad7 5727 name = (char *)params[0].get_str().c_str();
5728 funds = atof(params[1].get_str().c_str()) * COIN;
5729 minbet = atof(params[2].get_str().c_str()) * COIN;
5730 maxbet = atof(params[3].get_str().c_str()) * COIN;
5731 maxodds = atol(params[4].get_str().c_str());
9025093e 5732 timeoutblocks = atol(params[5].get_str().c_str());
124819ce
JDL
5733
5734 if (!VALID_PLAN_NAME(name)) {
5735 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
5736 return(result);
5737 }
5738
9025093e 5739 hex = DiceCreateFunding(0,name,funds,minbet,maxbet,maxodds,timeoutblocks);
8e0ff2b7 5740 if (CCerror != "") {
8a3e1884 5741 ERR_RESULT(CCerror);
8e0ff2b7 5742 } else if ( hex.size() > 0 ) {
65a961ff 5743 result.push_back(Pair("result", "success"));
5744 result.push_back(Pair("hex", hex));
8e0ff2b7 5745 } else {
8a3e1884 5746 ERR_RESULT( "couldnt create dice funding transaction");
8e0ff2b7 5747 }
65a961ff 5748 return(result);
5749}
5750
587e715d 5751UniValue diceaddfunds(const UniValue& params, bool fHelp)
5752{
8e0ff2b7 5753 UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid; int64_t amount; std::string hex;
587e715d 5754 if ( fHelp || params.size() != 3 )
5755 throw runtime_error("diceaddfunds name fundingtxid amount\n");
5756 if ( ensure_CCrequirements() < 0 )
5757 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 5758 const CKeyStore& keystore = *pwalletMain;
5759 LOCK2(cs_main, pwalletMain->cs_wallet);
587e715d 5760 name = (char *)params[0].get_str().c_str();
5761 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
5762 amount = atof(params[2].get_str().c_str()) * COIN;
124819ce
JDL
5763 if (!VALID_PLAN_NAME(name)) {
5764 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
5765 return(result);
5766 }
8e0ff2b7
JDL
5767 if ( amount > 0 ) {
5768 hex = DiceAddfunding(0,name,fundingtxid,amount);
5769 if (CCerror != "") {
8a3e1884 5770 ERR_RESULT(CCerror);
8e0ff2b7
JDL
5771 } else if ( hex.size() > 0 ) {
5772 result.push_back(Pair("result", "success"));
5773 result.push_back(Pair("hex", hex));
8a3e1884
JDL
5774 } else ERR_RESULT("couldnt create dice addfunding transaction");
5775 } else ERR_RESULT("amount must be positive");
587e715d 5776 return(result);
5777}
5778
cfea7a46 5779UniValue dicebet(const UniValue& params, bool fHelp)
65a961ff 5780{
8e0ff2b7 5781 UniValue result(UniValue::VOBJ); std::string hex; uint256 fundingtxid; int64_t amount,odds; char *name;
135ead85 5782 if ( fHelp || params.size() != 4 )
7d821112 5783 throw runtime_error("dicebet name fundingtxid amount odds\n");
e10def86 5784 if ( ensure_CCrequirements() < 0 )
5785 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 5786 const CKeyStore& keystore = *pwalletMain;
5787 LOCK2(cs_main, pwalletMain->cs_wallet);
7d821112 5788 name = (char *)params[0].get_str().c_str();
5789 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
5790 amount = atof(params[2].get_str().c_str()) * COIN;
5791 odds = atol(params[3].get_str().c_str());
124819ce
JDL
5792
5793 if (!VALID_PLAN_NAME(name)) {
5794 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
5795 return(result);
5796 }
8e0ff2b7
JDL
5797 if (amount > 0 && odds > 0) {
5798 hex = DiceBet(0,name,fundingtxid,amount,odds);
5799 if ( hex.size() > 0 )
5800 {
5801 result.push_back(Pair("result", "success"));
5802 result.push_back(Pair("hex", hex));
eb4cf14d 5803 } else ERR_RESULT("couldnt create dice bet transaction. make sure your address has funds");
8e0ff2b7
JDL
5804 } else {
5805 ERR_RESULT("amount and odds must be positive");
5806 }
65a961ff 5807 return(result);
5808}
5809
7e988759 5810UniValue dicefinish(const UniValue& params, bool fHelp)
5d3d3a87 5811{
8e0ff2b7 5812 UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid,bettxid; std::string hex; int32_t r;
5d3d3a87 5813 if ( fHelp || params.size() != 3 )
7e988759 5814 throw runtime_error("dicefinish name fundingtxid bettxid\n");
5d3d3a87 5815 if ( ensure_CCrequirements() < 0 )
5816 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 5817 const CKeyStore& keystore = *pwalletMain;
5818 LOCK2(cs_main, pwalletMain->cs_wallet);
5d3d3a87 5819 name = (char *)params[0].get_str().c_str();
124819ce
JDL
5820 if (!VALID_PLAN_NAME(name)) {
5821 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
5822 return(result);
5823 }
5d3d3a87 5824 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
5825 bettxid = Parseuint256((char *)params[2].get_str().c_str());
7e988759 5826 hex = DiceBetFinish(&r,0,name,fundingtxid,bettxid,1);
a03146b3
JDL
5827 if ( CCerror != "" )
5828 {
5829 ERR_RESULT(CCerror);
5830 } else if ( hex.size() > 0 )
5d3d3a87 5831 {
5832 result.push_back(Pair("result", "success"));
5833 result.push_back(Pair("hex", hex));
8a3e1884 5834 } else ERR_RESULT( "couldnt create dicefinish transaction");
5d3d3a87 5835 return(result);
5836}
5837
7e988759 5838UniValue dicestatus(const UniValue& params, bool fHelp)
5d3d3a87 5839{
8e0ff2b7 5840 UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid,bettxid; std::string status; double winnings;
7b44d4c1 5841 if ( fHelp || (params.size() != 2 && params.size() != 3) )
7e988759 5842 throw runtime_error("dicestatus name fundingtxid bettxid\n");
544593c6 5843 if ( ensure_CCrequirements() < 0 )
5844 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 5845 const CKeyStore& keystore = *pwalletMain;
5846 LOCK2(cs_main, pwalletMain->cs_wallet);
544593c6 5847 name = (char *)params[0].get_str().c_str();
124819ce
JDL
5848 if (!VALID_PLAN_NAME(name)) {
5849 ERR_RESULT(strprintf("Plan name can be at most %d ASCII characters",PLAN_NAME_MAX));
5850 return(result);
5851 }
544593c6 5852 fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
75dbd478 5853 memset(&bettxid,0,sizeof(bettxid));
5854 if ( params.size() == 3 )
5855 bettxid = Parseuint256((char *)params[2].get_str().c_str());
4e525e48 5856 winnings = DiceStatus(0,name,fundingtxid,bettxid);
a03146b3
JDL
5857 if (CCerror != "") {
5858 ERR_RESULT(CCerror);
5859 return result;
5860 }
7e988759 5861 result.push_back(Pair("result", "success"));
d74d791a 5862 if ( winnings >= 0. )
544593c6 5863 {
d74d791a 5864 if ( winnings > 0. )
5865 {
096cfeb8 5866 if ( params.size() == 3 )
5867 {
5868 result.push_back(Pair("status", "win"));
5869 result.push_back(Pair("won", winnings));
5870 }
5871 else
5872 {
5873 result.push_back(Pair("status", "finalized"));
5874 result.push_back(Pair("n", (int64_t)winnings));
5875 }
3bb6e233 5876 }
5877 else
5878 {
5879 if ( params.size() == 3 )
5880 result.push_back(Pair("status", "loss"));
5881 else result.push_back(Pair("status", "no pending bets"));
5882 }
6ca2e998 5883 } else result.push_back(Pair("status", "bet still pending"));
544593c6 5884 return(result);
5885}
5886
c857567a 5887UniValue dicelist(const UniValue& params, bool fHelp)
fdd22810 5888{
5889 uint256 tokenid;
5890 if ( fHelp || params.size() > 0 )
c857567a 5891 throw runtime_error("dicelist\n");
fdd22810 5892 if ( ensure_CCrequirements() < 0 )
5893 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
c857567a 5894 return(DiceList());
fdd22810 5895}
5896
c857567a 5897UniValue diceinfo(const UniValue& params, bool fHelp)
fdd22810 5898{
5899 uint256 fundingtxid;
5900 if ( fHelp || params.size() != 1 )
c857567a 5901 throw runtime_error("diceinfo fundingtxid\n");
fdd22810 5902 if ( ensure_CCrequirements() < 0 )
5903 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5904 fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
c857567a 5905 return(DiceInfo(fundingtxid));
fdd22810 5906}
5907
c66eb36d 5908UniValue tokenlist(const UniValue& params, bool fHelp)
5909{
5910 uint256 tokenid;
5911 if ( fHelp || params.size() > 0 )
5912 throw runtime_error("tokenlist\n");
5913 if ( ensure_CCrequirements() < 0 )
5914 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5915 return(AssetList());
5916}
5917
5918UniValue tokeninfo(const UniValue& params, bool fHelp)
5919{
5920 uint256 tokenid;
5921 if ( fHelp || params.size() != 1 )
5922 throw runtime_error("tokeninfo tokenid\n");
5923 if ( ensure_CCrequirements() < 0 )
5924 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
5925 tokenid = Parseuint256((char *)params[0].get_str().c_str());
5926 return(AssetInfo(tokenid));
5927}
5928
143488c8 5929UniValue tokenorders(const UniValue& params, bool fHelp)
5930{
5931 uint256 tokenid;
5932 if ( fHelp || params.size() > 1 )
5933 throw runtime_error("tokenorders [tokenid]\n");
e10def86 5934 if ( ensure_CCrequirements() < 0 )
5935 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
143488c8 5936 if ( params.size() == 1 )
5937 tokenid = Parseuint256((char *)params[0].get_str().c_str());
5938 else memset(&tokenid,0,sizeof(tokenid));
5939 return(AssetOrders(tokenid));
5940}
5941
5942UniValue tokenbalance(const UniValue& params, bool fHelp)
5943{
e04b5c08 5944 UniValue result(UniValue::VOBJ); char destaddr[64]; uint256 tokenid; uint64_t balance; std::vector<unsigned char> pubkey; struct CCcontract_info *cp,C;
5945 cp = CCinit(&C,EVAL_ASSETS);
143488c8 5946 if ( fHelp || params.size() > 2 )
5947 throw runtime_error("tokenbalance tokenid [pubkey]\n");
e10def86 5948 if ( ensure_CCrequirements() < 0 )
5949 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 5950 LOCK(cs_main);
143488c8 5951 tokenid = Parseuint256((char *)params[0].get_str().c_str());
5952 if ( params.size() == 2 )
5953 pubkey = ParseHex(params[1].get_str().c_str());
5954 else pubkey = Mypubkey();
5955 result.push_back(Pair("result", "success"));
e04b5c08 5956 if ( GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0 )
143488c8 5957 result.push_back(Pair("CCaddress",destaddr));
bb0c5133 5958 balance = GetAssetBalance(pubkey2pk(pubkey),tokenid);
143488c8 5959 result.push_back(Pair("tokenid", params[0].get_str()));
5960 result.push_back(Pair("balance", (int64_t)balance));
5961 return(result);
5962}
5963
1a02fde9 5964UniValue tokencreate(const UniValue& params, bool fHelp)
5965{
5966 UniValue result(UniValue::VOBJ); std::string name,description,hex; uint64_t supply;
5967 if ( fHelp || params.size() > 3 || params.size() < 2 )
9a579b30 5968 throw runtime_error("tokencreate name supply description\n");
e10def86 5969 if ( ensure_CCrequirements() < 0 )
5970 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 5971 const CKeyStore& keystore = *pwalletMain;
5972 LOCK2(cs_main, pwalletMain->cs_wallet);
246ea3c3 5973 name = params[0].get_str();
1a02fde9 5974 supply = atof(params[1].get_str().c_str()) * COIN;
124819ce 5975 if ( name.size() == 0 || name.size() > 32)
4d47fcb9 5976 {
124819ce
JDL
5977 ERR_RESULT("Token name must not be empty and up to 32 characters");
5978 return(result);
5979 }
5980 if ( supply <= 0 )
5981 {
5982 ERR_RESULT("Token supply must be positive");
4d47fcb9 5983 return(result);
5984 }
1a02fde9 5985 if ( params.size() == 3 )
6ca2e998 5986 {
1a02fde9 5987 description = params[2].get_str();
6ca2e998 5988 if ( description.size() > 4096 )
5989 {
124819ce 5990 ERR_RESULT("Token description must be <= 4096 characters");
6ca2e998 5991 return(result);
5992 }
5993 }
5963c84f 5994 hex = CreateAsset(0,supply,name,description);
1a02fde9 5995 if ( hex.size() > 0 )
5996 {
5997 result.push_back(Pair("result", "success"));
5998 result.push_back(Pair("hex", hex));
8a3e1884 5999 } else ERR_RESULT("couldnt create transaction");
246ea3c3 6000 return(result);
1a02fde9 6001}
6002
6003UniValue tokentransfer(const UniValue& params, bool fHelp)
6004{
8e0ff2b7 6005 UniValue result(UniValue::VOBJ); std::string hex; int64_t amount; uint256 tokenid;
e51e9274 6006 if ( fHelp || params.size() != 3 )
6007 throw runtime_error("tokentransfer tokenid destpubkey amount\n");
e10def86 6008 if ( ensure_CCrequirements() < 0 )
6009 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 6010 const CKeyStore& keystore = *pwalletMain;
6011 LOCK2(cs_main, pwalletMain->cs_wallet);
e51e9274 6012 tokenid = Parseuint256((char *)params[0].get_str().c_str());
6013 std::vector<unsigned char> pubkey(ParseHex(params[1].get_str().c_str()));
6014 amount = atol(params[2].get_str().c_str());
124819ce 6015 if ( tokenid == zeroid )
f6160f58 6016 {
124819ce
JDL
6017 ERR_RESULT("invalid tokenid");
6018 return(result);
6019 }
6020 if ( amount <= 0 )
6021 {
6022 ERR_RESULT("amount must be positive");
f6160f58 6023 return(result);
6024 }
e51e9274 6025 hex = AssetTransfer(0,tokenid,pubkey,amount);
8e0ff2b7
JDL
6026 if (amount > 0) {
6027 if ( hex.size() > 0 )
6028 {
6029 result.push_back(Pair("result", "success"));
6030 result.push_back(Pair("hex", hex));
8a3e1884 6031 } else ERR_RESULT("couldnt transfer assets");
8e0ff2b7
JDL
6032 } else {
6033 ERR_RESULT("amount must be positive");
6034 }
1a02fde9 6035 return(result);
6036}
6037
6038UniValue tokenbid(const UniValue& params, bool fHelp)
6039{
8e0ff2b7 6040 UniValue result(UniValue::VOBJ); int64_t bidamount,numtokens; std::string hex; double price; uint256 tokenid;
5963c84f 6041 if ( fHelp || params.size() != 3 )
6042 throw runtime_error("tokenbid numtokens tokenid price\n");
e10def86 6043 if ( ensure_CCrequirements() < 0 )
6044 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 6045 const CKeyStore& keystore = *pwalletMain;
6046 LOCK2(cs_main, pwalletMain->cs_wallet);
5963c84f 6047 numtokens = atoi(params[0].get_str().c_str());
6a530006 6048 tokenid = Parseuint256((char *)params[1].get_str().c_str());
5963c84f 6049 price = atof(params[2].get_str().c_str());
93e02ad9 6050 bidamount = (price * numtokens) * COIN + 0.0000000049999;
124819ce 6051 if ( price <= 0 )
f6160f58 6052 {
124819ce
JDL
6053 ERR_RESULT("price must be positive");
6054 return(result);
6055 }
6056 if ( tokenid == zeroid )
6057 {
6058 ERR_RESULT("invalid tokenid");
6059 return(result);
6060 }
6061 if ( bidamount <= 0 )
6062 {
6063 ERR_RESULT("bid amount must be positive");
f6160f58 6064 return(result);
6065 }
5963c84f 6066 hex = CreateBuyOffer(0,bidamount,tokenid,numtokens);
8e0ff2b7
JDL
6067 if (price > 0 && numtokens > 0) {
6068 if ( hex.size() > 0 )
6069 {
6070 result.push_back(Pair("result", "success"));
6071 result.push_back(Pair("hex", hex));
124819ce 6072 } else ERR_RESULT("couldnt create bid");
8e0ff2b7
JDL
6073 } else {
6074 ERR_RESULT("price and numtokens must be positive");
6075 }
1a02fde9 6076 return(result);
6077}
6078
6079UniValue tokencancelbid(const UniValue& params, bool fHelp)
6080{
437d6328 6081 UniValue result(UniValue::VOBJ); std::string hex; int32_t i; uint256 tokenid,bidtxid;
6082 if ( fHelp || params.size() != 2 )
6083 throw runtime_error("tokencancelbid tokenid bidtxid\n");
e10def86 6084 if ( ensure_CCrequirements() < 0 )
6085 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 6086 const CKeyStore& keystore = *pwalletMain;
6087 LOCK2(cs_main, pwalletMain->cs_wallet);
437d6328 6088 tokenid = Parseuint256((char *)params[0].get_str().c_str());
6089 bidtxid = Parseuint256((char *)params[1].get_str().c_str());
f6160f58 6090 if ( tokenid == zeroid || bidtxid == zeroid )
6091 {
6092 result.push_back(Pair("error", "invalid parameter"));
6093 return(result);
6094 }
437d6328 6095 hex = CancelBuyOffer(0,tokenid,bidtxid);
cf610814 6096 if ( hex.size() > 0 )
6097 {
6098 result.push_back(Pair("result", "success"));
6099 result.push_back(Pair("hex", hex));
8a3e1884 6100 } else ERR_RESULT("couldnt cancel bid");
1a02fde9 6101 return(result);
6102}
6103
6104UniValue tokenfillbid(const UniValue& params, bool fHelp)
6105{
a03146b3 6106 UniValue result(UniValue::VOBJ); int64_t fillamount; std::string hex; uint256 tokenid,bidtxid;
143488c8 6107 if ( fHelp || params.size() != 3 )
6108 throw runtime_error("tokenfillbid tokenid bidtxid fillamount\n");
e10def86 6109 if ( ensure_CCrequirements() < 0 )
6110 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 6111 const CKeyStore& keystore = *pwalletMain;
6112 LOCK2(cs_main, pwalletMain->cs_wallet);
143488c8 6113 tokenid = Parseuint256((char *)params[0].get_str().c_str());
6114 bidtxid = Parseuint256((char *)params[1].get_str().c_str());
6115 fillamount = atol(params[2].get_str().c_str());
a03146b3 6116 if ( fillamount <= 0 )
f6160f58 6117 {
a03146b3
JDL
6118 ERR_RESULT("fillamount must be positive");
6119 return(result);
6120 }
6121 if ( tokenid == zeroid || bidtxid == zeroid )
6122 {
6123 ERR_RESULT("must provide tokenid and bidtxid");
f6160f58 6124 return(result);
6125 }
143488c8 6126 hex = FillBuyOffer(0,tokenid,bidtxid,fillamount);
6127 if ( hex.size() > 0 )
6128 {
6129 result.push_back(Pair("result", "success"));
6130 result.push_back(Pair("hex", hex));
8a3e1884 6131 } else ERR_RESULT("couldnt fill bid");
143488c8 6132 return(result);
6133}
6134
6135UniValue tokenask(const UniValue& params, bool fHelp)
6136{
8e0ff2b7 6137 UniValue result(UniValue::VOBJ); int64_t askamount,numtokens; std::string hex; double price; uint256 tokenid;
143488c8 6138 if ( fHelp || params.size() != 3 )
6139 throw runtime_error("tokenask numtokens tokenid price\n");
e10def86 6140 if ( ensure_CCrequirements() < 0 )
6141 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 6142 const CKeyStore& keystore = *pwalletMain;
6143 LOCK2(cs_main, pwalletMain->cs_wallet);
143488c8 6144 numtokens = atoi(params[0].get_str().c_str());
6145 tokenid = Parseuint256((char *)params[1].get_str().c_str());
6146 price = atof(params[2].get_str().c_str());
6147 askamount = (price * numtokens) * COIN + 0.0000000049999;
f6160f58 6148 if ( tokenid == zeroid || numtokens <= 0 || price <= 0 || askamount <= 0 )
6149 {
a03146b3 6150 ERR_RESULT("invalid parameter");
f6160f58 6151 return(result);
6152 }
fff7c5d2 6153 hex = CreateSell(0,numtokens,tokenid,askamount);
8e0ff2b7
JDL
6154 if (price > 0 && numtokens > 0) {
6155 if ( hex.size() > 0 )
6156 {
6157 result.push_back(Pair("result", "success"));
6158 result.push_back(Pair("hex", hex));
8a3e1884 6159 } else ERR_RESULT("couldnt create ask");
8e0ff2b7
JDL
6160 } else {
6161 ERR_RESULT("price and numtokens must be positive");
6162 }
143488c8 6163 return(result);
6164}
6165
6166UniValue tokenswapask(const UniValue& params, bool fHelp)
6167{
6168 static uint256 zeroid;
8e0ff2b7 6169 UniValue result(UniValue::VOBJ); int64_t askamount,numtokens; std::string hex; double price; uint256 tokenid,otherid;
e78fa189 6170 if ( fHelp || params.size() != 4 )
c0198c14 6171 throw runtime_error("tokenswapask numtokens tokenid otherid price\n");
e10def86 6172 if ( ensure_CCrequirements() < 0 )
6173 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 6174 const CKeyStore& keystore = *pwalletMain;
6175 LOCK2(cs_main, pwalletMain->cs_wallet);
143488c8 6176 numtokens = atoi(params[0].get_str().c_str());
6177 tokenid = Parseuint256((char *)params[1].get_str().c_str());
6178 otherid = Parseuint256((char *)params[2].get_str().c_str());
6179 price = atof(params[3].get_str().c_str());
fff7c5d2 6180 askamount = (price * numtokens);
6181 hex = CreateSwap(0,numtokens,tokenid,otherid,askamount);
8e0ff2b7
JDL
6182 if (price > 0 && numtokens > 0) {
6183 if ( hex.size() > 0 )
6184 {
6185 result.push_back(Pair("result", "success"));
6186 result.push_back(Pair("hex", hex));
8a3e1884 6187 } else ERR_RESULT("couldnt create swap");
8e0ff2b7
JDL
6188 } else {
6189 ERR_RESULT("price and numtokens must be positive");
6190 }
143488c8 6191 return(result);
6192}
6193
6194UniValue tokencancelask(const UniValue& params, bool fHelp)
6195{
ef2c8deb 6196 UniValue result(UniValue::VOBJ); std::string hex; int32_t i; uint256 tokenid,asktxid;
143488c8 6197 if ( fHelp || params.size() != 2 )
6198 throw runtime_error("tokencancelask tokenid asktxid\n");
e10def86 6199 if ( ensure_CCrequirements() < 0 )
6200 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 6201 const CKeyStore& keystore = *pwalletMain;
6202 LOCK2(cs_main, pwalletMain->cs_wallet);
09c7f7cc 6203 tokenid = Parseuint256((char *)params[0].get_str().c_str());
14708917 6204 asktxid = Parseuint256((char *)params[1].get_str().c_str());
f6160f58 6205 if ( tokenid == zeroid || asktxid == zeroid )
6206 {
6207 result.push_back(Pair("error", "invalid parameter"));
6208 return(result);
6209 }
143488c8 6210 hex = CancelSell(0,tokenid,asktxid);
6211 if ( hex.size() > 0 )
6212 {
6213 result.push_back(Pair("result", "success"));
6214 result.push_back(Pair("hex", hex));
e4f4e63b 6215 } else ERR_RESULT("couldnt cancel ask");
143488c8 6216 return(result);
6217}
6218
6219UniValue tokenfillask(const UniValue& params, bool fHelp)
6220{
a03146b3 6221 UniValue result(UniValue::VOBJ); int64_t fillunits; std::string hex; uint256 tokenid,asktxid;
143488c8 6222 if ( fHelp || params.size() != 3 )
ba8a98f2 6223 throw runtime_error("tokenfillask tokenid asktxid fillunits\n");
e10def86 6224 if ( ensure_CCrequirements() < 0 )
6225 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 6226 const CKeyStore& keystore = *pwalletMain;
6227 LOCK2(cs_main, pwalletMain->cs_wallet);
143488c8 6228 tokenid = Parseuint256((char *)params[0].get_str().c_str());
6229 asktxid = Parseuint256((char *)params[1].get_str().c_str());
ba8a98f2 6230 fillunits = atol(params[2].get_str().c_str());
a03146b3
JDL
6231 if ( fillunits <= 0 )
6232 {
6233 ERR_RESULT("fillunits must be positive");
6234 return(result);
6235 }
6236 if ( tokenid == zeroid || asktxid == zeroid )
f6160f58 6237 {
6238 result.push_back(Pair("error", "invalid parameter"));
6239 return(result);
6240 }
ba8a98f2 6241 hex = FillSell(0,tokenid,zeroid,asktxid,fillunits);
8e0ff2b7 6242 if (fillunits > 0) {
8a3e1884
JDL
6243 if (CCerror != "") {
6244 ERR_RESULT(CCerror);
6245 } else if ( hex.size() > 0) {
8e0ff2b7
JDL
6246 result.push_back(Pair("result", "success"));
6247 result.push_back(Pair("hex", hex));
8a3e1884
JDL
6248 } else {
6249 ERR_RESULT("couldnt fill bid");
6250 }
8e0ff2b7
JDL
6251 } else {
6252 ERR_RESULT("fillunits must be positive");
6253 }
143488c8 6254 return(result);
6255}
6256
6257UniValue tokenfillswap(const UniValue& params, bool fHelp)
6258{
6259 static uint256 zeroid;
8e0ff2b7 6260 UniValue result(UniValue::VOBJ); int64_t fillunits; std::string hex; uint256 tokenid,otherid,asktxid;
143488c8 6261 if ( fHelp || params.size() != 4 )
ba8a98f2 6262 throw runtime_error("tokenfillswap tokenid otherid asktxid fillunits\n");
e10def86 6263 if ( ensure_CCrequirements() < 0 )
6264 throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
b47b1743 6265 const CKeyStore& keystore = *pwalletMain;
6266 LOCK2(cs_main, pwalletMain->cs_wallet);
143488c8 6267 tokenid = Parseuint256((char *)params[0].get_str().c_str());
6268 otherid = Parseuint256((char *)params[1].get_str().c_str());
6269 asktxid = Parseuint256((char *)params[2].get_str().c_str());
ba8a98f2 6270 fillunits = atol(params[3].get_str().c_str());
6271 hex = FillSell(0,tokenid,otherid,asktxid,fillunits);
8e0ff2b7
JDL
6272 if (fillunits > 0) {
6273 if ( hex.size() > 0 ) {
6274 result.push_back(Pair("result", "success"));
6275 result.push_back(Pair("hex", hex));
6276 } else ERR_RESULT("couldnt fill bid");
6277 } else {
6278 ERR_RESULT("fillunits must be positive");
6279 }
1a02fde9 6280 return(result);
6281}
6282
4f02fc40 6283UniValue getbalance64(const UniValue& params, bool fHelp)
6284{
6285 set<CBitcoinAddress> setAddress; vector<COutput> vecOutputs;
5e0b330d 6286 UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR),b(UniValue::VARR); CTxDestination address;
4f02fc40 6287 const CKeyStore& keystore = *pwalletMain;
6288 CAmount nValues[64],nValues2[64],nValue,total,total2; int32_t i,segid;
6289 assert(pwalletMain != NULL);
6290 if (fHelp || params.size() > 0)
6291 throw runtime_error("getbalance64\n");
6292 total = total2 = 0;
6293 memset(nValues,0,sizeof(nValues));
6294 memset(nValues2,0,sizeof(nValues2));
6295 LOCK2(cs_main, pwalletMain->cs_wallet);
6296 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
6297 BOOST_FOREACH(const COutput& out, vecOutputs)
6298 {
6299 nValue = out.tx->vout[out.i].nValue;
5e0b330d 6300 if ( ExtractDestination(out.tx->vout[out.i].scriptPubKey, address) )
4f02fc40 6301 {
ca76a7df 6302 segid = (komodo_segid32((char *)CBitcoinAddress(address).ToString().c_str()) & 0x3f);
4f02fc40 6303 if ( out.nDepth < 100 )
6304 nValues2[segid] += nValue, total2 += nValue;
6305 else nValues[segid] += nValue, total += nValue;
d979952f 6306 //fprintf(stderr,"%s %.8f depth.%d segid.%d\n",(char *)CBitcoinAddress(address).ToString().c_str(),(double)nValue/COIN,(int32_t)out.nDepth,segid);
5e0b330d 6307 } else fprintf(stderr,"no destination\n");
4f02fc40 6308 }
5e0b330d 6309 ret.push_back(Pair("mature",(double)total/COIN));
4f02fc40 6310 ret.push_back(Pair("immature",(double)total2/COIN));
6311 for (i=0; i<64; i++)
6312 {
5e0b330d 6313 a.push_back((uint64_t)nValues[i]);
6314 b.push_back((uint64_t)nValues2[i]);
4f02fc40 6315 }
6316 ret.push_back(Pair("staking", a));
5e0b330d 6317 ret.push_back(Pair("notstaking", b));
4f02fc40 6318 return ret;
6319}
This page took 1.93757 seconds and 4 git commands to generate.