mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
GatewayBalances RPC command
RPC command to get a gateway's hot wallet balances and total obligations.
This commit is contained in:
@@ -2967,6 +2967,9 @@
|
|||||||
<ClCompile Include="..\..\src\ripple\rpc\handlers\FetchInfo.cpp">
|
<ClCompile Include="..\..\src\ripple\rpc\handlers\FetchInfo.cpp">
|
||||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\ripple\rpc\handlers\GatewayBalances.cpp">
|
||||||
|
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\rpc\handlers\GetCounts.cpp">
|
<ClCompile Include="..\..\src\ripple\rpc\handlers\GetCounts.cpp">
|
||||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|||||||
@@ -3651,6 +3651,9 @@
|
|||||||
<ClCompile Include="..\..\src\ripple\rpc\handlers\FetchInfo.cpp">
|
<ClCompile Include="..\..\src\ripple\rpc\handlers\FetchInfo.cpp">
|
||||||
<Filter>ripple\rpc\handlers</Filter>
|
<Filter>ripple\rpc\handlers</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\ripple\rpc\handlers\GatewayBalances.cpp">
|
||||||
|
<Filter>ripple\rpc\handlers</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\rpc\handlers\GetCounts.cpp">
|
<ClCompile Include="..\..\src\ripple\rpc\handlers\GetCounts.cpp">
|
||||||
<Filter>ripple\rpc\handlers</Filter>
|
<Filter>ripple\rpc\handlers</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|||||||
@@ -790,6 +790,46 @@ private:
|
|||||||
return jvRequest;
|
return jvRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parse gateway balances
|
||||||
|
// gateway_balances [<ledger>] <issuer_account> [ <hotwallet> [ <hotwallet> ]]
|
||||||
|
|
||||||
|
Json::Value parseGatewayBalances (Json::Value const& jvParams)
|
||||||
|
{
|
||||||
|
unsigned int index = 0;
|
||||||
|
const unsigned int size = jvParams.size ();
|
||||||
|
|
||||||
|
Json::Value jvRequest;
|
||||||
|
|
||||||
|
std::string param = jvParams[index++].asString ();
|
||||||
|
if (param.empty ())
|
||||||
|
return RPC::make_param_error ("Invalid first parameter");
|
||||||
|
|
||||||
|
if (param[0] != 'r')
|
||||||
|
{
|
||||||
|
if (param.size() == 64)
|
||||||
|
jvRequest[jss::ledger_hash] = param;
|
||||||
|
else
|
||||||
|
jvRequest[jss::ledger_index] = param;
|
||||||
|
|
||||||
|
if (size <= index)
|
||||||
|
return RPC::make_param_error ("Invalid hotwallet");
|
||||||
|
|
||||||
|
param = jvParams[index++].asString ();
|
||||||
|
}
|
||||||
|
|
||||||
|
jvRequest[jss::account] = param;
|
||||||
|
|
||||||
|
if (index < size)
|
||||||
|
{
|
||||||
|
Json::Value& hotWallets =
|
||||||
|
(jvRequest["hotwallet"] = Json::arrayValue);
|
||||||
|
while (index < size)
|
||||||
|
hotWallets.append (jvParams[index++].asString ());
|
||||||
|
}
|
||||||
|
|
||||||
|
return jvRequest;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -858,6 +898,7 @@ public:
|
|||||||
{ "consensus_info", &RPCParser::parseAsIs, 0, 0 },
|
{ "consensus_info", &RPCParser::parseAsIs, 0, 0 },
|
||||||
{ "feature", &RPCParser::parseFeature, 0, 2 },
|
{ "feature", &RPCParser::parseFeature, 0, 2 },
|
||||||
{ "fetch_info", &RPCParser::parseFetchInfo, 0, 1 },
|
{ "fetch_info", &RPCParser::parseFetchInfo, 0, 1 },
|
||||||
|
{ "gateway_balances", &RPCParser::parseGatewayBalances , 1, -1 },
|
||||||
{ "get_counts", &RPCParser::parseGetCounts, 0, 1 },
|
{ "get_counts", &RPCParser::parseGetCounts, 0, 1 },
|
||||||
{ "json", &RPCParser::parseJson, 2, 2 },
|
{ "json", &RPCParser::parseJson, 2, 2 },
|
||||||
{ "ledger", &RPCParser::parseLedger, 0, 2 },
|
{ "ledger", &RPCParser::parseLedger, 0, 2 },
|
||||||
|
|||||||
@@ -79,8 +79,10 @@ JSS ( age ); // out: UniqueNodeList, NetworkOPs
|
|||||||
JSS ( alternatives ); // out: PathRequest, RipplePathFind
|
JSS ( alternatives ); // out: PathRequest, RipplePathFind
|
||||||
JSS ( amendment_blocked ); // out: NetworkOPs
|
JSS ( amendment_blocked ); // out: NetworkOPs
|
||||||
JSS ( asks ); // out: Subscribe
|
JSS ( asks ); // out: Subscribe
|
||||||
|
JSS ( assets ); // out: GatewayBalances
|
||||||
JSS ( authorized ); // out: AccountLines
|
JSS ( authorized ); // out: AccountLines
|
||||||
JSS ( balance ); // out: AccountLines
|
JSS ( balance ); // out: AccountLines
|
||||||
|
JSS ( balances ); // out: GatewayBalances
|
||||||
JSS ( base ); // out: LogLevel
|
JSS ( base ); // out: LogLevel
|
||||||
JSS ( base_fee ); // out: NetworkOPs
|
JSS ( base_fee ); // out: NetworkOPs
|
||||||
JSS ( base_fee_xrp ); // out: NetworkOPs
|
JSS ( base_fee_xrp ); // out: NetworkOPs
|
||||||
@@ -252,6 +254,7 @@ JSS ( node_reads_total ); // out: GetCounts
|
|||||||
JSS ( node_writes ); // out: GetCounts
|
JSS ( node_writes ); // out: GetCounts
|
||||||
JSS ( node_written_bytes ); // out: GetCounts
|
JSS ( node_written_bytes ); // out: GetCounts
|
||||||
JSS ( nodes ); // out: LedgerEntrySet, PathState
|
JSS ( nodes ); // out: LedgerEntrySet, PathState
|
||||||
|
JSS ( obligations ); // out: GatewayBalances
|
||||||
JSS ( offer ); // in: LedgerEntry
|
JSS ( offer ); // in: LedgerEntry
|
||||||
JSS ( offers ); // out: NetworkOPs, AccountOffers, Subscribe
|
JSS ( offers ); // out: NetworkOPs, AccountOffers, Subscribe
|
||||||
JSS ( offline ); // in: TransactionSign
|
JSS ( offline ); // in: TransactionSign
|
||||||
|
|||||||
229
src/ripple/rpc/handlers/GatewayBalances.cpp
Normal file
229
src/ripple/rpc/handlers/GatewayBalances.cpp
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012-2014 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <BeastConfig.h>
|
||||||
|
#include <ripple/rpc/impl/AccountFromString.h>
|
||||||
|
#include <ripple/rpc/impl/LookupLedger.h>
|
||||||
|
#include <ripple/app/paths/RippleState.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
// Query:
|
||||||
|
// 1) Specify ledger to query.
|
||||||
|
// 2) Specify issuer account (cold wallet) in "account" field.
|
||||||
|
// 3) Specify accounts that hold gateway assets (such as hot wallets)
|
||||||
|
// using "hotwallet" field which should be either a string (if just
|
||||||
|
// one wallet) or an array of strings (if more than one).
|
||||||
|
|
||||||
|
// Response:
|
||||||
|
// 1) Array, "obligations", indicating the total obligations of the
|
||||||
|
// gateway in each currency. Obligations to specified hot wallets
|
||||||
|
// are not counted here.
|
||||||
|
// 2) Object, "balances", indicating balances in each account
|
||||||
|
// that holds gateway assets. (Those specified in the "hotwallet"
|
||||||
|
// field.)
|
||||||
|
// 3) Object of "assets" indicating accounts that owe the gateway.
|
||||||
|
// (Gateways typically do not hold positive balances. This is unusual.)
|
||||||
|
|
||||||
|
// gateway_balances [<ledger>] <account> [<howallet> [<hotwallet [...
|
||||||
|
|
||||||
|
Json::Value doGatewayBalances (RPC::Context& context)
|
||||||
|
{
|
||||||
|
auto& params = context.params;
|
||||||
|
|
||||||
|
// Get the current ledger
|
||||||
|
Ledger::pointer ledger;
|
||||||
|
Json::Value result (RPC::lookupLedger (params, ledger, context.netOps));
|
||||||
|
|
||||||
|
if (!ledger)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (!(params.isMember (jss::account) || params.isMember (jss::ident)))
|
||||||
|
return RPC::missing_field_error (jss::account);
|
||||||
|
|
||||||
|
std::string const strIdent (params.isMember (jss::account)
|
||||||
|
? params[jss::account].asString ()
|
||||||
|
: params[jss::ident].asString ());
|
||||||
|
|
||||||
|
int iIndex = 0;
|
||||||
|
|
||||||
|
if (params.isMember (jss::account_index))
|
||||||
|
{
|
||||||
|
auto const& accountIndex = params[jss::account_index];
|
||||||
|
if (!accountIndex.isUInt() && !accountIndex.isInt ())
|
||||||
|
return RPC::invalid_field_message (jss::account_index);
|
||||||
|
iIndex = accountIndex.asUInt ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool const bStrict = params.isMember (jss::strict) &&
|
||||||
|
params[jss::strict].asBool ();
|
||||||
|
|
||||||
|
// Get info on account.
|
||||||
|
bool bIndex; // out param
|
||||||
|
RippleAddress naAccount; // out param
|
||||||
|
Json::Value jvAccepted (RPC::accountFromString (
|
||||||
|
naAccount, bIndex, strIdent, iIndex, bStrict));
|
||||||
|
|
||||||
|
if (!jvAccepted.empty ())
|
||||||
|
return jvAccepted;
|
||||||
|
|
||||||
|
context.loadType = Resource::feeHighBurdenRPC;
|
||||||
|
|
||||||
|
result[jss::account] = naAccount.humanAccountID();
|
||||||
|
auto accountID = naAccount.getAccountID();
|
||||||
|
|
||||||
|
// Parse the specified hotwallet(s), if any
|
||||||
|
std::set <Account> hotWallets;
|
||||||
|
|
||||||
|
if (params.isMember ("hotwallet"))
|
||||||
|
{
|
||||||
|
Json::Value const& hw = params["hotwallet"];
|
||||||
|
bool valid = true;
|
||||||
|
|
||||||
|
auto addHotWallet = [&valid, &hotWallets](Json::Value const& j)
|
||||||
|
{
|
||||||
|
if (j.isString())
|
||||||
|
{
|
||||||
|
RippleAddress ra;
|
||||||
|
if (! ra.setAccountPublic (j.asString ()) &&
|
||||||
|
! ra.setAccountID (j.asString()))
|
||||||
|
{
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
hotWallets.insert (ra.getAccountID ());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (hw.isArray())
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < hw.size(); ++i)
|
||||||
|
addHotWallet (hw[i]);
|
||||||
|
}
|
||||||
|
else if (hw.isString())
|
||||||
|
{
|
||||||
|
addHotWallet (hw);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! valid)
|
||||||
|
{
|
||||||
|
result[jss::error] = "invalidHotWallet";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map <Currency, STAmount> sums;
|
||||||
|
std::map <Account, std::vector <STAmount>> hotBalances;
|
||||||
|
std::map <Account, std::vector <STAmount>> assets;
|
||||||
|
|
||||||
|
// Traverse the cold wallet's trust lines
|
||||||
|
forEachItem(*ledger, accountID, getApp().getSLECache(),
|
||||||
|
[&](std::shared_ptr<SLE const> const& sle)
|
||||||
|
{
|
||||||
|
auto rs = RippleState::makeItem (accountID, sle);
|
||||||
|
|
||||||
|
if (!rs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int balSign = rs->getBalance().signum();
|
||||||
|
if (balSign == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto const& peer = rs->getAccountIDPeer();
|
||||||
|
|
||||||
|
// Here, a negative balance means the cold wallet owes (normal)
|
||||||
|
// A positive balance means the cold wallet has an asset (unusual)
|
||||||
|
|
||||||
|
if (hotWallets.count (peer) > 0)
|
||||||
|
{
|
||||||
|
// This is a specified hot wallt
|
||||||
|
hotBalances[peer].push_back (-rs->getBalance ());
|
||||||
|
}
|
||||||
|
else if (balSign > 0)
|
||||||
|
{
|
||||||
|
// This is a gateway asset
|
||||||
|
assets[peer].push_back (rs->getBalance ());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// normal negative balance, obligation to customer
|
||||||
|
auto& bal = sums[rs->getBalance().getCurrency()];
|
||||||
|
if (bal == zero)
|
||||||
|
{
|
||||||
|
// This is needed to set the currency code correctly
|
||||||
|
bal = -rs->getBalance();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
bal -= rs->getBalance();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (! sums.empty())
|
||||||
|
{
|
||||||
|
Json::Value& j = (result [jss::obligations] = Json::objectValue);
|
||||||
|
for (auto const& e : sums)
|
||||||
|
{
|
||||||
|
j[to_string (e.first)] = e.second.getText ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! hotBalances.empty())
|
||||||
|
{
|
||||||
|
Json::Value& j = (result [jss::balances] = Json::objectValue);
|
||||||
|
for (auto const& account : hotBalances)
|
||||||
|
{
|
||||||
|
Json::Value& balanceArray = (j[to_string (account.first)] = Json::arrayValue);
|
||||||
|
for (auto const& balance : account.second)
|
||||||
|
{
|
||||||
|
Json::Value& entry = balanceArray.append (Json::objectValue);
|
||||||
|
entry[jss::currency] = to_string (balance.issue ().currency);
|
||||||
|
entry[jss::value] = balance.getText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! assets.empty())
|
||||||
|
{
|
||||||
|
Json::Value& j = (result [jss::assets] = Json::objectValue);
|
||||||
|
|
||||||
|
for (auto const& account : assets)
|
||||||
|
{
|
||||||
|
Json::Value& balanceArray = (j[to_string (account.first)] = Json::arrayValue);
|
||||||
|
for (auto const& balance : account.second)
|
||||||
|
{
|
||||||
|
Json::Value& entry = balanceArray.append (Json::objectValue);
|
||||||
|
entry[jss::currency] = to_string (balance.issue ().currency);
|
||||||
|
entry[jss::value] = balance.getText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // ripple
|
||||||
@@ -37,6 +37,7 @@ Json::Value doConnect (RPC::Context&);
|
|||||||
Json::Value doConsensusInfo (RPC::Context&);
|
Json::Value doConsensusInfo (RPC::Context&);
|
||||||
Json::Value doFeature (RPC::Context&);
|
Json::Value doFeature (RPC::Context&);
|
||||||
Json::Value doFetchInfo (RPC::Context&);
|
Json::Value doFetchInfo (RPC::Context&);
|
||||||
|
Json::Value doGatewayBalances (RPC::Context&);
|
||||||
Json::Value doGetCounts (RPC::Context&);
|
Json::Value doGetCounts (RPC::Context&);
|
||||||
Json::Value doInternal (RPC::Context&);
|
Json::Value doInternal (RPC::Context&);
|
||||||
Json::Value doLedgerAccept (RPC::Context&);
|
Json::Value doLedgerAccept (RPC::Context&);
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ HandlerTable HANDLERS({
|
|||||||
{ "can_delete", byRef (&doCanDelete), Role::ADMIN, NO_CONDITION },
|
{ "can_delete", byRef (&doCanDelete), Role::ADMIN, NO_CONDITION },
|
||||||
{ "connect", byRef (&doConnect), Role::ADMIN, NO_CONDITION },
|
{ "connect", byRef (&doConnect), Role::ADMIN, NO_CONDITION },
|
||||||
{ "consensus_info", byRef (&doConsensusInfo), Role::ADMIN, NO_CONDITION },
|
{ "consensus_info", byRef (&doConsensusInfo), Role::ADMIN, NO_CONDITION },
|
||||||
|
{ "gateway_balances", byRef (&doGatewayBalances), Role::USER, NO_CONDITION },
|
||||||
{ "get_counts", byRef (&doGetCounts), Role::ADMIN, NO_CONDITION },
|
{ "get_counts", byRef (&doGetCounts), Role::ADMIN, NO_CONDITION },
|
||||||
{ "internal", byRef (&doInternal), Role::ADMIN, NO_CONDITION },
|
{ "internal", byRef (&doInternal), Role::ADMIN, NO_CONDITION },
|
||||||
{ "feature", byRef (&doFeature), Role::ADMIN, NO_CONDITION },
|
{ "feature", byRef (&doFeature), Role::ADMIN, NO_CONDITION },
|
||||||
|
|||||||
@@ -49,6 +49,7 @@
|
|||||||
#include <ripple/rpc/handlers/ConsensusInfo.cpp>
|
#include <ripple/rpc/handlers/ConsensusInfo.cpp>
|
||||||
#include <ripple/rpc/handlers/Feature.cpp>
|
#include <ripple/rpc/handlers/Feature.cpp>
|
||||||
#include <ripple/rpc/handlers/FetchInfo.cpp>
|
#include <ripple/rpc/handlers/FetchInfo.cpp>
|
||||||
|
#include <ripple/rpc/handlers/GatewayBalances.cpp>
|
||||||
#include <ripple/rpc/handlers/GetCounts.cpp>
|
#include <ripple/rpc/handlers/GetCounts.cpp>
|
||||||
#include <ripple/rpc/handlers/Internal.cpp>
|
#include <ripple/rpc/handlers/Internal.cpp>
|
||||||
#include <ripple/rpc/handlers/Ledger.cpp>
|
#include <ripple/rpc/handlers/Ledger.cpp>
|
||||||
|
|||||||
Reference in New Issue
Block a user