rippled
Loading...
Searching...
No Matches
GatewayBalances.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012-2014 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/app/main/Application.h>
21#include <xrpld/app/paths/TrustLine.h>
22#include <xrpld/ledger/ReadView.h>
23#include <xrpld/rpc/Context.h>
24#include <xrpld/rpc/detail/RPCHelpers.h>
25
26#include <xrpl/protocol/AccountID.h>
27#include <xrpl/protocol/ErrorCodes.h>
28#include <xrpl/protocol/RPCErr.h>
29#include <xrpl/protocol/jss.h>
30#include <xrpl/resource/Fees.h>
31
32namespace ripple {
33
34// Query:
35// 1) Specify ledger to query.
36// 2) Specify issuer account (cold wallet) in "account" field.
37// 3) Specify accounts that hold gateway assets (such as hot wallets)
38// using "hotwallet" field which should be either a string (if just
39// one wallet) or an array of strings (if more than one).
40
41// Response:
42// 1) Array, "obligations", indicating the total obligations of the
43// gateway in each currency. Obligations to specified hot wallets
44// are not counted here.
45// 2) Object, "balances", indicating balances in each account
46// that holds gateway assets. (Those specified in the "hotwallet"
47// field.)
48// 3) Object of "assets" indicating accounts that owe the gateway.
49// (Gateways typically do not hold positive balances. This is unusual.)
50
51// gateway_balances [<ledger>] <account> [<howallet> [<hotwallet [...
52
55{
56 auto& params = context.params;
57
58 // Get the current ledger
60 auto result = RPC::lookupLedger(ledger, context);
61
62 if (!ledger)
63 return result;
64
65 if (!(params.isMember(jss::account) || params.isMember(jss::ident)))
66 return RPC::missing_field_error(jss::account);
67
68 std::string const strIdent(
69 params.isMember(jss::account) ? params[jss::account].asString()
70 : params[jss::ident].asString());
71
72 // Get info on account.
73 auto id = parseBase58<AccountID>(strIdent);
74 if (!id)
76 auto const accountID{std::move(id.value())};
78
79 result[jss::account] = toBase58(accountID);
80
81 if (context.apiVersion > 1u && !ledger->exists(keylet::account(accountID)))
82 {
84 return result;
85 }
86
87 // Parse the specified hotwallet(s), if any
88 std::set<AccountID> hotWallets;
89
90 if (params.isMember(jss::hotwallet))
91 {
92 auto addHotWallet = [&hotWallets](Json::Value const& j) {
93 if (j.isString())
94 {
95 if (auto id = parseBase58<AccountID>(j.asString()); id)
96 {
97 hotWallets.insert(std::move(id.value()));
98 return true;
99 }
100 }
101
102 return false;
103 };
104
105 Json::Value const& hw = params[jss::hotwallet];
106 bool valid = true;
107
108 // null is treated as a valid 0-sized array of hotwallet
109 if (hw.isArrayOrNull())
110 {
111 for (unsigned i = 0; i < hw.size(); ++i)
112 valid &= addHotWallet(hw[i]);
113 }
114 else if (hw.isString())
115 {
116 valid &= addHotWallet(hw);
117 }
118 else
119 {
120 valid = false;
121 }
122
123 if (!valid)
124 {
125 // The documentation states that invalidParams is used when
126 // One or more fields are specified incorrectly.
127 // invalidHotwallet should be used when the account exists, but does
128 // not have currency issued by the account from the request.
129 if (context.apiVersion < 2u)
130 {
132 }
133 else
134 {
136 }
137 return result;
138 }
139 }
140
145
146 // Traverse the cold wallet's trust lines
147 {
149 *ledger, accountID, [&](std::shared_ptr<SLE const> const& sle) {
150 auto rs = PathFindTrustLine::makeItem(accountID, sle);
151
152 if (!rs)
153 return;
154
155 int balSign = rs->getBalance().signum();
156 if (balSign == 0)
157 return;
158
159 auto const& peer = rs->getAccountIDPeer();
160
161 // Here, a negative balance means the cold wallet owes (normal)
162 // A positive balance means the cold wallet has an asset
163 // (unusual)
164
165 if (hotWallets.count(peer) > 0)
166 {
167 // This is a specified hot wallet
168 hotBalances[peer].push_back(-rs->getBalance());
169 }
170 else if (balSign > 0)
171 {
172 // This is a gateway asset
173 assets[peer].push_back(rs->getBalance());
174 }
175 else if (rs->getFreeze())
176 {
177 // An obligation the gateway has frozen
178 frozenBalances[peer].push_back(-rs->getBalance());
179 }
180 else
181 {
182 // normal negative balance, obligation to customer
183 auto& bal = sums[rs->getBalance().getCurrency()];
184 if (bal == beast::zero)
185 {
186 // This is needed to set the currency code correctly
187 bal = -rs->getBalance();
188 }
189 else
190 {
191 try
192 {
193 bal -= rs->getBalance();
194 }
195 catch (std::runtime_error const&)
196 {
197 // Presumably the exception was caused by overflow.
198 // On overflow return the largest valid STAmount.
199 // Very large sums of STAmount are approximations
200 // anyway.
201 bal = STAmount(
202 bal.issue(),
205 }
206 }
207 }
208 });
209 }
210
211 if (!sums.empty())
212 {
213 Json::Value j;
214 for (auto const& [k, v] : sums)
215 {
216 j[to_string(k)] = v.getText();
217 }
218 result[jss::obligations] = std::move(j);
219 }
220
221 auto populateResult =
222 [&result](
224 Json::StaticString const& name) {
225 if (!array.empty())
226 {
227 Json::Value j;
228 for (auto const& [accId, accBalances] : array)
229 {
230 Json::Value balanceArray;
231 for (auto const& balance : accBalances)
232 {
233 Json::Value entry;
234 entry[jss::currency] =
235 to_string(balance.issue().currency);
236 entry[jss::value] = balance.getText();
237 balanceArray.append(std::move(entry));
238 }
239 j[to_string(accId)] = std::move(balanceArray);
240 }
241 result[name] = std::move(j);
242 }
243 };
244
245 populateResult(hotBalances, jss::balances);
246 populateResult(frozenBalances, jss::frozen_balances);
247 populateResult(assets, jss::assets);
248
249 return result;
250}
251
252} // namespace ripple
Lightweight wrapper to tag static string.
Definition: json_value.h:64
Represents a JSON value.
Definition: json_value.h:150
Value & append(Value const &value)
Append value to array at the end.
Definition: json_value.cpp:910
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:719
bool isString() const
bool isArrayOrNull() const
static std::optional< PathFindTrustLine > makeItem(AccountID const &accountID, std::shared_ptr< SLE const > const &sle)
Definition: TrustLine.cpp:52
static int const cMaxOffset
Definition: STAmount.h:66
static std::uint64_t const cMaxValue
Definition: STAmount.h:70
T count(T... args)
T empty(T... args)
T insert(T... args)
void inject_error(error_code_i code, JsonValue &json)
Add or update the json update to reflect the error code.
Definition: ErrorCodes.h:223
Status lookupLedger(std::shared_ptr< ReadView const > &ledger, JsonContext &context, Json::Value &result)
Look up a ledger from a request and fill a Json::Result with the data representing a ledger.
Definition: RPCHelpers.cpp:622
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:273
Charge const feeHeavyBurdenRPC
TER valid(PreclaimContext const &ctx, AccountID const &src)
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:177
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:114
@ rpcACT_NOT_FOUND
Definition: ErrorCodes.h:70
@ rpcACT_MALFORMED
Definition: ErrorCodes.h:90
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
@ rpcINVALID_HOTWALLET
Definition: ErrorCodes.h:81
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:31
Json::Value doGatewayBalances(RPC::JsonContext &context)
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
void forEachItem(ReadView const &view, Keylet const &root, std::function< void(std::shared_ptr< SLE const > const &)> const &f)
Iterate all items in the given directory.
Definition: View.cpp:656
unsigned int apiVersion
Definition: Context.h:49
Resource::Charge & loadType
Definition: Context.h:42
Json::Value params
Definition: Context.h:63