Browse Source

Implemented transfer RPC call.

cn_mining
Jianping Wu 5 years ago
parent
commit
b39ed3748d
  1. 128
      src/wallet/rpcwallet.cpp

128
src/wallet/rpcwallet.cpp

@ -1221,6 +1221,133 @@ UniValue sendmany(const JSONRPCRequest& request) @@ -1221,6 +1221,133 @@ UniValue sendmany(const JSONRPCRequest& request)
return wtx.GetHash().GetHex();
}
static CAmount AmountFromIntegerValue(const UniValue& value)
{
if (!value.isNum())
throw std::runtime_error("Amount is not a number or string");
CAmount amount = value.get_int64();
if (!MoneyRange(amount))
throw std::runtime_error("Amount out of range");
return amount;
}
// Cryptnote JSON RPC
UniValue transfer(const JSONRPCRequest& request)
{
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 12)
throw std::runtime_error(
"transfer [{\"address\":amount,...}, ...] \n"
"\nSend multiple times. Amounts are in atomic units."
+ HelpRequiringPassphrase(pwallet) + "\n"
"\nArguments:\n"
"1. \"destinations\" (string, required) A json object with addresses and amounts\n"
" [{\n"
" \"address\":address (string) The kevacoin address\n"
" \"amount\":amount (numeric) The numeric amount in atomic unut\n"
" ,...\n"
" }, ...]\n"
"\nResult:\n"
"\"txid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
" the number of addresses.\n"
"\nExamples:\n"
"\nSend two amounts to two different addresses:\n"
+ HelpExampleCli("sendmany", "\"\" \"{\\\"LEr4hNAefWYhBMgxCFP2Po1NPrUeiK8kM2\\\":0.01,\\\"LbhhnrHHVFP1eUjP1tdNIYeEVsNHfN9FCw\\\":0.02}\"") +
"\nSend two amounts to two different addresses setting the confirmation and comment:\n"
+ HelpExampleCli("sendmany", "\"\" \"{\\\"LEr4hNAefWYhBMgxCFP2Po1NPrUeiK8kM2\\\":0.01,\\\"LbhhnrHHVFP1eUjP1tdNIYeEVsNHfN9FCw\\\":0.02}\" 6 \"testing\"") +
"\nSend two amounts to two different addresses, subtract fee from amount:\n"
+ HelpExampleCli("sendmany", "\"\" \"{\\\"LEr4hNAefWYhBMgxCFP2Po1NPrUeiK8kM2\\\":0.01,\\\"LbhhnrHHVFP1eUjP1tdNIYeEVsNHfN9FCw\\\":0.02}\" 1 \"\" \"[\\\"LEr4hNAefWYhBMgxCFP2Po1NPrUeiK8kM2\\\",\\\"LbhhnrHHVFP1eUjP1tdNIYeEVsNHfN9FCw\\\"]\"") +
"\nAs a json rpc call\n"
+ HelpExampleRpc("sendmany", "\"\", {\"LEr4hNAefWYhBMgxCFP2Po1NPrUeiK8kM2\":0.01,\"LbhhnrHHVFP1eUjP1tdNIYeEVsNHfN9FCw\":0.02}, 6, \"testing\"")
);
ObserveSafeMode();
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
LOCK2(cs_main, pwallet->cs_wallet);
if (pwallet->GetBroadcastTransactions() && !g_connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
}
UniValue sendToList = request.params[0].get_array();
CWalletTx wtx;
CCoinControl coin_control;
std::set<CTxDestination> destinations;
std::vector<CRecipient> vecSend;
CAmount totalAmount = 0;
for (unsigned int idx = 0; idx < sendToList.size(); idx++) {
const UniValue& sendTo = sendToList[idx].get_obj();
const UniValue& addr = find_value(sendTo, "address");
if (addr.isNull()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, missing address: "));
}
std::string addrStr = addr.get_str();
CTxDestination dest = DecodeDestination(addrStr);
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Kevacoin address: ") + addrStr);
}
if (destinations.count(dest)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + addrStr);
}
destinations.insert(dest);
CScript scriptPubKey = GetScriptForDestination(dest);
const UniValue& amount = find_value(sendTo, "amount");
CAmount nAmount = AmountFromIntegerValue(amount);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
totalAmount += nAmount;
CRecipient recipient = {scriptPubKey, nAmount, false};
vecSend.push_back(recipient);
}
EnsureWalletIsUnlocked(pwallet);
// Check funds
CAmount nBalance = pwallet->GetLegacyBalance(ISMINE_SPENDABLE, 1, nullptr);
if (totalAmount > nBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
// Send
CReserveKey keyChange(pwallet);
CAmount nFeeRequired = 0;
int nChangePosRet = -1;
std::string strFailReason;
std::vector<unsigned char> empty;
bool fCreated = pwallet->CreateTransaction(vecSend, nullptr, empty, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control);
if (!fCreated)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
CValidationState state;
if (!pwallet->CommitTransaction(wtx, keyChange, g_connman.get(), state)) {
strFailReason = strprintf("Transaction commit failed:: %s", state.GetRejectReason());
throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
}
UniValue result(UniValue::VOBJ);
result.push_back(Pair("amount", (uint64_t)totalAmount));
result.push_back(Pair("fee", (uint64_t)nFeeRequired));
result.push_back(Pair("multisig_txset", ""));
result.push_back(Pair("tx_blob", ""));
result.push_back(Pair("tx_hash", wtx.GetHash().GetHex()));
result.push_back(Pair("tx_key", ""));
result.push_back(Pair("tx_metadata", ""));
result.push_back(Pair("unsigned_txset", ""));
return result;
}
UniValue addmultisigaddress(const JSONRPCRequest& request)
{
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
@ -3658,6 +3785,7 @@ static const CRPCCommand commands[] = @@ -3658,6 +3785,7 @@ static const CRPCCommand commands[] =
{ "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },
{ "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
{ "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
{ "wallet", "transfer", &transfer, {"destinations"} },
{ "generating", "generate", &generate, {"nblocks","maxtries"} },

Loading…
Cancel
Save