]> Git Repo - VerusCoin.git/blame - src/wallet/rpcwallet.cpp
Add public field 'memo' to JSOutput to enable creation of notes with custom memos.
[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"
ae775b5b 8#include "core_io.h"
e3bc5698 9#include "init.h"
8a893c94 10#include "main.h"
51ed9ec9
BD
11#include "net.h"
12#include "netbase.h"
8a893c94 13#include "rpcserver.h"
14f888ca 14#include "timedata.h"
51ed9ec9 15#include "util.h"
b93173de 16#include "utilmoneystr.h"
51ed9ec9
BD
17#include "wallet.h"
18#include "walletdb.h"
8cb25088 19#include "primitives/transaction.h"
6962bb3d 20#include "zcbenchmarks.h"
6aae9d1a 21#include "script/interpreter.h"
51ed9ec9 22
fc72c078
S
23#include "utiltime.h"
24#include "asyncrpcoperation.h"
25#include "wallet/asyncrpcoperation_sendmany.h"
26
320f2cc7
SB
27#include "sodium.h"
28
51ed9ec9
BD
29#include <stdint.h>
30
31#include <boost/assign/list_of.hpp>
25cf6f3d 32
51ed9ec9
BD
33#include "json/json_spirit_utils.h"
34#include "json/json_spirit_value.h"
fc72c078 35#include "asyncrpcqueue.h"
e3bc5698 36
e3bc5698 37using namespace std;
fdbb537d 38using namespace json_spirit;
e3bc5698 39
2dc35992
SB
40using namespace libzcash;
41
51ed9ec9 42int64_t nWalletUnlockTime;
e3bc5698
JG
43static CCriticalSection cs_nWalletUnlockTime;
44
bdab0cf5 45std::string HelpRequiringPassphrase()
e3bc5698 46{
b0730874 47 return pwalletMain && pwalletMain->IsCrypted()
a6099ef3 48 ? "\nRequires wallet passphrase to be set with walletpassphrase call."
e3bc5698
JG
49 : "";
50}
51
b9fb692d
JS
52bool EnsureWalletIsAvailable(bool avoidException)
53{
54 if (!pwalletMain)
55 {
56 if (!avoidException)
57 throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
58 else
59 return false;
60 }
61 return true;
62}
63
bdab0cf5 64void EnsureWalletIsUnlocked()
e3bc5698
JG
65{
66 if (pwalletMain->IsLocked())
738835d7 67 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
e3bc5698
JG
68}
69
70void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
71{
72 int confirms = wtx.GetDepthInMainChain();
73 entry.push_back(Pair("confirmations", confirms));
e07c8e91
LD
74 if (wtx.IsCoinBase())
75 entry.push_back(Pair("generated", true));
2b72d46f 76 if (confirms > 0)
e3bc5698
JG
77 {
78 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
79 entry.push_back(Pair("blockindex", wtx.nIndex));
209377a7 80 entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
e3bc5698 81 }
805344dc 82 uint256 hash = wtx.GetHash();
731b89b8
GA
83 entry.push_back(Pair("txid", hash.GetHex()));
84 Array conflicts;
85 BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
86 conflicts.push_back(conflict.GetHex());
87 entry.push_back(Pair("walletconflicts", conflicts));
d56e30ca 88 entry.push_back(Pair("time", wtx.GetTxTime()));
4b61a6a4 89 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
e3bc5698
JG
90 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
91 entry.push_back(Pair(item.first, item.second));
92}
93
94string AccountFromValue(const Value& value)
95{
96 string strAccount = value.get_str();
97 if (strAccount == "*")
738835d7 98 throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name");
e3bc5698
JG
99 return strAccount;
100}
101
102Value getnewaddress(const Array& params, bool fHelp)
103{
b9fb692d
JS
104 if (!EnsureWalletIsAvailable(fHelp))
105 return Value::null;
106
e3bc5698
JG
107 if (fHelp || params.size() > 1)
108 throw runtime_error(
a6099ef3 109 "getnewaddress ( \"account\" )\n"
110 "\nReturns a new Bitcoin address for receiving payments.\n"
7b782f5b 111 "If 'account' is specified (DEPRECATED), it is added to the address book \n"
a6099ef3 112 "so payments received with the address will be credited to 'account'.\n"
113 "\nArguments:\n"
91a9fe09 114 "1. \"account\" (string, optional) DEPRECATED. The account name for the address to be linked to. If not provided, the default account \"\" is used. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created if there is no account by the given name.\n"
a6099ef3 115 "\nResult:\n"
116 "\"bitcoinaddress\" (string) The new bitcoin address\n"
117 "\nExamples:\n"
118 + HelpExampleCli("getnewaddress", "")
7b782f5b 119 + HelpExampleRpc("getnewaddress", "")
a6099ef3 120 );
e3bc5698 121
4401b2d7
EL
122 LOCK2(cs_main, pwalletMain->cs_wallet);
123
e3bc5698
JG
124 // Parse the account first so we don't generate a key if there's an error
125 string strAccount;
126 if (params.size() > 0)
127 strAccount = AccountFromValue(params[0]);
128
129 if (!pwalletMain->IsLocked())
130 pwalletMain->TopUpKeyPool();
131
132 // Generate a new key that is added to wallet
133 CPubKey newKey;
71ac5052 134 if (!pwalletMain->GetKeyFromPool(newKey))
738835d7 135 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e3bc5698
JG
136 CKeyID keyID = newKey.GetID();
137
a41d5fe0 138 pwalletMain->SetAddressBook(keyID, strAccount, "receive");
e3bc5698
JG
139
140 return CBitcoinAddress(keyID).ToString();
141}
142
143
144CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
145{
146 CWalletDB walletdb(pwalletMain->strWalletFile);
147
148 CAccount account;
149 walletdb.ReadAccount(strAccount, account);
150
151 bool bKeyUsed = false;
152
153 // Check if the current key has been used
154 if (account.vchPubKey.IsValid())
155 {
0be990ba 156 CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
e3bc5698
JG
157 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
158 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
159 ++it)
160 {
161 const CWalletTx& wtx = (*it).second;
162 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
163 if (txout.scriptPubKey == scriptPubKey)
164 bKeyUsed = true;
165 }
166 }
167
168 // Generate a new key
169 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
170 {
71ac5052 171 if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
738835d7 172 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e3bc5698 173
a41d5fe0 174 pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
e3bc5698
JG
175 walletdb.WriteAccount(strAccount, account);
176 }
177
178 return CBitcoinAddress(account.vchPubKey.GetID());
179}
180
181Value getaccountaddress(const Array& params, bool fHelp)
182{
b9fb692d
JS
183 if (!EnsureWalletIsAvailable(fHelp))
184 return Value::null;
185
e3bc5698
JG
186 if (fHelp || params.size() != 1)
187 throw runtime_error(
a6099ef3 188 "getaccountaddress \"account\"\n"
7b782f5b 189 "\nDEPRECATED. Returns the current Bitcoin address for receiving payments to this account.\n"
a6099ef3 190 "\nArguments:\n"
191 "1. \"account\" (string, required) The account name for the address. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created and a new address created if there is no account by the given name.\n"
192 "\nResult:\n"
193 "\"bitcoinaddress\" (string) The account bitcoin address\n"
194 "\nExamples:\n"
195 + HelpExampleCli("getaccountaddress", "")
196 + HelpExampleCli("getaccountaddress", "\"\"")
197 + HelpExampleCli("getaccountaddress", "\"myaccount\"")
198 + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
199 );
e3bc5698 200
4401b2d7
EL
201 LOCK2(cs_main, pwalletMain->cs_wallet);
202
e3bc5698
JG
203 // Parse the account first so we don't generate a key if there's an error
204 string strAccount = AccountFromValue(params[0]);
205
206 Value ret;
207
208 ret = GetAccountAddress(strAccount).ToString();
e3bc5698
JG
209 return ret;
210}
211
212
e5e9904c
JG
213Value getrawchangeaddress(const Array& params, bool fHelp)
214{
b9fb692d
JS
215 if (!EnsureWalletIsAvailable(fHelp))
216 return Value::null;
217
e5e9904c
JG
218 if (fHelp || params.size() > 1)
219 throw runtime_error(
220 "getrawchangeaddress\n"
a6099ef3 221 "\nReturns a new Bitcoin address, for receiving change.\n"
222 "This is for use with raw transactions, NOT normal use.\n"
223 "\nResult:\n"
224 "\"address\" (string) The address\n"
225 "\nExamples:\n"
226 + HelpExampleCli("getrawchangeaddress", "")
227 + HelpExampleRpc("getrawchangeaddress", "")
228 );
e5e9904c 229
4401b2d7
EL
230 LOCK2(cs_main, pwalletMain->cs_wallet);
231
e5e9904c
JG
232 if (!pwalletMain->IsLocked())
233 pwalletMain->TopUpKeyPool();
234
235 CReserveKey reservekey(pwalletMain);
236 CPubKey vchPubKey;
237 if (!reservekey.GetReservedKey(vchPubKey))
6c37f7fd 238 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e5e9904c
JG
239
240 reservekey.KeepKey();
241
242 CKeyID keyID = vchPubKey.GetID();
243
244 return CBitcoinAddress(keyID).ToString();
245}
246
e3bc5698
JG
247
248Value setaccount(const Array& params, bool fHelp)
249{
b9fb692d
JS
250 if (!EnsureWalletIsAvailable(fHelp))
251 return Value::null;
252
e3bc5698
JG
253 if (fHelp || params.size() < 1 || params.size() > 2)
254 throw runtime_error(
a6099ef3 255 "setaccount \"bitcoinaddress\" \"account\"\n"
7b782f5b 256 "\nDEPRECATED. Sets the account associated with the given address.\n"
a6099ef3 257 "\nArguments:\n"
258 "1. \"bitcoinaddress\" (string, required) The bitcoin address to be associated with an account.\n"
259 "2. \"account\" (string, required) The account to assign the address to.\n"
260 "\nExamples:\n"
261 + HelpExampleCli("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"tabby\"")
262 + HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"tabby\"")
263 );
e3bc5698 264
4401b2d7
EL
265 LOCK2(cs_main, pwalletMain->cs_wallet);
266
e3bc5698
JG
267 CBitcoinAddress address(params[0].get_str());
268 if (!address.IsValid())
738835d7 269 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
e3bc5698 270
e3bc5698
JG
271 string strAccount;
272 if (params.size() > 1)
273 strAccount = AccountFromValue(params[1]);
274
31d6390f
ES
275 // Only add the account if the address is yours.
276 if (IsMine(*pwalletMain, address.Get()))
e3bc5698 277 {
31d6390f
ES
278 // Detect when changing the account of an address that is the 'unused current key' of another account:
279 if (pwalletMain->mapAddressBook.count(address.Get()))
280 {
281 string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name;
282 if (address == GetAccountAddress(strOldAccount))
283 GetAccountAddress(strOldAccount, true);
284 }
285 pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
e3bc5698 286 }
31d6390f
ES
287 else
288 throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
e3bc5698
JG
289
290 return Value::null;
291}
292
293
294Value getaccount(const Array& params, bool fHelp)
295{
b9fb692d
JS
296 if (!EnsureWalletIsAvailable(fHelp))
297 return Value::null;
298
e3bc5698
JG
299 if (fHelp || params.size() != 1)
300 throw runtime_error(
a6099ef3 301 "getaccount \"bitcoinaddress\"\n"
7b782f5b 302 "\nDEPRECATED. Returns the account associated with the given address.\n"
a6099ef3 303 "\nArguments:\n"
304 "1. \"bitcoinaddress\" (string, required) The bitcoin address for account lookup.\n"
305 "\nResult:\n"
306 "\"accountname\" (string) the account address\n"
307 "\nExamples:\n"
308 + HelpExampleCli("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
309 + HelpExampleRpc("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
310 );
e3bc5698 311
4401b2d7
EL
312 LOCK2(cs_main, pwalletMain->cs_wallet);
313
e3bc5698
JG
314 CBitcoinAddress address(params[0].get_str());
315 if (!address.IsValid())
738835d7 316 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
e3bc5698
JG
317
318 string strAccount;
61885513
GA
319 map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
320 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty())
321 strAccount = (*mi).second.name;
e3bc5698
JG
322 return strAccount;
323}
324
325
326Value getaddressesbyaccount(const Array& params, bool fHelp)
327{
b9fb692d
JS
328 if (!EnsureWalletIsAvailable(fHelp))
329 return Value::null;
330
e3bc5698
JG
331 if (fHelp || params.size() != 1)
332 throw runtime_error(
a6099ef3 333 "getaddressesbyaccount \"account\"\n"
7b782f5b 334 "\nDEPRECATED. Returns the list of addresses for the given account.\n"
a6099ef3 335 "\nArguments:\n"
336 "1. \"account\" (string, required) The account name.\n"
337 "\nResult:\n"
338 "[ (json array of string)\n"
339 " \"bitcoinaddress\" (string) a bitcoin address associated with the given account\n"
340 " ,...\n"
341 "]\n"
342 "\nExamples:\n"
343 + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
344 + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
345 );
e3bc5698 346
4401b2d7
EL
347 LOCK2(cs_main, pwalletMain->cs_wallet);
348
e3bc5698
JG
349 string strAccount = AccountFromValue(params[0]);
350
351 // Find all addresses that have the given account
352 Array ret;
61885513 353 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
e3bc5698
JG
354 {
355 const CBitcoinAddress& address = item.first;
61885513 356 const string& strName = item.second.name;
e3bc5698
JG
357 if (strName == strAccount)
358 ret.push_back(address.ToString());
359 }
360 return ret;
361}
362
292623ad 363static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew)
b93173de 364{
25cf6f3d
PK
365 CAmount curBalance = pwalletMain->GetBalance();
366
b93173de
PJ
367 // Check amount
368 if (nValue <= 0)
4be639ea 369 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
b93173de 370
25cf6f3d 371 if (nValue > curBalance)
b93173de
PJ
372 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
373
b93173de
PJ
374 // Parse Bitcoin address
375 CScript scriptPubKey = GetScriptForDestination(address);
376
377 // Create and send the transaction
378 CReserveKey reservekey(pwalletMain);
379 CAmount nFeeRequired;
25cf6f3d 380 std::string strError;
292623ad
CL
381 vector<CRecipient> vecSend;
382 int nChangePosRet = -1;
383 CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
384 vecSend.push_back(recipient);
385 if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
386 if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
387 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));
388 throw JSONRPCError(RPC_WALLET_ERROR, strError);
b93173de
PJ
389 }
390 if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
391 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
392}
393
e3bc5698
JG
394Value sendtoaddress(const Array& params, bool fHelp)
395{
b9fb692d
JS
396 if (!EnsureWalletIsAvailable(fHelp))
397 return Value::null;
398
292623ad 399 if (fHelp || params.size() < 2 || params.size() > 5)
e3bc5698 400 throw runtime_error(
292623ad 401 "sendtoaddress \"bitcoinaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
e743678d 402 "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
a6099ef3 403 + HelpRequiringPassphrase() +
404 "\nArguments:\n"
405 "1. \"bitcoinaddress\" (string, required) The bitcoin address to send to.\n"
406 "2. \"amount\" (numeric, required) The amount in btc to send. eg 0.1\n"
407 "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
408 " This is not part of the transaction, just kept in your wallet.\n"
409 "4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
410 " to which you're sending the transaction. This is not part of the \n"
411 " transaction, just kept in your wallet.\n"
292623ad
CL
412 "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
413 " The recipient will receive less bitcoins than you enter in the amount field.\n"
a6099ef3 414 "\nResult:\n"
b5ef85c7 415 "\"transactionid\" (string) The transaction id.\n"
a6099ef3 416 "\nExamples:\n"
417 + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
418 + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"donation\" \"seans outpost\"")
292623ad 419 + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"\" \"\" true")
a6099ef3 420 + HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
421 );
e3bc5698 422
4401b2d7
EL
423 LOCK2(cs_main, pwalletMain->cs_wallet);
424
e3bc5698
JG
425 CBitcoinAddress address(params[0].get_str());
426 if (!address.IsValid())
738835d7 427 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
e3bc5698
JG
428
429 // Amount
a372168e 430 CAmount nAmount = AmountFromValue(params[1]);
e3bc5698
JG
431
432 // Wallet comments
433 CWalletTx wtx;
434 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
435 wtx.mapValue["comment"] = params[2].get_str();
436 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
437 wtx.mapValue["to"] = params[3].get_str();
438
292623ad
CL
439 bool fSubtractFeeFromAmount = false;
440 if (params.size() > 4)
441 fSubtractFeeFromAmount = params[4].get_bool();
442
f914c7a1 443 EnsureWalletIsUnlocked();
e3bc5698 444
292623ad 445 SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, wtx);
e3bc5698 446
805344dc 447 return wtx.GetHash().GetHex();
e3bc5698
JG
448}
449
22dfd735 450Value listaddressgroupings(const Array& params, bool fHelp)
451{
b9fb692d
JS
452 if (!EnsureWalletIsAvailable(fHelp))
453 return Value::null;
454
22dfd735 455 if (fHelp)
b1093efa
GM
456 throw runtime_error(
457 "listaddressgroupings\n"
a6099ef3 458 "\nLists groups of addresses which have had their common ownership\n"
b1093efa 459 "made public by common use as inputs or as the resulting change\n"
a6099ef3 460 "in past transactions\n"
461 "\nResult:\n"
462 "[\n"
463 " [\n"
464 " [\n"
465 " \"bitcoinaddress\", (string) The bitcoin address\n"
466 " amount, (numeric) The amount in btc\n"
7b782f5b 467 " \"account\" (string, optional) The account (DEPRECATED)\n"
a6099ef3 468 " ]\n"
469 " ,...\n"
470 " ]\n"
471 " ,...\n"
472 "]\n"
473 "\nExamples:\n"
474 + HelpExampleCli("listaddressgroupings", "")
475 + HelpExampleRpc("listaddressgroupings", "")
476 );
22dfd735 477
4401b2d7
EL
478 LOCK2(cs_main, pwalletMain->cs_wallet);
479
22dfd735 480 Array jsonGroupings;
a372168e 481 map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
b1093efa 482 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
22dfd735 483 {
484 Array jsonGrouping;
b1093efa 485 BOOST_FOREACH(CTxDestination address, grouping)
22dfd735 486 {
487 Array addressInfo;
b1093efa 488 addressInfo.push_back(CBitcoinAddress(address).ToString());
22dfd735 489 addressInfo.push_back(ValueFromAmount(balances[address]));
490 {
22dfd735 491 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
61885513 492 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
22dfd735 493 }
494 jsonGrouping.push_back(addressInfo);
495 }
496 jsonGroupings.push_back(jsonGrouping);
497 }
498 return jsonGroupings;
499}
500
e3bc5698
JG
501Value signmessage(const Array& params, bool fHelp)
502{
b9fb692d
JS
503 if (!EnsureWalletIsAvailable(fHelp))
504 return Value::null;
505
e3bc5698
JG
506 if (fHelp || params.size() != 2)
507 throw runtime_error(
a6099ef3 508 "signmessage \"bitcoinaddress\" \"message\"\n"
509 "\nSign a message with the private key of an address"
510 + HelpRequiringPassphrase() + "\n"
511 "\nArguments:\n"
512 "1. \"bitcoinaddress\" (string, required) The bitcoin address to use for the private key.\n"
513 "2. \"message\" (string, required) The message to create a signature of.\n"
514 "\nResult:\n"
515 "\"signature\" (string) The signature of the message encoded in base 64\n"
516 "\nExamples:\n"
517 "\nUnlock the wallet for 30 seconds\n"
518 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
519 "\nCreate the signature\n"
520 + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
521 "\nVerify the signature\n"
522 + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
523 "\nAs json rpc\n"
524 + HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"my message\"")
525 );
e3bc5698 526
4401b2d7
EL
527 LOCK2(cs_main, pwalletMain->cs_wallet);
528
e3bc5698
JG
529 EnsureWalletIsUnlocked();
530
531 string strAddress = params[0].get_str();
532 string strMessage = params[1].get_str();
533
534 CBitcoinAddress addr(strAddress);
535 if (!addr.IsValid())
738835d7 536 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
e3bc5698
JG
537
538 CKeyID keyID;
539 if (!addr.GetKeyID(keyID))
738835d7 540 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
e3bc5698
JG
541
542 CKey key;
543 if (!pwalletMain->GetKey(keyID, key))
738835d7 544 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
e3bc5698 545
8980a509 546 CHashWriter ss(SER_GETHASH, 0);
e3bc5698
JG
547 ss << strMessageMagic;
548 ss << strMessage;
549
550 vector<unsigned char> vchSig;
8980a509 551 if (!key.SignCompact(ss.GetHash(), vchSig))
738835d7 552 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
e3bc5698
JG
553
554 return EncodeBase64(&vchSig[0], vchSig.size());
555}
556
e3bc5698
JG
557Value getreceivedbyaddress(const Array& params, bool fHelp)
558{
b9fb692d
JS
559 if (!EnsureWalletIsAvailable(fHelp))
560 return Value::null;
561
e3bc5698
JG
562 if (fHelp || params.size() < 1 || params.size() > 2)
563 throw runtime_error(
a6099ef3 564 "getreceivedbyaddress \"bitcoinaddress\" ( minconf )\n"
565 "\nReturns the total amount received by the given bitcoinaddress in transactions with at least minconf confirmations.\n"
566 "\nArguments:\n"
567 "1. \"bitcoinaddress\" (string, required) The bitcoin address for transactions.\n"
568 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
569 "\nResult:\n"
570 "amount (numeric) The total amount in btc received at this address.\n"
571 "\nExamples:\n"
572 "\nThe amount from transactions with at least 1 confirmation\n"
573 + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"") +
574 "\nThe amount including unconfirmed transactions, zero confirmations\n"
575 + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" 0") +
576 "\nThe amount with at least 6 confirmation, very safe\n"
577 + HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" 6") +
578 "\nAs a json rpc call\n"
579 + HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", 6")
580 );
e3bc5698 581
4401b2d7
EL
582 LOCK2(cs_main, pwalletMain->cs_wallet);
583
e3bc5698
JG
584 // Bitcoin address
585 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
e3bc5698 586 if (!address.IsValid())
738835d7 587 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
0be990ba 588 CScript scriptPubKey = GetScriptForDestination(address.Get());
e3bc5698
JG
589 if (!IsMine(*pwalletMain,scriptPubKey))
590 return (double)0.0;
591
592 // Minimum confirmations
593 int nMinDepth = 1;
594 if (params.size() > 1)
595 nMinDepth = params[1].get_int();
596
597 // Tally
a372168e 598 CAmount nAmount = 0;
e3bc5698
JG
599 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
600 {
601 const CWalletTx& wtx = (*it).second;
75a4d512 602 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
603 continue;
604
605 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
606 if (txout.scriptPubKey == scriptPubKey)
607 if (wtx.GetDepthInMainChain() >= nMinDepth)
608 nAmount += txout.nValue;
609 }
610
611 return ValueFromAmount(nAmount);
612}
613
614
e3bc5698
JG
615Value getreceivedbyaccount(const Array& params, bool fHelp)
616{
b9fb692d
JS
617 if (!EnsureWalletIsAvailable(fHelp))
618 return Value::null;
619
e3bc5698
JG
620 if (fHelp || params.size() < 1 || params.size() > 2)
621 throw runtime_error(
a6099ef3 622 "getreceivedbyaccount \"account\" ( minconf )\n"
7b782f5b 623 "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
a6099ef3 624 "\nArguments:\n"
625 "1. \"account\" (string, required) The selected account, may be the default account using \"\".\n"
626 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
627 "\nResult:\n"
628 "amount (numeric) The total amount in btc received for this account.\n"
629 "\nExamples:\n"
630 "\nAmount received by the default account with at least 1 confirmation\n"
631 + HelpExampleCli("getreceivedbyaccount", "\"\"") +
632 "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
633 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
634 "\nThe amount with at least 6 confirmation, very safe\n"
635 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
636 "\nAs a json rpc call\n"
637 + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
638 );
e3bc5698 639
4401b2d7
EL
640 LOCK2(cs_main, pwalletMain->cs_wallet);
641
e3bc5698
JG
642 // Minimum confirmations
643 int nMinDepth = 1;
644 if (params.size() > 1)
645 nMinDepth = params[1].get_int();
646
647 // Get the set of pub keys assigned to account
648 string strAccount = AccountFromValue(params[0]);
3624356e 649 set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
e3bc5698
JG
650
651 // Tally
a372168e 652 CAmount nAmount = 0;
e3bc5698
JG
653 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
654 {
655 const CWalletTx& wtx = (*it).second;
75a4d512 656 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
657 continue;
658
659 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
660 {
661 CTxDestination address;
662 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
663 if (wtx.GetDepthInMainChain() >= nMinDepth)
664 nAmount += txout.nValue;
665 }
666 }
667
668 return (double)nAmount / (double)COIN;
669}
670
671
a372168e 672CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
e3bc5698 673{
a372168e 674 CAmount nBalance = 0;
e3bc5698
JG
675
676 // Tally wallet transactions
677 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
678 {
679 const CWalletTx& wtx = (*it).second;
75a4d512 680 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
e3bc5698
JG
681 continue;
682
a372168e 683 CAmount nReceived, nSent, nFee;
d4640d7d 684 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
e3bc5698
JG
685
686 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
687 nBalance += nReceived;
e07c8e91 688 nBalance -= nSent + nFee;
e3bc5698
JG
689 }
690
691 // Tally internal accounting entries
692 nBalance += walletdb.GetAccountCreditDebit(strAccount);
693
694 return nBalance;
695}
696
a372168e 697CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
e3bc5698
JG
698{
699 CWalletDB walletdb(pwalletMain->strWalletFile);
d4640d7d 700 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
e3bc5698
JG
701}
702
703
704Value getbalance(const Array& params, bool fHelp)
705{
b9fb692d
JS
706 if (!EnsureWalletIsAvailable(fHelp))
707 return Value::null;
708
d4640d7d 709 if (fHelp || params.size() > 3)
e3bc5698 710 throw runtime_error(
d4640d7d 711 "getbalance ( \"account\" minconf includeWatchonly )\n"
a6099ef3 712 "\nIf account is not specified, returns the server's total available balance.\n"
7b782f5b 713 "If account is specified (DEPRECATED), returns the balance in the account.\n"
a6099ef3 714 "Note that the account \"\" is not the same as leaving the parameter out.\n"
715 "The server total may be different to the balance in the default \"\" account.\n"
716 "\nArguments:\n"
7b782f5b 717 "1. \"account\" (string, optional) DEPRECATED. The selected account, or \"*\" for entire wallet. It may be the default account using \"\".\n"
a6099ef3 718 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
d4640d7d 719 "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
a6099ef3 720 "\nResult:\n"
721 "amount (numeric) The total amount in btc received for this account.\n"
722 "\nExamples:\n"
7b782f5b 723 "\nThe total amount in the wallet\n"
a6099ef3 724 + HelpExampleCli("getbalance", "") +
7b782f5b 725 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3cf1f436 726 + HelpExampleCli("getbalance", "\"*\" 6") +
a6099ef3 727 "\nAs a json rpc call\n"
7b782f5b 728 + HelpExampleRpc("getbalance", "\"*\", 6")
a6099ef3 729 );
e3bc5698 730
4401b2d7
EL
731 LOCK2(cs_main, pwalletMain->cs_wallet);
732
e3bc5698
JG
733 if (params.size() == 0)
734 return ValueFromAmount(pwalletMain->GetBalance());
735
736 int nMinDepth = 1;
737 if (params.size() > 1)
738 nMinDepth = params[1].get_int();
a3e192a3 739 isminefilter filter = ISMINE_SPENDABLE;
a5c6c5d6
J
740 if(params.size() > 2)
741 if(params[2].get_bool())
a3e192a3 742 filter = filter | ISMINE_WATCH_ONLY;
e3bc5698
JG
743
744 if (params[0].get_str() == "*") {
745 // Calculate total balance a different way from GetBalance()
746 // (GetBalance() sums up all unspent TxOuts)
c9fd9078 747 // getbalance and "getbalance * 1 true" should return the same number
a372168e 748 CAmount nBalance = 0;
e3bc5698
JG
749 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
750 {
751 const CWalletTx& wtx = (*it).second;
c9fd9078 752 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
e3bc5698
JG
753 continue;
754
a372168e 755 CAmount allFee;
e3bc5698 756 string strSentAccount;
1b4568cb
CL
757 list<COutputEntry> listReceived;
758 list<COutputEntry> listSent;
d4640d7d 759 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
e3bc5698
JG
760 if (wtx.GetDepthInMainChain() >= nMinDepth)
761 {
1b4568cb
CL
762 BOOST_FOREACH(const COutputEntry& r, listReceived)
763 nBalance += r.amount;
e3bc5698 764 }
1b4568cb
CL
765 BOOST_FOREACH(const COutputEntry& s, listSent)
766 nBalance -= s.amount;
e3bc5698 767 nBalance -= allFee;
e3bc5698
JG
768 }
769 return ValueFromAmount(nBalance);
770 }
771
772 string strAccount = AccountFromValue(params[0]);
773
a372168e 774 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
e3bc5698
JG
775
776 return ValueFromAmount(nBalance);
777}
778
6027b460
MB
779Value getunconfirmedbalance(const Array &params, bool fHelp)
780{
b9fb692d
JS
781 if (!EnsureWalletIsAvailable(fHelp))
782 return Value::null;
783
6027b460
MB
784 if (fHelp || params.size() > 0)
785 throw runtime_error(
786 "getunconfirmedbalance\n"
787 "Returns the server's total unconfirmed balance\n");
4401b2d7
EL
788
789 LOCK2(cs_main, pwalletMain->cs_wallet);
790
6027b460
MB
791 return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
792}
793
e3bc5698
JG
794
795Value movecmd(const Array& params, bool fHelp)
796{
b9fb692d
JS
797 if (!EnsureWalletIsAvailable(fHelp))
798 return Value::null;
799
e3bc5698
JG
800 if (fHelp || params.size() < 3 || params.size() > 5)
801 throw runtime_error(
a6099ef3 802 "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
7b782f5b 803 "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
a6099ef3 804 "\nArguments:\n"
805 "1. \"fromaccount\" (string, required) The name of the account to move funds from. May be the default account using \"\".\n"
806 "2. \"toaccount\" (string, required) The name of the account to move funds to. May be the default account using \"\".\n"
807 "3. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
808 "4. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
809 "\nResult:\n"
45bfa137 810 "true|false (boolean) true if successful.\n"
a6099ef3 811 "\nExamples:\n"
812 "\nMove 0.01 btc from the default account to the account named tabby\n"
813 + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
814 "\nMove 0.01 btc timotei to akiko with a comment and funds have 6 confirmations\n"
815 + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
816 "\nAs a json rpc call\n"
817 + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
818 );
e3bc5698 819
4401b2d7
EL
820 LOCK2(cs_main, pwalletMain->cs_wallet);
821
e3bc5698
JG
822 string strFrom = AccountFromValue(params[0]);
823 string strTo = AccountFromValue(params[1]);
a372168e 824 CAmount nAmount = AmountFromValue(params[2]);
e3bc5698
JG
825 if (params.size() > 3)
826 // unused parameter, used to be nMinDepth, keep type-checking it though
827 (void)params[3].get_int();
828 string strComment;
829 if (params.size() > 4)
830 strComment = params[4].get_str();
831
832 CWalletDB walletdb(pwalletMain->strWalletFile);
833 if (!walletdb.TxnBegin())
738835d7 834 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
e3bc5698 835
51ed9ec9 836 int64_t nNow = GetAdjustedTime();
e3bc5698
JG
837
838 // Debit
839 CAccountingEntry debit;
4291e8fe 840 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
e3bc5698
JG
841 debit.strAccount = strFrom;
842 debit.nCreditDebit = -nAmount;
843 debit.nTime = nNow;
844 debit.strOtherAccount = strTo;
845 debit.strComment = strComment;
846 walletdb.WriteAccountingEntry(debit);
847
848 // Credit
849 CAccountingEntry credit;
4291e8fe 850 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
e3bc5698
JG
851 credit.strAccount = strTo;
852 credit.nCreditDebit = nAmount;
853 credit.nTime = nNow;
854 credit.strOtherAccount = strFrom;
855 credit.strComment = strComment;
856 walletdb.WriteAccountingEntry(credit);
857
858 if (!walletdb.TxnCommit())
738835d7 859 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
e3bc5698
JG
860
861 return true;
862}
863
864
865Value sendfrom(const Array& params, bool fHelp)
866{
b9fb692d
JS
867 if (!EnsureWalletIsAvailable(fHelp))
868 return Value::null;
869
e3bc5698
JG
870 if (fHelp || params.size() < 3 || params.size() > 6)
871 throw runtime_error(
a6099ef3 872 "sendfrom \"fromaccount\" \"tobitcoinaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
7b782f5b 873 "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a bitcoin address.\n"
a6099ef3 874 "The amount is a real and is rounded to the nearest 0.00000001."
875 + HelpRequiringPassphrase() + "\n"
876 "\nArguments:\n"
877 "1. \"fromaccount\" (string, required) The name of the account to send funds from. May be the default account using \"\".\n"
878 "2. \"tobitcoinaddress\" (string, required) The bitcoin address to send funds to.\n"
879 "3. amount (numeric, required) The amount in btc. (transaction fee is added on top).\n"
880 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
881 "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
882 " This is not part of the transaction, just kept in your wallet.\n"
883 "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n"
884 " to which you're sending the transaction. This is not part of the transaction, \n"
885 " it is just kept in your wallet.\n"
886 "\nResult:\n"
b5ef85c7 887 "\"transactionid\" (string) The transaction id.\n"
a6099ef3 888 "\nExamples:\n"
889 "\nSend 0.01 btc from the default account to the address, must have at least 1 confirmation\n"
890 + HelpExampleCli("sendfrom", "\"\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
891 "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
892 + HelpExampleCli("sendfrom", "\"tabby\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01 6 \"donation\" \"seans outpost\"") +
893 "\nAs a json rpc call\n"
894 + HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
895 );
e3bc5698 896
4401b2d7
EL
897 LOCK2(cs_main, pwalletMain->cs_wallet);
898
e3bc5698
JG
899 string strAccount = AccountFromValue(params[0]);
900 CBitcoinAddress address(params[1].get_str());
901 if (!address.IsValid())
738835d7 902 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
a372168e 903 CAmount nAmount = AmountFromValue(params[2]);
e3bc5698
JG
904 int nMinDepth = 1;
905 if (params.size() > 3)
906 nMinDepth = params[3].get_int();
907
908 CWalletTx wtx;
909 wtx.strFromAccount = strAccount;
910 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
911 wtx.mapValue["comment"] = params[4].get_str();
912 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
913 wtx.mapValue["to"] = params[5].get_str();
914
915 EnsureWalletIsUnlocked();
916
917 // Check funds
a372168e 918 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
e3bc5698 919 if (nAmount > nBalance)
738835d7 920 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
e3bc5698 921
292623ad 922 SendMoney(address.Get(), nAmount, false, wtx);
e3bc5698 923
805344dc 924 return wtx.GetHash().GetHex();
e3bc5698
JG
925}
926
927
928Value sendmany(const Array& params, bool fHelp)
929{
b9fb692d
JS
930 if (!EnsureWalletIsAvailable(fHelp))
931 return Value::null;
932
292623ad 933 if (fHelp || params.size() < 2 || params.size() > 5)
e3bc5698 934 throw runtime_error(
40a75733 935 "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
a6099ef3 936 "\nSend multiple times. Amounts are double-precision floating point numbers."
937 + HelpRequiringPassphrase() + "\n"
938 "\nArguments:\n"
7b782f5b 939 "1. \"fromaccount\" (string, required) DEPRECATED. The account to send the funds from. Should be \"\" for the default account\n"
a6099ef3 940 "2. \"amounts\" (string, required) A json object with addresses and amounts\n"
941 " {\n"
942 " \"address\":amount (numeric) The bitcoin address is the key, the numeric amount in btc is the value\n"
943 " ,...\n"
944 " }\n"
945 "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
946 "4. \"comment\" (string, optional) A comment\n"
40a75733 947 "5. subtractfeefromamount (string, optional) A json array with addresses.\n"
292623ad
CL
948 " The fee will be equally deducted from the amount of each selected address.\n"
949 " Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
40a75733
LD
950 " If no addresses are specified here, the sender pays the fee.\n"
951 " [\n"
952 " \"address\" (string) Subtract fee from this address\n"
292623ad 953 " ,...\n"
40a75733 954 " ]\n"
a6099ef3 955 "\nResult:\n"
956 "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
b5ef85c7 957 " the number of addresses.\n"
a6099ef3 958 "\nExamples:\n"
959 "\nSend two amounts to two different addresses:\n"
7b782f5b 960 + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
a6099ef3 961 "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
7b782f5b 962 + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
292623ad 963 "\nSend two amounts to two different addresses, subtract fee from amount:\n"
40a75733 964 + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\",\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
a6099ef3 965 "\nAs a json rpc call\n"
7b782f5b 966 + HelpExampleRpc("sendmany", "\"\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
a6099ef3 967 );
e3bc5698 968
4401b2d7
EL
969 LOCK2(cs_main, pwalletMain->cs_wallet);
970
e3bc5698
JG
971 string strAccount = AccountFromValue(params[0]);
972 Object sendTo = params[1].get_obj();
973 int nMinDepth = 1;
974 if (params.size() > 2)
975 nMinDepth = params[2].get_int();
976
977 CWalletTx wtx;
978 wtx.strFromAccount = strAccount;
979 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
980 wtx.mapValue["comment"] = params[3].get_str();
981
40a75733 982 Array subtractFeeFromAmount;
292623ad 983 if (params.size() > 4)
40a75733 984 subtractFeeFromAmount = params[4].get_array();
292623ad 985
e3bc5698 986 set<CBitcoinAddress> setAddress;
292623ad 987 vector<CRecipient> vecSend;
e3bc5698 988
a372168e 989 CAmount totalAmount = 0;
e3bc5698
JG
990 BOOST_FOREACH(const Pair& s, sendTo)
991 {
992 CBitcoinAddress address(s.name_);
993 if (!address.IsValid())
738835d7 994 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
e3bc5698
JG
995
996 if (setAddress.count(address))
738835d7 997 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
e3bc5698
JG
998 setAddress.insert(address);
999
0be990ba 1000 CScript scriptPubKey = GetScriptForDestination(address.Get());
a372168e 1001 CAmount nAmount = AmountFromValue(s.value_);
e3bc5698
JG
1002 totalAmount += nAmount;
1003
292623ad 1004 bool fSubtractFeeFromAmount = false;
40a75733
LD
1005 BOOST_FOREACH(const Value& addr, subtractFeeFromAmount)
1006 if (addr.get_str() == s.name_)
292623ad
CL
1007 fSubtractFeeFromAmount = true;
1008
1009 CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
1010 vecSend.push_back(recipient);
e3bc5698
JG
1011 }
1012
1013 EnsureWalletIsUnlocked();
1014
1015 // Check funds
a372168e 1016 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
e3bc5698 1017 if (totalAmount > nBalance)
738835d7 1018 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
e3bc5698
JG
1019
1020 // Send
1021 CReserveKey keyChange(pwalletMain);
a372168e 1022 CAmount nFeeRequired = 0;
292623ad 1023 int nChangePosRet = -1;
1f00f4e9 1024 string strFailReason;
292623ad 1025 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
e3bc5698 1026 if (!fCreated)
1f00f4e9 1027 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
e3bc5698 1028 if (!pwalletMain->CommitTransaction(wtx, keyChange))
738835d7 1029 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
e3bc5698 1030
805344dc 1031 return wtx.GetHash().GetHex();
e3bc5698
JG
1032}
1033
723a03d2 1034// Defined in rpcmisc.cpp
787ee0c9 1035extern CScript _createmultisig_redeemScript(const Array& params);
34226be7
GA
1036
1037Value addmultisigaddress(const Array& params, bool fHelp)
1038{
b9fb692d
JS
1039 if (!EnsureWalletIsAvailable(fHelp))
1040 return Value::null;
1041
34226be7
GA
1042 if (fHelp || params.size() < 2 || params.size() > 3)
1043 {
a6099ef3 1044 string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
1045 "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
1046 "Each key is a Bitcoin address or hex-encoded public key.\n"
7b782f5b 1047 "If 'account' is specified (DEPRECATED), assign address to that account.\n"
a6099ef3 1048
1049 "\nArguments:\n"
1050 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
1051 "2. \"keysobject\" (string, required) A json array of bitcoin addresses or hex-encoded public keys\n"
1052 " [\n"
1053 " \"address\" (string) bitcoin address or hex-encoded public key\n"
1054 " ...,\n"
1055 " ]\n"
7b782f5b 1056 "3. \"account\" (string, optional) DEPRECATED. An account to assign the addresses to.\n"
a6099ef3 1057
1058 "\nResult:\n"
1059 "\"bitcoinaddress\" (string) A bitcoin address associated with the keys.\n"
1060
1061 "\nExamples:\n"
1062 "\nAdd a multisig address from 2 addresses\n"
1063 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
1064 "\nAs json rpc call\n"
1065 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
1066 ;
34226be7
GA
1067 throw runtime_error(msg);
1068 }
1069
4401b2d7
EL
1070 LOCK2(cs_main, pwalletMain->cs_wallet);
1071
34226be7
GA
1072 string strAccount;
1073 if (params.size() > 2)
1074 strAccount = AccountFromValue(params[2]);
e3bc5698
JG
1075
1076 // Construct using pay-to-script-hash:
787ee0c9 1077 CScript inner = _createmultisig_redeemScript(params);
066e2a14 1078 CScriptID innerID(inner);
e3bc5698
JG
1079 pwalletMain->AddCScript(inner);
1080
a41d5fe0 1081 pwalletMain->SetAddressBook(innerID, strAccount, "send");
e3bc5698
JG
1082 return CBitcoinAddress(innerID).ToString();
1083}
1084
1085
1086struct tallyitem
1087{
a372168e 1088 CAmount nAmount;
e3bc5698 1089 int nConf;
62c9b115 1090 vector<uint256> txids;
0fa2f889 1091 bool fIsWatchonly;
e3bc5698
JG
1092 tallyitem()
1093 {
1094 nAmount = 0;
1095 nConf = std::numeric_limits<int>::max();
0fa2f889 1096 fIsWatchonly = false;
e3bc5698
JG
1097 }
1098};
1099
1100Value ListReceived(const Array& params, bool fByAccounts)
1101{
1102 // Minimum confirmations
1103 int nMinDepth = 1;
1104 if (params.size() > 0)
1105 nMinDepth = params[0].get_int();
1106
1107 // Whether to include empty accounts
1108 bool fIncludeEmpty = false;
1109 if (params.size() > 1)
1110 fIncludeEmpty = params[1].get_bool();
1111
a3e192a3 1112 isminefilter filter = ISMINE_SPENDABLE;
0fa2f889
J
1113 if(params.size() > 2)
1114 if(params[2].get_bool())
a3e192a3 1115 filter = filter | ISMINE_WATCH_ONLY;
0fa2f889 1116
e3bc5698
JG
1117 // Tally
1118 map<CBitcoinAddress, tallyitem> mapTally;
1119 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1120 {
1121 const CWalletTx& wtx = (*it).second;
1122
75a4d512 1123 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
1124 continue;
1125
1126 int nDepth = wtx.GetDepthInMainChain();
1127 if (nDepth < nMinDepth)
1128 continue;
1129
1130 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1131 {
1132 CTxDestination address;
0fa2f889
J
1133 if (!ExtractDestination(txout.scriptPubKey, address))
1134 continue;
1135
1136 isminefilter mine = IsMine(*pwalletMain, address);
f28707a8 1137 if(!(mine & filter))
e3bc5698
JG
1138 continue;
1139
1140 tallyitem& item = mapTally[address];
1141 item.nAmount += txout.nValue;
1142 item.nConf = min(item.nConf, nDepth);
805344dc 1143 item.txids.push_back(wtx.GetHash());
a3e192a3 1144 if (mine & ISMINE_WATCH_ONLY)
0fa2f889 1145 item.fIsWatchonly = true;
e3bc5698
JG
1146 }
1147 }
1148
1149 // Reply
1150 Array ret;
1151 map<string, tallyitem> mapAccountTally;
61885513 1152 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
e3bc5698
JG
1153 {
1154 const CBitcoinAddress& address = item.first;
61885513 1155 const string& strAccount = item.second.name;
e3bc5698
JG
1156 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1157 if (it == mapTally.end() && !fIncludeEmpty)
1158 continue;
1159
a372168e 1160 CAmount nAmount = 0;
e3bc5698 1161 int nConf = std::numeric_limits<int>::max();
0fa2f889 1162 bool fIsWatchonly = false;
e3bc5698
JG
1163 if (it != mapTally.end())
1164 {
1165 nAmount = (*it).second.nAmount;
1166 nConf = (*it).second.nConf;
0fa2f889 1167 fIsWatchonly = (*it).second.fIsWatchonly;
e3bc5698
JG
1168 }
1169
1170 if (fByAccounts)
1171 {
1172 tallyitem& item = mapAccountTally[strAccount];
1173 item.nAmount += nAmount;
1174 item.nConf = min(item.nConf, nConf);
0fa2f889 1175 item.fIsWatchonly = fIsWatchonly;
e3bc5698
JG
1176 }
1177 else
1178 {
1179 Object obj;
0fa2f889
J
1180 if(fIsWatchonly)
1181 obj.push_back(Pair("involvesWatchonly", true));
e3bc5698
JG
1182 obj.push_back(Pair("address", address.ToString()));
1183 obj.push_back(Pair("account", strAccount));
1184 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1185 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
62c9b115 1186 Array transactions;
1a204694 1187 if (it != mapTally.end())
62c9b115 1188 {
1a204694
A
1189 BOOST_FOREACH(const uint256& item, (*it).second.txids)
1190 {
1191 transactions.push_back(item.GetHex());
1192 }
62c9b115
A
1193 }
1194 obj.push_back(Pair("txids", transactions));
e3bc5698
JG
1195 ret.push_back(obj);
1196 }
1197 }
1198
1199 if (fByAccounts)
1200 {
1201 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1202 {
a372168e 1203 CAmount nAmount = (*it).second.nAmount;
e3bc5698
JG
1204 int nConf = (*it).second.nConf;
1205 Object obj;
0fa2f889
J
1206 if((*it).second.fIsWatchonly)
1207 obj.push_back(Pair("involvesWatchonly", true));
e3bc5698
JG
1208 obj.push_back(Pair("account", (*it).first));
1209 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1210 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1211 ret.push_back(obj);
1212 }
1213 }
1214
1215 return ret;
1216}
1217
1218Value listreceivedbyaddress(const Array& params, bool fHelp)
1219{
b9fb692d
JS
1220 if (!EnsureWalletIsAvailable(fHelp))
1221 return Value::null;
1222
0fa2f889 1223 if (fHelp || params.size() > 3)
e3bc5698 1224 throw runtime_error(
0fa2f889 1225 "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
a6099ef3 1226 "\nList balances by receiving address.\n"
1227 "\nArguments:\n"
1228 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
5617267c 1229 "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n"
0fa2f889 1230 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
a6099ef3 1231
1232 "\nResult:\n"
1233 "[\n"
1234 " {\n"
8f6860a0 1235 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
a6099ef3 1236 " \"address\" : \"receivingaddress\", (string) The receiving address\n"
7b782f5b 1237 " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
a6099ef3 1238 " \"amount\" : x.xxx, (numeric) The total amount in btc received by the address\n"
1239 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1240 " }\n"
1241 " ,...\n"
1242 "]\n"
1243
1244 "\nExamples:\n"
1245 + HelpExampleCli("listreceivedbyaddress", "")
1246 + HelpExampleCli("listreceivedbyaddress", "6 true")
0fa2f889 1247 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
a6099ef3 1248 );
e3bc5698 1249
4401b2d7
EL
1250 LOCK2(cs_main, pwalletMain->cs_wallet);
1251
e3bc5698
JG
1252 return ListReceived(params, false);
1253}
1254
1255Value listreceivedbyaccount(const Array& params, bool fHelp)
1256{
b9fb692d
JS
1257 if (!EnsureWalletIsAvailable(fHelp))
1258 return Value::null;
1259
0fa2f889 1260 if (fHelp || params.size() > 3)
e3bc5698 1261 throw runtime_error(
0fa2f889 1262 "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
7b782f5b 1263 "\nDEPRECATED. List balances by account.\n"
a6099ef3 1264 "\nArguments:\n"
1265 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1266 "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
0fa2f889 1267 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
a6099ef3 1268
1269 "\nResult:\n"
1270 "[\n"
1271 " {\n"
8f6860a0 1272 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
a6099ef3 1273 " \"account\" : \"accountname\", (string) The account name of the receiving account\n"
1274 " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
1275 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1276 " }\n"
1277 " ,...\n"
1278 "]\n"
1279
1280 "\nExamples:\n"
1281 + HelpExampleCli("listreceivedbyaccount", "")
1282 + HelpExampleCli("listreceivedbyaccount", "6 true")
0fa2f889 1283 + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
a6099ef3 1284 );
e3bc5698 1285
4401b2d7
EL
1286 LOCK2(cs_main, pwalletMain->cs_wallet);
1287
e3bc5698
JG
1288 return ListReceived(params, true);
1289}
1290
cc6cfab3
LD
1291static void MaybePushAddress(Object & entry, const CTxDestination &dest)
1292{
1293 CBitcoinAddress addr;
1294 if (addr.Set(dest))
1295 entry.push_back(Pair("address", addr.ToString()));
1296}
1297
80dda36a 1298void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
e3bc5698 1299{
a372168e 1300 CAmount nFee;
e3bc5698 1301 string strSentAccount;
1b4568cb
CL
1302 list<COutputEntry> listReceived;
1303 list<COutputEntry> listSent;
e3bc5698 1304
d7d5d23b 1305 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
e3bc5698
JG
1306
1307 bool fAllAccounts = (strAccount == string("*"));
a3e192a3 1308 bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
e3bc5698 1309
e3bc5698
JG
1310 // Sent
1311 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1312 {
1b4568cb 1313 BOOST_FOREACH(const COutputEntry& s, listSent)
e3bc5698
JG
1314 {
1315 Object entry;
1b4568cb 1316 if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
952877e0 1317 entry.push_back(Pair("involvesWatchonly", true));
e3bc5698 1318 entry.push_back(Pair("account", strSentAccount));
1b4568cb 1319 MaybePushAddress(entry, s.destination);
b96f6a77 1320 entry.push_back(Pair("category", "send"));
1b4568cb
CL
1321 entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
1322 entry.push_back(Pair("vout", s.vout));
e3bc5698
JG
1323 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1324 if (fLong)
1325 WalletTxToJSON(wtx, entry);
1326 ret.push_back(entry);
1327 }
1328 }
1329
1330 // Received
1331 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1332 {
1b4568cb 1333 BOOST_FOREACH(const COutputEntry& r, listReceived)
e3bc5698
JG
1334 {
1335 string account;
1b4568cb
CL
1336 if (pwalletMain->mapAddressBook.count(r.destination))
1337 account = pwalletMain->mapAddressBook[r.destination].name;
e3bc5698
JG
1338 if (fAllAccounts || (account == strAccount))
1339 {
1340 Object entry;
1b4568cb 1341 if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
952877e0 1342 entry.push_back(Pair("involvesWatchonly", true));
e3bc5698 1343 entry.push_back(Pair("account", account));
1b4568cb 1344 MaybePushAddress(entry, r.destination);
e07c8e91
LD
1345 if (wtx.IsCoinBase())
1346 {
1347 if (wtx.GetDepthInMainChain() < 1)
1348 entry.push_back(Pair("category", "orphan"));
1349 else if (wtx.GetBlocksToMaturity() > 0)
1350 entry.push_back(Pair("category", "immature"));
1351 else
1352 entry.push_back(Pair("category", "generate"));
1353 }
1354 else
2b72d46f 1355 {
b96f6a77 1356 entry.push_back(Pair("category", "receive"));
2b72d46f 1357 }
1b4568cb
CL
1358 entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
1359 entry.push_back(Pair("vout", r.vout));
e3bc5698
JG
1360 if (fLong)
1361 WalletTxToJSON(wtx, entry);
1362 ret.push_back(entry);
1363 }
1364 }
1365 }
1366}
1367
1368void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1369{
1370 bool fAllAccounts = (strAccount == string("*"));
1371
1372 if (fAllAccounts || acentry.strAccount == strAccount)
1373 {
1374 Object entry;
1375 entry.push_back(Pair("account", acentry.strAccount));
1376 entry.push_back(Pair("category", "move"));
d56e30ca 1377 entry.push_back(Pair("time", acentry.nTime));
e3bc5698
JG
1378 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1379 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1380 entry.push_back(Pair("comment", acentry.strComment));
1381 ret.push_back(entry);
1382 }
1383}
1384
1385Value listtransactions(const Array& params, bool fHelp)
1386{
b9fb692d
JS
1387 if (!EnsureWalletIsAvailable(fHelp))
1388 return Value::null;
1389
d7d5d23b 1390 if (fHelp || params.size() > 4)
e3bc5698 1391 throw runtime_error(
d7d5d23b 1392 "listtransactions ( \"account\" count from includeWatchonly)\n"
a6099ef3 1393 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
1394 "\nArguments:\n"
7b782f5b 1395 "1. \"account\" (string, optional) DEPRECATED. The account name. Should be \"*\".\n"
a6099ef3 1396 "2. count (numeric, optional, default=10) The number of transactions to return\n"
1397 "3. from (numeric, optional, default=0) The number of transactions to skip\n"
d7d5d23b 1398 "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
a6099ef3 1399 "\nResult:\n"
1400 "[\n"
1401 " {\n"
7b782f5b 1402 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n"
a6099ef3 1403 " It will be \"\" for the default account.\n"
1404 " \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for \n"
1405 " move transactions (category = move).\n"
1406 " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
1407 " transaction between accounts, and not associated with an address,\n"
1408 " transaction id or block. 'send' and 'receive' transactions are \n"
1409 " associated with an address, transaction id and block details\n"
1410 " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the\n"
1411 " 'move' category for moves outbound. It is positive for the 'receive' category,\n"
1412 " and for the 'move' category for inbound funds.\n"
1b4568cb 1413 " \"vout\" : n, (numeric) the vout value\n"
a6099ef3 1414 " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the \n"
1415 " 'send' category of transactions.\n"
1416 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
1417 " 'receive' category of transactions.\n"
1418 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
1419 " category of transactions.\n"
1420 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
1421 " category of transactions.\n"
b5ef85c7 1422 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
a6099ef3 1423 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1424 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
1425 " for 'send' and 'receive' category of transactions.\n"
1426 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1427 " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
1428 " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
1429 " negative amounts).\n"
1430 " }\n"
1431 "]\n"
1432
1433 "\nExamples:\n"
1434 "\nList the most recent 10 transactions in the systems\n"
1435 + HelpExampleCli("listtransactions", "") +
7b782f5b
LD
1436 "\nList transactions 100 to 120\n"
1437 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
a6099ef3 1438 "\nAs a json rpc call\n"
7b782f5b 1439 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
a6099ef3 1440 );
e3bc5698 1441
4401b2d7
EL
1442 LOCK2(cs_main, pwalletMain->cs_wallet);
1443
e3bc5698
JG
1444 string strAccount = "*";
1445 if (params.size() > 0)
1446 strAccount = params[0].get_str();
1447 int nCount = 10;
1448 if (params.size() > 1)
1449 nCount = params[1].get_int();
1450 int nFrom = 0;
1451 if (params.size() > 2)
1452 nFrom = params[2].get_int();
a3e192a3 1453 isminefilter filter = ISMINE_SPENDABLE;
a5c6c5d6
J
1454 if(params.size() > 3)
1455 if(params[3].get_bool())
a3e192a3 1456 filter = filter | ISMINE_WATCH_ONLY;
e3bc5698
JG
1457
1458 if (nCount < 0)
738835d7 1459 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
e3bc5698 1460 if (nFrom < 0)
738835d7 1461 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
e3bc5698
JG
1462
1463 Array ret;
e3bc5698 1464
ddb709e9
LD
1465 std::list<CAccountingEntry> acentries;
1466 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
e3bc5698
JG
1467
1468 // iterate backwards until we have nCount items to return:
c3f95ef1 1469 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
e3bc5698
JG
1470 {
1471 CWalletTx *const pwtx = (*it).second.first;
1472 if (pwtx != 0)
d7d5d23b 1473 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
e3bc5698
JG
1474 CAccountingEntry *const pacentry = (*it).second.second;
1475 if (pacentry != 0)
1476 AcentryToJSON(*pacentry, strAccount, ret);
1477
1478 if ((int)ret.size() >= (nCount+nFrom)) break;
1479 }
1480 // ret is newest to oldest
1481
1482 if (nFrom > (int)ret.size())
1483 nFrom = ret.size();
1484 if ((nFrom + nCount) > (int)ret.size())
1485 nCount = ret.size() - nFrom;
1486 Array::iterator first = ret.begin();
1487 std::advance(first, nFrom);
1488 Array::iterator last = ret.begin();
1489 std::advance(last, nFrom+nCount);
1490
1491 if (last != ret.end()) ret.erase(last, ret.end());
1492 if (first != ret.begin()) ret.erase(ret.begin(), first);
1493
1494 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1495
1496 return ret;
1497}
1498
1499Value listaccounts(const Array& params, bool fHelp)
1500{
b9fb692d
JS
1501 if (!EnsureWalletIsAvailable(fHelp))
1502 return Value::null;
1503
83f3543f 1504 if (fHelp || params.size() > 2)
e3bc5698 1505 throw runtime_error(
83f3543f 1506 "listaccounts ( minconf includeWatchonly)\n"
7b782f5b 1507 "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
a6099ef3 1508 "\nArguments:\n"
5617267c 1509 "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
83f3543f 1510 "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
a6099ef3 1511 "\nResult:\n"
1512 "{ (json object where keys are account names, and values are numeric balances\n"
1513 " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
1514 " ...\n"
1515 "}\n"
1516 "\nExamples:\n"
1517 "\nList account balances where there at least 1 confirmation\n"
1518 + HelpExampleCli("listaccounts", "") +
1519 "\nList account balances including zero confirmation transactions\n"
1520 + HelpExampleCli("listaccounts", "0") +
1521 "\nList account balances for 6 or more confirmations\n"
1522 + HelpExampleCli("listaccounts", "6") +
1523 "\nAs json rpc call\n"
1524 + HelpExampleRpc("listaccounts", "6")
1525 );
e3bc5698 1526
4401b2d7
EL
1527 LOCK2(cs_main, pwalletMain->cs_wallet);
1528
e3bc5698
JG
1529 int nMinDepth = 1;
1530 if (params.size() > 0)
1531 nMinDepth = params[0].get_int();
a3e192a3 1532 isminefilter includeWatchonly = ISMINE_SPENDABLE;
a5c6c5d6
J
1533 if(params.size() > 1)
1534 if(params[1].get_bool())
a3e192a3 1535 includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
e3bc5698 1536
a372168e 1537 map<string, CAmount> mapAccountBalances;
61885513 1538 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
83f3543f 1539 if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
61885513 1540 mapAccountBalances[entry.second.name] = 0;
e3bc5698
JG
1541 }
1542
1543 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1544 {
1545 const CWalletTx& wtx = (*it).second;
a372168e 1546 CAmount nFee;
e3bc5698 1547 string strSentAccount;
1b4568cb
CL
1548 list<COutputEntry> listReceived;
1549 list<COutputEntry> listSent;
93a18a36
GA
1550 int nDepth = wtx.GetDepthInMainChain();
1551 if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
731b89b8 1552 continue;
83f3543f 1553 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
e3bc5698 1554 mapAccountBalances[strSentAccount] -= nFee;
1b4568cb
CL
1555 BOOST_FOREACH(const COutputEntry& s, listSent)
1556 mapAccountBalances[strSentAccount] -= s.amount;
93a18a36 1557 if (nDepth >= nMinDepth)
e3bc5698 1558 {
1b4568cb
CL
1559 BOOST_FOREACH(const COutputEntry& r, listReceived)
1560 if (pwalletMain->mapAddressBook.count(r.destination))
1561 mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
e3bc5698 1562 else
1b4568cb 1563 mapAccountBalances[""] += r.amount;
e3bc5698
JG
1564 }
1565 }
1566
1567 list<CAccountingEntry> acentries;
1568 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1569 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1570 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1571
1572 Object ret;
a372168e 1573 BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
e3bc5698
JG
1574 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1575 }
1576 return ret;
1577}
1578
1579Value listsinceblock(const Array& params, bool fHelp)
1580{
b9fb692d
JS
1581 if (!EnsureWalletIsAvailable(fHelp))
1582 return Value::null;
1583
e3bc5698
JG
1584 if (fHelp)
1585 throw runtime_error(
d7d5d23b 1586 "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
a6099ef3 1587 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
1588 "\nArguments:\n"
1589 "1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
1590 "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
d7d5d23b 1591 "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
a6099ef3 1592 "\nResult:\n"
1593 "{\n"
1594 " \"transactions\": [\n"
7b782f5b 1595 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
a6099ef3 1596 " \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for move transactions (category = move).\n"
1597 " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
1598 " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the 'move' category for moves \n"
1599 " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
1b4568cb 1600 " \"vout\" : n, (numeric) the vout value\n"
a6099ef3 1601 " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the 'send' category of transactions.\n"
1602 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
1603 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1604 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1605 " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
b5ef85c7 1606 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
a6099ef3 1607 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
1608 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
1609 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1610 " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
1611 " ],\n"
1612 " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
1613 "}\n"
1614 "\nExamples:\n"
1615 + HelpExampleCli("listsinceblock", "")
1616 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1617 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1618 );
e3bc5698 1619
4401b2d7
EL
1620 LOCK2(cs_main, pwalletMain->cs_wallet);
1621
e3bc5698
JG
1622 CBlockIndex *pindex = NULL;
1623 int target_confirms = 1;
a3e192a3 1624 isminefilter filter = ISMINE_SPENDABLE;
e3bc5698
JG
1625
1626 if (params.size() > 0)
1627 {
4f152496 1628 uint256 blockId;
e3bc5698
JG
1629
1630 blockId.SetHex(params[0].get_str());
145d5be8 1631 BlockMap::iterator it = mapBlockIndex.find(blockId);
e4daecda
PW
1632 if (it != mapBlockIndex.end())
1633 pindex = it->second;
e3bc5698
JG
1634 }
1635
1636 if (params.size() > 1)
1637 {
1638 target_confirms = params[1].get_int();
1639
1640 if (target_confirms < 1)
738835d7 1641 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
e3bc5698
JG
1642 }
1643
a5c6c5d6
J
1644 if(params.size() > 2)
1645 if(params[2].get_bool())
a3e192a3 1646 filter = filter | ISMINE_WATCH_ONLY;
a5c6c5d6 1647
4c6d41b8 1648 int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
e3bc5698
JG
1649
1650 Array transactions;
1651
1652 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1653 {
1654 CWalletTx tx = (*it).second;
1655
1656 if (depth == -1 || tx.GetDepthInMainChain() < depth)
d7d5d23b 1657 ListTransactions(tx, "*", 0, true, transactions, filter);
e3bc5698
JG
1658 }
1659
4c6d41b8 1660 CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
4f152496 1661 uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
e3bc5698
JG
1662
1663 Object ret;
1664 ret.push_back(Pair("transactions", transactions));
1665 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1666
1667 return ret;
1668}
1669
1670Value gettransaction(const Array& params, bool fHelp)
1671{
b9fb692d
JS
1672 if (!EnsureWalletIsAvailable(fHelp))
1673 return Value::null;
1674
f87ba3df 1675 if (fHelp || params.size() < 1 || params.size() > 2)
e3bc5698 1676 throw runtime_error(
57e1716d 1677 "gettransaction \"txid\" ( includeWatchonly )\n"
a6099ef3 1678 "\nGet detailed information about in-wallet transaction <txid>\n"
1679 "\nArguments:\n"
1680 "1. \"txid\" (string, required) The transaction id\n"
f87ba3df 1681 "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
a6099ef3 1682 "\nResult:\n"
1683 "{\n"
1684 " \"amount\" : x.xxx, (numeric) The transaction amount in btc\n"
1685 " \"confirmations\" : n, (numeric) The number of confirmations\n"
1686 " \"blockhash\" : \"hash\", (string) The block hash\n"
1687 " \"blockindex\" : xx, (numeric) The block index\n"
1688 " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
b5ef85c7 1689 " \"txid\" : \"transactionid\", (string) The transaction id.\n"
a6099ef3 1690 " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
1691 " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
1692 " \"details\" : [\n"
1693 " {\n"
7b782f5b 1694 " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
a6099ef3 1695 " \"address\" : \"bitcoinaddress\", (string) The bitcoin address involved in the transaction\n"
1696 " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
1697 " \"amount\" : x.xxx (numeric) The amount in btc\n"
1b4568cb 1698 " \"vout\" : n, (numeric) the vout value\n"
a6099ef3 1699 " }\n"
1700 " ,...\n"
3a1c20b7
WL
1701 " ],\n"
1702 " \"hex\" : \"data\" (string) Raw data for transaction\n"
a6099ef3 1703 "}\n"
1704
ab45ddb5 1705 "\nExamples:\n"
a6099ef3 1706 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
57e1716d 1707 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
a6099ef3 1708 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1709 );
e3bc5698 1710
4401b2d7
EL
1711 LOCK2(cs_main, pwalletMain->cs_wallet);
1712
e3bc5698
JG
1713 uint256 hash;
1714 hash.SetHex(params[0].get_str());
1715
a3e192a3 1716 isminefilter filter = ISMINE_SPENDABLE;
f87ba3df
J
1717 if(params.size() > 1)
1718 if(params[1].get_bool())
a3e192a3 1719 filter = filter | ISMINE_WATCH_ONLY;
f87ba3df 1720
e3bc5698
JG
1721 Object entry;
1722 if (!pwalletMain->mapWallet.count(hash))
738835d7 1723 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
e3bc5698
JG
1724 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1725
ccca27a7 1726 CAmount nCredit = wtx.GetCredit(filter);
a372168e
MF
1727 CAmount nDebit = wtx.GetDebit(filter);
1728 CAmount nNet = nCredit - nDebit;
1729 CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
e3bc5698
JG
1730
1731 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
80dda36a 1732 if (wtx.IsFromMe(filter))
e3bc5698
JG
1733 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1734
1735 WalletTxToJSON(wtx, entry);
1736
1737 Array details;
f87ba3df 1738 ListTransactions(wtx, "*", 0, false, details, filter);
e3bc5698
JG
1739 entry.push_back(Pair("details", details));
1740
ae775b5b 1741 string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
3a1c20b7
WL
1742 entry.push_back(Pair("hex", strHex));
1743
e3bc5698
JG
1744 return entry;
1745}
1746
1747
1748Value backupwallet(const Array& params, bool fHelp)
1749{
b9fb692d
JS
1750 if (!EnsureWalletIsAvailable(fHelp))
1751 return Value::null;
1752
e3bc5698
JG
1753 if (fHelp || params.size() != 1)
1754 throw runtime_error(
a6099ef3 1755 "backupwallet \"destination\"\n"
1756 "\nSafely copies wallet.dat to destination, which can be a directory or a path with filename.\n"
1757 "\nArguments:\n"
1758 "1. \"destination\" (string) The destination directory or file\n"
1759 "\nExamples:\n"
1760 + HelpExampleCli("backupwallet", "\"backup.dat\"")
1761 + HelpExampleRpc("backupwallet", "\"backup.dat\"")
1762 );
e3bc5698 1763
4401b2d7
EL
1764 LOCK2(cs_main, pwalletMain->cs_wallet);
1765
e3bc5698 1766 string strDest = params[0].get_str();
ad525e9c
PK
1767 if (!BackupWallet(*pwalletMain, strDest))
1768 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
e3bc5698
JG
1769
1770 return Value::null;
1771}
1772
1773
1774Value keypoolrefill(const Array& params, bool fHelp)
1775{
b9fb692d
JS
1776 if (!EnsureWalletIsAvailable(fHelp))
1777 return Value::null;
1778
36bd46f1 1779 if (fHelp || params.size() > 1)
e3bc5698 1780 throw runtime_error(
a6099ef3 1781 "keypoolrefill ( newsize )\n"
1782 "\nFills the keypool."
1783 + HelpRequiringPassphrase() + "\n"
1784 "\nArguments\n"
1785 "1. newsize (numeric, optional, default=100) The new keypool size\n"
1786 "\nExamples:\n"
1787 + HelpExampleCli("keypoolrefill", "")
1788 + HelpExampleRpc("keypoolrefill", "")
1789 );
e3bc5698 1790
4401b2d7
EL
1791 LOCK2(cs_main, pwalletMain->cs_wallet);
1792
f914c7a1
PK
1793 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
1794 unsigned int kpSize = 0;
36bd46f1
JG
1795 if (params.size() > 0) {
1796 if (params[0].get_int() < 0)
f914c7a1
PK
1797 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
1798 kpSize = (unsigned int)params[0].get_int();
36bd46f1
JG
1799 }
1800
e3bc5698 1801 EnsureWalletIsUnlocked();
36bd46f1 1802 pwalletMain->TopUpKeyPool(kpSize);
e3bc5698 1803
36bd46f1 1804 if (pwalletMain->GetKeyPoolSize() < kpSize)
738835d7 1805 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
e3bc5698
JG
1806
1807 return Value::null;
1808}
1809
1810
92f2c1fe 1811static void LockWallet(CWallet* pWallet)
e3bc5698 1812{
92f2c1fe
GA
1813 LOCK(cs_nWalletUnlockTime);
1814 nWalletUnlockTime = 0;
1815 pWallet->Lock();
e3bc5698
JG
1816}
1817
1818Value walletpassphrase(const Array& params, bool fHelp)
1819{
b9fb692d
JS
1820 if (!EnsureWalletIsAvailable(fHelp))
1821 return Value::null;
1822
e3bc5698
JG
1823 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1824 throw runtime_error(
a6099ef3 1825 "walletpassphrase \"passphrase\" timeout\n"
1826 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
1827 "This is needed prior to performing transactions related to private keys such as sending bitcoins\n"
1828 "\nArguments:\n"
1829 "1. \"passphrase\" (string, required) The wallet passphrase\n"
1830 "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
6c0db81c
WL
1831 "\nNote:\n"
1832 "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
1833 "time that overrides the old one.\n"
a6099ef3 1834 "\nExamples:\n"
1835 "\nunlock the wallet for 60 seconds\n"
1836 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
1837 "\nLock the wallet again (before 60 seconds)\n"
1838 + HelpExampleCli("walletlock", "") +
1839 "\nAs json rpc call\n"
1840 + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
1841 );
1842
4401b2d7
EL
1843 LOCK2(cs_main, pwalletMain->cs_wallet);
1844
e3bc5698
JG
1845 if (fHelp)
1846 return true;
1847 if (!pwalletMain->IsCrypted())
738835d7 1848 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
e3bc5698 1849
e3bc5698
JG
1850 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1851 SecureString strWalletPass;
1852 strWalletPass.reserve(100);
1853 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1854 // Alternately, find a way to make params[0] mlock()'d to begin with.
1855 strWalletPass = params[0].get_str().c_str();
1856
1857 if (strWalletPass.length() > 0)
1858 {
1859 if (!pwalletMain->Unlock(strWalletPass))
738835d7 1860 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
e3bc5698
JG
1861 }
1862 else
1863 throw runtime_error(
1864 "walletpassphrase <passphrase> <timeout>\n"
1865 "Stores the wallet decryption key in memory for <timeout> seconds.");
1866
92f2c1fe
GA
1867 pwalletMain->TopUpKeyPool();
1868
51ed9ec9 1869 int64_t nSleepTime = params[1].get_int64();
92f2c1fe
GA
1870 LOCK(cs_nWalletUnlockTime);
1871 nWalletUnlockTime = GetTime() + nSleepTime;
1872 RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
e3bc5698
JG
1873
1874 return Value::null;
1875}
1876
1877
1878Value walletpassphrasechange(const Array& params, bool fHelp)
1879{
b9fb692d
JS
1880 if (!EnsureWalletIsAvailable(fHelp))
1881 return Value::null;
1882
e3bc5698
JG
1883 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1884 throw runtime_error(
a6099ef3 1885 "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
1886 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
1887 "\nArguments:\n"
1888 "1. \"oldpassphrase\" (string) The current passphrase\n"
1889 "2. \"newpassphrase\" (string) The new passphrase\n"
1890 "\nExamples:\n"
1891 + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
1892 + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
1893 );
1894
4401b2d7
EL
1895 LOCK2(cs_main, pwalletMain->cs_wallet);
1896
e3bc5698
JG
1897 if (fHelp)
1898 return true;
1899 if (!pwalletMain->IsCrypted())
738835d7 1900 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
e3bc5698
JG
1901
1902 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1903 // Alternately, find a way to make params[0] mlock()'d to begin with.
1904 SecureString strOldWalletPass;
1905 strOldWalletPass.reserve(100);
1906 strOldWalletPass = params[0].get_str().c_str();
1907
1908 SecureString strNewWalletPass;
1909 strNewWalletPass.reserve(100);
1910 strNewWalletPass = params[1].get_str().c_str();
1911
1912 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1913 throw runtime_error(
1914 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1915 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1916
1917 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
738835d7 1918 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
e3bc5698
JG
1919
1920 return Value::null;
1921}
1922
1923
1924Value walletlock(const Array& params, bool fHelp)
1925{
b9fb692d
JS
1926 if (!EnsureWalletIsAvailable(fHelp))
1927 return Value::null;
1928
e3bc5698
JG
1929 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1930 throw runtime_error(
1931 "walletlock\n"
a6099ef3 1932 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
e3bc5698 1933 "After calling this method, you will need to call walletpassphrase again\n"
a6099ef3 1934 "before being able to call any methods which require the wallet to be unlocked.\n"
1935 "\nExamples:\n"
1936 "\nSet the passphrase for 2 minutes to perform a transaction\n"
1937 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
1938 "\nPerform a send (requires passphrase set)\n"
1939 + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 1.0") +
1940 "\nClear the passphrase since we are done before 2 minutes is up\n"
1941 + HelpExampleCli("walletlock", "") +
1942 "\nAs json rpc call\n"
1943 + HelpExampleRpc("walletlock", "")
1944 );
1945
4401b2d7
EL
1946 LOCK2(cs_main, pwalletMain->cs_wallet);
1947
e3bc5698
JG
1948 if (fHelp)
1949 return true;
1950 if (!pwalletMain->IsCrypted())
738835d7 1951 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
e3bc5698
JG
1952
1953 {
1954 LOCK(cs_nWalletUnlockTime);
1955 pwalletMain->Lock();
1956 nWalletUnlockTime = 0;
1957 }
1958
1959 return Value::null;
1960}
1961
1962
1963Value encryptwallet(const Array& params, bool fHelp)
1964{
b9fb692d
JS
1965 if (!EnsureWalletIsAvailable(fHelp))
1966 return Value::null;
1967
e3bc5698
JG
1968 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1969 throw runtime_error(
a6099ef3 1970 "encryptwallet \"passphrase\"\n"
1971 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
1972 "After this, any calls that interact with private keys such as sending or signing \n"
1973 "will require the passphrase to be set prior the making these calls.\n"
1974 "Use the walletpassphrase call for this, and then walletlock call.\n"
1975 "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
1976 "Note that this will shutdown the server.\n"
1977 "\nArguments:\n"
1978 "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
1979 "\nExamples:\n"
1980 "\nEncrypt you wallet\n"
1981 + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
1982 "\nNow set the passphrase to use the wallet, such as for signing or sending bitcoin\n"
1983 + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
1984 "\nNow we can so something like sign\n"
1985 + HelpExampleCli("signmessage", "\"bitcoinaddress\" \"test message\"") +
1986 "\nNow lock the wallet again by removing the passphrase\n"
1987 + HelpExampleCli("walletlock", "") +
1988 "\nAs a json rpc call\n"
1989 + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
1990 );
1991
4401b2d7
EL
1992 LOCK2(cs_main, pwalletMain->cs_wallet);
1993
e3bc5698
JG
1994 if (fHelp)
1995 return true;
1996 if (pwalletMain->IsCrypted())
738835d7 1997 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
e3bc5698
JG
1998
1999 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2000 // Alternately, find a way to make params[0] mlock()'d to begin with.
2001 SecureString strWalletPass;
2002 strWalletPass.reserve(100);
2003 strWalletPass = params[0].get_str().c_str();
2004
2005 if (strWalletPass.length() < 1)
2006 throw runtime_error(
2007 "encryptwallet <passphrase>\n"
2008 "Encrypts the wallet with <passphrase>.");
2009
2010 if (!pwalletMain->EncryptWallet(strWalletPass))
738835d7 2011 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
e3bc5698
JG
2012
2013 // BDB seems to have a bad habit of writing old data into
2014 // slack space in .dat files; that is bad if the old data is
331544bc 2015 // unencrypted private keys. So:
e3bc5698 2016 StartShutdown();
6b3783a9 2017 return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
e3bc5698
JG
2018}
2019
fdbb537d
JG
2020Value lockunspent(const Array& params, bool fHelp)
2021{
b9fb692d
JS
2022 if (!EnsureWalletIsAvailable(fHelp))
2023 return Value::null;
2024
fdbb537d
JG
2025 if (fHelp || params.size() < 1 || params.size() > 2)
2026 throw runtime_error(
a6099ef3 2027 "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
2028 "\nUpdates list of temporarily unspendable outputs.\n"
90fd8737 2029 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
a6099ef3 2030 "A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n"
2031 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2032 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
2033 "Also see the listunspent call\n"
2034 "\nArguments:\n"
2035 "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
2036 "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
2037 " [ (json array of json objects)\n"
2038 " {\n"
2039 " \"txid\":\"id\", (string) The transaction id\n"
2040 " \"vout\": n (numeric) The output number\n"
2041 " }\n"
2042 " ,...\n"
2043 " ]\n"
2044
2045 "\nResult:\n"
2046 "true|false (boolean) Whether the command was successful or not\n"
2047
2048 "\nExamples:\n"
2049 "\nList the unspent transactions\n"
2050 + HelpExampleCli("listunspent", "") +
2051 "\nLock an unspent transaction\n"
2052 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2053 "\nList the locked transactions\n"
2054 + HelpExampleCli("listlockunspent", "") +
2055 "\nUnlock the transaction again\n"
2056 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2057 "\nAs a json rpc call\n"
2058 + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
2059 );
fdbb537d 2060
4401b2d7
EL
2061 LOCK2(cs_main, pwalletMain->cs_wallet);
2062
fdbb537d 2063 if (params.size() == 1)
856e862f 2064 RPCTypeCheck(params, boost::assign::list_of(bool_type));
fdbb537d 2065 else
856e862f 2066 RPCTypeCheck(params, boost::assign::list_of(bool_type)(array_type));
fdbb537d
JG
2067
2068 bool fUnlock = params[0].get_bool();
2069
2070 if (params.size() == 1) {
2071 if (fUnlock)
2072 pwalletMain->UnlockAllCoins();
2073 return true;
2074 }
2075
2076 Array outputs = params[1].get_array();
2077 BOOST_FOREACH(Value& output, outputs)
2078 {
2079 if (output.type() != obj_type)
15117692 2080 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
fdbb537d
JG
2081 const Object& o = output.get_obj();
2082
856e862f 2083 RPCTypeCheck(o, boost::assign::map_list_of("txid", str_type)("vout", int_type));
fdbb537d
JG
2084
2085 string txid = find_value(o, "txid").get_str();
2086 if (!IsHex(txid))
15117692 2087 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
fdbb537d
JG
2088
2089 int nOutput = find_value(o, "vout").get_int();
2090 if (nOutput < 0)
15117692 2091 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
fdbb537d 2092
34cdc411 2093 COutPoint outpt(uint256S(txid), nOutput);
fdbb537d
JG
2094
2095 if (fUnlock)
2096 pwalletMain->UnlockCoin(outpt);
2097 else
2098 pwalletMain->LockCoin(outpt);
2099 }
2100
2101 return true;
2102}
2103
2104Value listlockunspent(const Array& params, bool fHelp)
2105{
b9fb692d
JS
2106 if (!EnsureWalletIsAvailable(fHelp))
2107 return Value::null;
2108
fdbb537d
JG
2109 if (fHelp || params.size() > 0)
2110 throw runtime_error(
2111 "listlockunspent\n"
a6099ef3 2112 "\nReturns list of temporarily unspendable outputs.\n"
2113 "See the lockunspent call to lock and unlock transactions for spending.\n"
2114 "\nResult:\n"
2115 "[\n"
2116 " {\n"
2117 " \"txid\" : \"transactionid\", (string) The transaction id locked\n"
2118 " \"vout\" : n (numeric) The vout value\n"
2119 " }\n"
2120 " ,...\n"
2121 "]\n"
2122 "\nExamples:\n"
2123 "\nList the unspent transactions\n"
2124 + HelpExampleCli("listunspent", "") +
2125 "\nLock an unspent transaction\n"
2126 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2127 "\nList the locked transactions\n"
2128 + HelpExampleCli("listlockunspent", "") +
2129 "\nUnlock the transaction again\n"
2130 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2131 "\nAs a json rpc call\n"
2132 + HelpExampleRpc("listlockunspent", "")
2133 );
fdbb537d 2134
4401b2d7
EL
2135 LOCK2(cs_main, pwalletMain->cs_wallet);
2136
fdbb537d
JG
2137 vector<COutPoint> vOutpts;
2138 pwalletMain->ListLockedCoins(vOutpts);
2139
2140 Array ret;
2141
2142 BOOST_FOREACH(COutPoint &outpt, vOutpts) {
2143 Object o;
2144
2145 o.push_back(Pair("txid", outpt.hash.GetHex()));
2146 o.push_back(Pair("vout", (int)outpt.n));
2147 ret.push_back(o);
2148 }
2149
2150 return ret;
2151}
2152
a943bde6
WL
2153Value settxfee(const Array& params, bool fHelp)
2154{
b9fb692d
JS
2155 if (!EnsureWalletIsAvailable(fHelp))
2156 return Value::null;
2157
a943bde6
WL
2158 if (fHelp || params.size() < 1 || params.size() > 1)
2159 throw runtime_error(
2160 "settxfee amount\n"
6943cb9b 2161 "\nSet the transaction fee per kB.\n"
a943bde6 2162 "\nArguments:\n"
6943cb9b 2163 "1. amount (numeric, required) The transaction fee in BTC/kB rounded to the nearest 0.00000001\n"
a943bde6
WL
2164 "\nResult\n"
2165 "true|false (boolean) Returns true if successful\n"
2166 "\nExamples:\n"
2167 + HelpExampleCli("settxfee", "0.00001")
2168 + HelpExampleRpc("settxfee", "0.00001")
2169 );
2170
4401b2d7
EL
2171 LOCK2(cs_main, pwalletMain->cs_wallet);
2172
a943bde6 2173 // Amount
a372168e 2174 CAmount nAmount = 0;
a943bde6
WL
2175 if (params[0].get_real() != 0.0)
2176 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
2177
c6cb21d1 2178 payTxFee = CFeeRate(nAmount, 1000);
a943bde6
WL
2179 return true;
2180}
2181
a00ebb51
DN
2182Value getwalletinfo(const Array& params, bool fHelp)
2183{
b9fb692d
JS
2184 if (!EnsureWalletIsAvailable(fHelp))
2185 return Value::null;
2186
a00ebb51
DN
2187 if (fHelp || params.size() != 0)
2188 throw runtime_error(
2189 "getwalletinfo\n"
2190 "Returns an object containing various wallet state info.\n"
2191 "\nResult:\n"
2192 "{\n"
2193 " \"walletversion\": xxxxx, (numeric) the wallet version\n"
d44c5456 2194 " \"balance\": xxxxxxx, (numeric) the total confirmed bitcoin balance of the wallet\n"
8024d67d
GM
2195 " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed bitcoin balance of the wallet\n"
2196 " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet\n"
a00ebb51
DN
2197 " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
2198 " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
2199 " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
2200 " \"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"
2201 "}\n"
2202 "\nExamples:\n"
2203 + HelpExampleCli("getwalletinfo", "")
2204 + HelpExampleRpc("getwalletinfo", "")
2205 );
2206
4401b2d7
EL
2207 LOCK2(cs_main, pwalletMain->cs_wallet);
2208
a00ebb51
DN
2209 Object obj;
2210 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
2211 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
8024d67d
GM
2212 obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
2213 obj.push_back(Pair("immature_balance", ValueFromAmount(pwalletMain->GetImmatureBalance())));
a00ebb51 2214 obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size()));
d56e30ca 2215 obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
a00ebb51
DN
2216 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
2217 if (pwalletMain->IsCrypted())
d56e30ca 2218 obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
a00ebb51
DN
2219 return obj;
2220}
0f5954c4
GA
2221
2222Value resendwallettransactions(const Array& params, bool fHelp)
2223{
b9fb692d
JS
2224 if (!EnsureWalletIsAvailable(fHelp))
2225 return Value::null;
2226
0f5954c4
GA
2227 if (fHelp || params.size() != 0)
2228 throw runtime_error(
2229 "resendwallettransactions\n"
2230 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
2231 "Intended only for testing; the wallet code periodically re-broadcasts\n"
2232 "automatically.\n"
2233 "Returns array of transaction ids that were re-broadcast.\n"
2234 );
2235
2236 LOCK2(cs_main, pwalletMain->cs_wallet);
2237
2238 std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
2239 Array result;
2240 BOOST_FOREACH(const uint256& txid, txids)
2241 {
2242 result.push_back(txid.ToString());
2243 }
2244 return result;
2245}
0b9dc9c8
JS
2246
2247Value listunspent(const Array& params, bool fHelp)
2248{
2249 if (!EnsureWalletIsAvailable(fHelp))
2250 return Value::null;
2251
2252 if (fHelp || params.size() > 3)
ea9e82df
JS
2253 throw runtime_error(
2254 "listunspent ( minconf maxconf [\"address\",...] )\n"
2255 "\nReturns array of unspent transaction outputs\n"
2256 "with between minconf and maxconf (inclusive) confirmations.\n"
2257 "Optionally filter to only include txouts paid to specified addresses.\n"
2258 "Results are an array of Objects, each of which has:\n"
2259 "{txid, vout, scriptPubKey, amount, confirmations}\n"
2260 "\nArguments:\n"
2261 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
2262 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
2263 "3. \"addresses\" (string) A json array of bitcoin addresses to filter\n"
2264 " [\n"
2265 " \"address\" (string) bitcoin address\n"
2266 " ,...\n"
2267 " ]\n"
2268 "\nResult\n"
2269 "[ (array of json object)\n"
2270 " {\n"
2271 " \"txid\" : \"txid\", (string) the transaction id \n"
2272 " \"vout\" : n, (numeric) the vout value\n"
2273 " \"address\" : \"address\", (string) the bitcoin address\n"
2274 " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
2275 " \"scriptPubKey\" : \"key\", (string) the script key\n"
2276 " \"amount\" : x.xxx, (numeric) the transaction amount in btc\n"
2277 " \"confirmations\" : n (numeric) The number of confirmations\n"
2278 " }\n"
2279 " ,...\n"
2280 "]\n"
2281
2282 "\nExamples\n"
2283 + HelpExampleCli("listunspent", "")
2284 + HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2285 + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2286 );
2287
0b9dc9c8 2288 RPCTypeCheck(params, boost::assign::list_of(int_type)(int_type)(array_type));
ea9e82df 2289
0b9dc9c8
JS
2290 int nMinDepth = 1;
2291 if (params.size() > 0)
ea9e82df
JS
2292 nMinDepth = params[0].get_int();
2293
0b9dc9c8
JS
2294 int nMaxDepth = 9999999;
2295 if (params.size() > 1)
ea9e82df
JS
2296 nMaxDepth = params[1].get_int();
2297
0b9dc9c8
JS
2298 set<CBitcoinAddress> setAddress;
2299 if (params.size() > 2) {
2300 Array inputs = params[2].get_array();
2301 BOOST_FOREACH(Value& input, inputs) {
2302 CBitcoinAddress address(input.get_str());
2303 if (!address.IsValid())
ea9e82df 2304 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+input.get_str());
0b9dc9c8 2305 if (setAddress.count(address))
ea9e82df
JS
2306 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
2307 setAddress.insert(address);
0b9dc9c8
JS
2308 }
2309 }
ea9e82df 2310
0b9dc9c8
JS
2311 Array results;
2312 vector<COutput> vecOutputs;
2313 assert(pwalletMain != NULL);
2314 LOCK2(cs_main, pwalletMain->cs_wallet);
219953ce 2315 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
0b9dc9c8
JS
2316 BOOST_FOREACH(const COutput& out, vecOutputs) {
2317 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
ea9e82df
JS
2318 continue;
2319
0b9dc9c8
JS
2320 if (setAddress.size()) {
2321 CTxDestination address;
2322 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
ea9e82df
JS
2323 continue;
2324
0b9dc9c8 2325 if (!setAddress.count(address))
ea9e82df 2326 continue;
0b9dc9c8 2327 }
ea9e82df 2328
0b9dc9c8
JS
2329 CAmount nValue = out.tx->vout[out.i].nValue;
2330 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
2331 Object entry;
805344dc 2332 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
0b9dc9c8
JS
2333 entry.push_back(Pair("vout", out.i));
2334 CTxDestination address;
2335 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
2336 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
2337 if (pwalletMain->mapAddressBook.count(address))
ea9e82df 2338 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
0b9dc9c8
JS
2339 }
2340 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
2341 if (pk.IsPayToScriptHash()) {
2342 CTxDestination address;
2343 if (ExtractDestination(pk, address)) {
8b08d953 2344 const CScriptID& hash = boost::get<CScriptID>(address);
0b9dc9c8
JS
2345 CScript redeemScript;
2346 if (pwalletMain->GetCScript(hash, redeemScript))
ea9e82df 2347 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
0b9dc9c8
JS
2348 }
2349 }
2350 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
2351 entry.push_back(Pair("confirmations",out.nDepth));
2352 entry.push_back(Pair("spendable", out.fSpendable));
2353 results.push_back(entry);
2354 }
ea9e82df 2355
0b9dc9c8 2356 return results;
c9fd9078 2357}
730790f7 2358
1737627c
SB
2359Value zc_sample_joinsplit(const json_spirit::Array& params, bool fHelp)
2360{
2361 if (fHelp) {
2362 throw runtime_error(
2363 "zcsamplejoinsplit\n"
2364 "\n"
2365 "Perform a joinsplit and return the JSDescription.\n"
2366 );
2367 }
2368
2369 LOCK(cs_main);
2370
2371 uint256 pubKeyHash;
2372 uint256 anchor = ZCIncrementalMerkleTree().root();
2373 JSDescription samplejoinsplit(*pzcashParams,
2374 pubKeyHash,
2375 anchor,
2376 {JSInput(), JSInput()},
2377 {JSOutput(), JSOutput()},
2378 0,
2379 0);
2380
2381 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2382 ss << samplejoinsplit;
2383
2384 return HexStr(ss.begin(), ss.end());
2385}
2386
6962bb3d
TH
2387Value zc_benchmark(const json_spirit::Array& params, bool fHelp)
2388{
2389 if (!EnsureWalletIsAvailable(fHelp)) {
2390 return Value::null;
2391 }
2392
2393 if (fHelp || params.size() < 2) {
2394 throw runtime_error(
2395 "zcbenchmark benchmarktype samplecount\n"
2396 "\n"
2397 "Runs a benchmark of the selected type samplecount times,\n"
2398 "returning the running times of each sample.\n"
2399 "\n"
2400 "Output: [\n"
2401 " {\n"
2402 " \"runningtime\": runningtime\n"
2403 " },\n"
2404 " {\n"
2405 " \"runningtime\": runningtime\n"
2406 " }\n"
2407 " ...\n"
2408 "]\n"
2409 );
2410 }
2411
2412 LOCK(cs_main);
2413
2414 std::string benchmarktype = params[0].get_str();
2415 int samplecount = params[1].get_int();
2416
2417 if (samplecount <= 0) {
2418 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount");
2419 }
2420
2421 std::vector<double> sample_times;
2422
2423 if (benchmarktype == "createjoinsplit") {
2424 /* Load the proving now key so that it doesn't happen as part of the
2425 * first joinsplit. */
2dc35992 2426 pzcashParams->loadProvingKey();
6962bb3d
TH
2427 }
2428
1737627c 2429 JSDescription samplejoinsplit;
2fbbde59
SB
2430
2431 if (benchmarktype == "verifyjoinsplit") {
1737627c
SB
2432 CDataStream ss(ParseHexV(params[2].get_str(), "js"), SER_NETWORK, PROTOCOL_VERSION);
2433 ss >> samplejoinsplit;
2fbbde59
SB
2434 }
2435
6962bb3d
TH
2436 for (int i = 0; i < samplecount; i++) {
2437 if (benchmarktype == "sleep") {
2438 sample_times.push_back(benchmark_sleep());
2439 } else if (benchmarktype == "parameterloading") {
2440 sample_times.push_back(benchmark_parameter_loading());
2441 } else if (benchmarktype == "createjoinsplit") {
2442 sample_times.push_back(benchmark_create_joinsplit());
2443 } else if (benchmarktype == "verifyjoinsplit") {
1737627c 2444 sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
bf8def97 2445 } else if (benchmarktype == "solveequihash") {
f7478de6
JG
2446 if (params.size() < 3) {
2447 sample_times.push_back(benchmark_solve_equihash(true));
2448 } else {
2449 int nThreads = params[2].get_int();
2450 sample_times.push_back(benchmark_solve_equihash_threaded(nThreads));
2451 }
bf8def97 2452 } else if (benchmarktype == "verifyequihash") {
a1cd1a27 2453 sample_times.push_back(benchmark_verify_equihash());
f5edc37f 2454 } else if (benchmarktype == "validatelargetx") {
9c45b501 2455 sample_times.push_back(benchmark_large_tx());
6962bb3d
TH
2456 } else {
2457 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
2458 }
2459 }
2460
2461 Array results;
2462 for (int i = 0; i < samplecount; i++) {
2463 Object result;
2464 result.push_back(Pair("runningtime", sample_times.at(i)));
2465 results.push_back(result);
2466 }
2467
2468 return results;
2469}
2470
a8ac403d
SB
2471Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
2472{
f15b9549
NW
2473 if (!EnsureWalletIsAvailable(fHelp)) {
2474 return Value::null;
2475 }
2476
2477 if (fHelp || params.size() != 2) {
2478 throw runtime_error(
eae37941 2479 "zcrawreceive zcsecretkey encryptednote\n"
f15b9549 2480 "\n"
eae37941 2481 "Scheduled for deprecation. This call will be removed in 1.0.\n"
4bc00dc1 2482 "Decrypts encryptednote and checks if the coin commitments\n"
f15b9549
NW
2483 "are in the blockchain as indicated by the \"exists\" result.\n"
2484 "\n"
2485 "Output: {\n"
2486 " \"amount\": value,\n"
4bc00dc1 2487 " \"note\": noteplaintext,\n"
f15b9549
NW
2488 " \"exists\": exists\n"
2489 "}\n"
2490 );
2491 }
2492
a8ac403d 2493 RPCTypeCheck(params, boost::assign::list_of(str_type)(str_type));
f15b9549 2494
a8ac403d
SB
2495 LOCK(cs_main);
2496
0d6864e4
SB
2497 CZCSpendingKey spendingkey(params[0].get_str());
2498 SpendingKey k = spendingkey.Get();
a8ac403d 2499
6c36a9fe
SB
2500 uint256 epk;
2501 unsigned char nonce;
2502 ZCNoteEncryption::Ciphertext ct;
2dc35992 2503 uint256 h_sig;
6c36a9fe
SB
2504
2505 {
4bc00dc1 2506 CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
6c36a9fe
SB
2507 try {
2508 ssData >> nonce;
2509 ssData >> epk;
2510 ssData >> ct;
2dc35992 2511 ssData >> h_sig;
6c36a9fe
SB
2512 } catch(const std::exception &) {
2513 throw runtime_error(
4bc00dc1 2514 "encrypted_note could not be decoded"
6c36a9fe
SB
2515 );
2516 }
2517 }
2518
2dc35992 2519 ZCNoteDecryption decryptor(k.viewing_key());
a8ac403d 2520
2dc35992
SB
2521 NotePlaintext npt = NotePlaintext::decrypt(
2522 decryptor,
2523 ct,
2524 epk,
2525 h_sig,
2526 nonce
2527 );
2528 PaymentAddress payment_addr = k.address();
2529 Note decrypted_note = npt.note(payment_addr);
a8ac403d
SB
2530
2531 assert(pwalletMain != NULL);
2dc35992 2532 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
a8ac403d 2533 uint256 anchor;
2dc35992 2534 uint256 commitment = decrypted_note.cm();
4bc00dc1 2535 pwalletMain->WitnessNoteCommitment(
2dc35992
SB
2536 {commitment},
2537 witnesses,
2538 anchor
2539 );
a8ac403d
SB
2540
2541 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2dc35992 2542 ss << npt;
a8ac403d
SB
2543
2544 Object result;
2dc35992 2545 result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value)));
4bc00dc1 2546 result.push_back(Pair("note", HexStr(ss.begin(), ss.end())));
2dc35992 2547 result.push_back(Pair("exists", (bool) witnesses[0]));
a8ac403d
SB
2548 return result;
2549}
2550
2dc35992
SB
2551
2552
b7e4abd6 2553Value zc_raw_joinsplit(const json_spirit::Array& params, bool fHelp)
730790f7 2554{
f15b9549
NW
2555 if (!EnsureWalletIsAvailable(fHelp)) {
2556 return Value::null;
2557 }
2558
2559 if (fHelp || params.size() != 5) {
2560 throw runtime_error(
eae37941 2561 "zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
4bc00dc1 2562 " inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
f15b9549
NW
2563 " outputs: a JSON object mapping {zcaddr: value, ...}\n"
2564 "\n"
eae37941 2565 "Scheduled for deprecation. This call will be removed in 1.0.\n"
b7e4abd6 2566 "Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
f15b9549
NW
2567 "Outputs are confidential between sender/receiver. The vpub_old and\n"
2568 "vpub_new values are globally public and move transparent value into\n"
2569 "or out of the confidential value store, respectively.\n"
2570 "\n"
2571 "Note: The caller is responsible for delivering the output enc1 and\n"
2572 "enc2 to the appropriate recipients, as well as signing rawtxout and\n"
2573 "ensuring it is mined. (A future RPC call will deliver the confidential\n"
2574 "payments in-band on the blockchain.)\n"
2575 "\n"
2576 "Output: {\n"
4bc00dc1
DH
2577 " \"encryptednote1\": enc1,\n"
2578 " \"encryptednote2\": enc2,\n"
f15b9549
NW
2579 " \"rawtxn\": rawtxout\n"
2580 "}\n"
2581 );
2582 }
2583
a8ac403d 2584 LOCK(cs_main);
730790f7
SB
2585
2586 CTransaction tx;
2587 if (!DecodeHexTx(tx, params[0].get_str()))
2588 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2589
2590 Object inputs = params[1].get_obj();
2591 Object outputs = params[2].get_obj();
2592
2593 CAmount vpub_old(0);
2594 CAmount vpub_new(0);
2595
2596 if (params[3].get_real() != 0.0)
2597 vpub_old = AmountFromValue(params[3]);
2598
2599 if (params[4].get_real() != 0.0)
2600 vpub_new = AmountFromValue(params[4]);
2601
b7e4abd6
SB
2602 std::vector<JSInput> vjsin;
2603 std::vector<JSOutput> vjsout;
2dc35992
SB
2604 std::vector<Note> notes;
2605 std::vector<SpendingKey> keys;
2606 std::vector<uint256> commitments;
a8ac403d 2607
730790f7
SB
2608 BOOST_FOREACH(const Pair& s, inputs)
2609 {
0d6864e4
SB
2610 CZCSpendingKey spendingkey(s.value_.get_str());
2611 SpendingKey k = spendingkey.Get();
a8ac403d 2612
2dc35992 2613 keys.push_back(k);
a8ac403d 2614
2dc35992 2615 NotePlaintext npt;
a8ac403d 2616
2dc35992 2617 {
4bc00dc1 2618 CDataStream ssData(ParseHexV(s.name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
2dc35992 2619 ssData >> npt;
a8ac403d
SB
2620 }
2621
2dc35992
SB
2622 PaymentAddress addr = k.address();
2623 Note note = npt.note(addr);
2624 notes.push_back(note);
2625 commitments.push_back(note.cm());
2626 }
2627
2628 uint256 anchor;
2629 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
4bc00dc1 2630 pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
2dc35992
SB
2631
2632 assert(witnesses.size() == notes.size());
2633 assert(notes.size() == keys.size());
2634
2635 {
2636 for (size_t i = 0; i < witnesses.size(); i++) {
2637 if (!witnesses[i]) {
2638 throw runtime_error(
b7e4abd6 2639 "joinsplit input could not be found in tree"
2dc35992
SB
2640 );
2641 }
2642
b7e4abd6 2643 vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
2dc35992 2644 }
730790f7 2645 }
730790f7 2646
b7e4abd6
SB
2647 while (vjsin.size() < ZC_NUM_JS_INPUTS) {
2648 vjsin.push_back(JSInput());
a8ac403d 2649 }
730790f7
SB
2650
2651 BOOST_FOREACH(const Pair& s, outputs)
2652 {
e104fcdd
SB
2653 CZCPaymentAddress pubaddr(s.name_);
2654 PaymentAddress addrTo = pubaddr.Get();
730790f7
SB
2655 CAmount nAmount = AmountFromValue(s.value_);
2656
b7e4abd6 2657 vjsout.push_back(JSOutput(addrTo, nAmount));
730790f7
SB
2658 }
2659
b7e4abd6
SB
2660 while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
2661 vjsout.push_back(JSOutput());
730790f7
SB
2662 }
2663
2664 // TODO
b7e4abd6
SB
2665 if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
2666 throw runtime_error("unsupported joinsplit input/output counts");
730790f7
SB
2667 }
2668
320f2cc7
SB
2669 uint256 joinSplitPubKey;
2670 unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
2671 crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
6aae9d1a
TH
2672
2673 CMutableTransaction mtx(tx);
2674 mtx.nVersion = 2;
2675 mtx.joinSplitPubKey = joinSplitPubKey;
2676
22de1602
SB
2677 JSDescription jsdesc(*pzcashParams,
2678 joinSplitPubKey,
2679 anchor,
2680 {vjsin[0], vjsin[1]},
2681 {vjsout[0], vjsout[1]},
2682 vpub_old,
2683 vpub_new);
320f2cc7 2684
22de1602 2685 assert(jsdesc.Verify(*pzcashParams, joinSplitPubKey));
730790f7 2686
22de1602 2687 mtx.vjoinsplit.push_back(jsdesc);
730790f7 2688
6aae9d1a
TH
2689 // Empty output script.
2690 CScript scriptCode;
2691 CTransaction signTx(mtx);
2692 uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
6aae9d1a
TH
2693
2694 // Add the signature
320f2cc7
SB
2695 assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
2696 dataToBeSigned.begin(), 32,
2697 joinSplitPrivKey
2698 ) == 0);
2699
2700 // Sanity check
2701 assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
2702 dataToBeSigned.begin(), 32,
2703 mtx.joinSplitPubKey.begin()
2704 ) == 0);
6aae9d1a 2705
730790f7
SB
2706 CTransaction rawTx(mtx);
2707
2708 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2709 ss << rawTx;
2710
4bc00dc1
DH
2711 std::string encryptedNote1;
2712 std::string encryptedNote2;
6c36a9fe
SB
2713 {
2714 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
2715 ss2 << ((unsigned char) 0x00);
22de1602
SB
2716 ss2 << jsdesc.ephemeralKey;
2717 ss2 << jsdesc.ciphertexts[0];
2718 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
6c36a9fe 2719
4bc00dc1 2720 encryptedNote1 = HexStr(ss2.begin(), ss2.end());
6c36a9fe
SB
2721 }
2722 {
2723 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
2724 ss2 << ((unsigned char) 0x01);
22de1602
SB
2725 ss2 << jsdesc.ephemeralKey;
2726 ss2 << jsdesc.ciphertexts[1];
2727 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
6c36a9fe 2728
4bc00dc1 2729 encryptedNote2 = HexStr(ss2.begin(), ss2.end());
6c36a9fe
SB
2730 }
2731
730790f7 2732 Object result;
4bc00dc1
DH
2733 result.push_back(Pair("encryptednote1", encryptedNote1));
2734 result.push_back(Pair("encryptednote2", encryptedNote2));
730790f7
SB
2735 result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
2736 return result;
2737}
2738
2739Value zc_raw_keygen(const json_spirit::Array& params, bool fHelp)
2740{
f15b9549
NW
2741 if (!EnsureWalletIsAvailable(fHelp)) {
2742 return Value::null;
2743 }
2744
2745 if (fHelp || params.size() != 0) {
2746 throw runtime_error(
eae37941 2747 "zcrawkeygen\n"
f15b9549 2748 "\n"
eae37941 2749 "Scheduled for deprecation. This call will be removed in 1.0.\n"
f15b9549
NW
2750 "Generate a zcaddr which can send and receive confidential values.\n"
2751 "\n"
2752 "Output: {\n"
2753 " \"zcaddress\": zcaddr,\n"
2754 " \"zcsecretkey\": zcsecretkey,\n"
2755 "}\n"
2756 );
2757 }
2758
2dc35992
SB
2759 auto k = SpendingKey::random();
2760 auto addr = k.address();
2761 auto viewing_key = k.viewing_key();
730790f7 2762
2dc35992 2763 CDataStream viewing(SER_NETWORK, PROTOCOL_VERSION);
730790f7 2764
2dc35992 2765 viewing << viewing_key;
730790f7 2766
e104fcdd 2767 CZCPaymentAddress pubaddr(addr);
0d6864e4 2768 CZCSpendingKey spendingkey(k);
2dc35992 2769 std::string viewing_hex = HexStr(viewing.begin(), viewing.end());
730790f7
SB
2770
2771 Object result;
e104fcdd 2772 result.push_back(Pair("zcaddress", pubaddr.ToString()));
0d6864e4 2773 result.push_back(Pair("zcsecretkey", spendingkey.ToString()));
2dc35992 2774 result.push_back(Pair("zcviewingkey", viewing_hex));
730790f7 2775 return result;
f15b9549 2776}
c1c45943
S
2777
2778
2779Value z_getnewaddress(const Array& params, bool fHelp)
2780{
2781 if (!EnsureWalletIsAvailable(fHelp))
2782 return Value::null;
2783
2784 if (fHelp || params.size() > 1)
2785 throw runtime_error(
2786 "z_getnewaddress\n"
2787 "\nReturns a new zaddr for receiving payments.\n"
2788 "\nArguments:\n"
2789 "\nResult:\n"
2790 "\"zcashaddress\" (string) The new zaddr\n"
2791 "\nExamples:\n"
2792 + HelpExampleCli("z_getnewaddress", "")
2793 + HelpExampleRpc("z_getnewaddress", "")
2794 );
2795
2796 LOCK2(cs_main, pwalletMain->cs_wallet);
2797
2798 CZCPaymentAddress pubaddr = pwalletMain->GenerateNewZKey();
2799 std::string result = pubaddr.ToString();
2800 return result;
2801}
2802
e709997f
S
2803
2804Value z_listaddresses(const Array& params, bool fHelp)
2805{
2806 if (!EnsureWalletIsAvailable(fHelp))
2807 return Value::null;
2808
2809 if (fHelp || params.size() > 1)
2810 throw runtime_error(
2811 "z_listaddresses\n"
2812 "\nReturns the list of zaddr belonging to the wallet.\n"
2813 "\nArguments:\n"
2814 "\nResult:\n"
2815 "[ (json array of string)\n"
2816 " \"zaddr\" (string) a zaddr belonging to the wallet\n"
2817 " ,...\n"
2818 "]\n"
2819 "\nExamples:\n"
2820 + HelpExampleCli("z_listaddresses", "")
2821 + HelpExampleRpc("z_listaddresses", "")
2822 );
2823
2824 LOCK2(cs_main, pwalletMain->cs_wallet);
2825
2826 Array ret;
2827 std::set<libzcash::PaymentAddress> addresses;
2828 pwalletMain->GetPaymentAddresses(addresses);
2829 for (auto addr : addresses ) {
2830 ret.push_back(CZCPaymentAddress(addr).ToString());
2831 }
2832 return ret;
2833}
2834
fc72c078
S
2835
2836Value z_getoperationstatus(const Array& params, bool fHelp)
2837{
2838 if (!EnsureWalletIsAvailable(fHelp))
2839 return Value::null;
2840
2841 if (fHelp || params.size() != 1)
2842 throw runtime_error(
2843 "z_getoperationstatus \"operationid\"\n"
2844 "\nGet operation status and any associated result or error data."
2845 + HelpRequiringPassphrase() + "\n"
2846 "\nArguments:\n"
2847 "1. \"operationid\" (string, required) The operation id returned by an async operation call.\n"
2848 "\nResult:\n"
2849 "\" object\" (string) FIXME: ASYNC operation object \n"
2850 " with some key value pairs.\n"
2851 );
2852
2853 LOCK2(cs_main, pwalletMain->cs_wallet);
2854
2855 AsyncRPCOperationId id = params[0].get_str();
2856
2857 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
2858 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
2859 if (!operation) {
2860 throw JSONRPCError(RPC_INVALID_PARAMETER, "No operation exists for that id.");
2861 }
2862
2863 Value status = operation->getStatus();
2864
2865 // Remove operation from memory when it has finished and the caller has retrieved the result and reason for finishing.
2866 if (operation->isSuccess() || operation->isFailed() || operation->isCancelled()) {
2867 q->popOperationForId(id);
2868 }
2869
2870 return status;
2871}
2872
2873
2874Value z_sendmany(const Array& params, bool fHelp)
2875{
2876 if (!EnsureWalletIsAvailable(fHelp))
2877 return Value::null;
2878
2879 if (fHelp || params.size() < 2 || params.size() > 3)
2880 throw runtime_error(
2881 "z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf )\n"
2882 "\n*** THIS COMMAND HAS NOT BEEN IMPLEMENTED YET ***"
2883 "\nSend multiple times. Amounts are double-precision floating point numbers."
2884 + HelpRequiringPassphrase() + "\n"
2885 "\nArguments:\n"
2886 "1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from.\n"
2887 "2. \"amounts\" (array, required) An array of json objects representing the amounts to send.\n"
2888 " [{\n"
2889 " \"address\":address (string, required) The address is a taddr or zaddr\n"
2890 " \"amount\":amount (numeric, required) The numeric amount in ZEC is the value\n"
2891 " \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
2892 " }, ... ]\n"
2893 "3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
2894 "\nResult:\n"
2895 "\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
2896 );
2897
2898 LOCK2(cs_main, pwalletMain->cs_wallet);
2899
2900
2901 // Check that the from address is valid.
2902 auto fromaddress = params[0].get_str();
2903 bool fromTaddr = false;
2904 CBitcoinAddress taddr(fromaddress);
2905 fromTaddr = taddr.IsValid();
2906 libzcash::PaymentAddress zaddr;
2907 if (!fromTaddr) {
2908 CZCPaymentAddress address(fromaddress);
2909 try {
2910 zaddr = address.Get();
2911 } catch (std::runtime_error) {
2912 // invalid
2913 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
2914 }
2915 }
2916
2917 // Check that we have the spending key?
2918 if (!fromTaddr) {
2919 if (!pwalletMain->HaveSpendingKey(zaddr)) {
2920 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
2921 }
2922 }
2923
2924
2925 Array outputs = params[1].get_array();
2926
2927 if (outputs.size()==0)
2928 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
2929
2930 // Keep track of addresses to spot duplicates
2931 set<std::string> setAddress;
2932
2933 // Recipients
2934 std::vector<SendManyRecipient> recipients;
2935
2936 BOOST_FOREACH(Value& output, outputs)
2937 {
2938 if (output.type() != obj_type)
2939 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
2940 const Object& o = output.get_obj();
2941
2942 RPCTypeCheck(o, boost::assign::map_list_of("address", str_type)("amount", real_type));
2943
2944 // sanity check, report error if unknown key-value pairs
2945// for (auto& p : o) {
2946 for (const Pair& p : o) {
2947 std::string s = p.name_;
2948 if (s != "address" && s != "amount" && s!="memo")
2949 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown key: ")+s);
2950 }
2951
2952 string address = find_value(o, "address").get_str();
2953 bool isZaddr = false;
2954 CBitcoinAddress taddr(address);
2955 if (!taddr.IsValid()) {
2956 try {
2957 CZCPaymentAddress zaddr(address);
2958 zaddr.Get();
2959 isZaddr = true;
2960 } catch (std::runtime_error) {
2961 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
2962 }
2963 }
2964
2965 if (setAddress.count(address))
2966 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address);
2967 setAddress.insert(address);
2968
2969 Value memoValue = find_value(o, "memo");
2970 string memo;
2971 if (!memoValue.is_null()) {
2972 memo = memoValue.get_str();
2973 if (!isZaddr) {
2974 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
2975 } else if (!IsHex(memo)) {
2976 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
2977 }
2978 }
2979
2980 //int nOutput = find_value(o, "amount").get_real(); // int();
2981 Value av = find_value(o, "amount");
2982 CAmount nAmount = AmountFromValue( av );
2983 if (nAmount < 0)
2984 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
2985
2986 recipients.push_back( SendManyRecipient(address, nAmount, memo) );
2987 }
2988
2989
2990
2991 // Minimum confirmations
2992 int nMinDepth = 1;
2993 if (params.size() > 2)
2994 nMinDepth = params[2].get_int();
2995
2996
2997// std::vector<string>
2998// GetPaymentAddresses(addresses);
2999// for (auto addr : addresses ) {
3000// ret.push_back(CZCPaymentAddress(addr).ToString());
3001// }
3002
3003
3004 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3005 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(fromaddress, recipients, nMinDepth) );
3006 // operation->
3007 //std::shared_ptr<AsyncRPCOperation> operation = make_shared<AsyncRPCOperation>(AsyncRPCOperation_sendmany());
3008 q->addOperation(operation);
3009 AsyncRPCOperationId operationId = operation->getId();
3010 return operationId;
3011// return Value::null;
3012
3013// Array ret;
3014// std::set<libzcash::PaymentAddress> addresses;
3015// pwalletMain->GetPaymentAddresses(addresses);
3016// for (auto addr : addresses ) {
3017// ret.push_back(CZCPaymentAddress(addr).ToString());
3018// }
3019// return ret;
3020}
This page took 0.63997 seconds and 4 git commands to generate.