rippled
Loading...
Searching...
No Matches
AMMInfo.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2023 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/ledger/LedgerMaster.h>
21#include <xrpld/app/misc/AMMUtils.h>
22#include <xrpld/rpc/Context.h>
23#include <xrpld/rpc/detail/RPCHelpers.h>
24
25#include <xrpl/json/json_value.h>
26#include <xrpl/ledger/ReadView.h>
27#include <xrpl/protocol/AMMCore.h>
28#include <xrpl/protocol/Issue.h>
29
30#include <grpcpp/support/status.h>
31
32namespace ripple {
33
36{
37 std::string strIdent(v.asString());
38 AccountID accountID;
39
40 if (auto jv = RPC::accountFromString(accountID, strIdent))
41 {
42 for (auto it = jv.begin(); it != jv.end(); ++it)
43 result[it.memberName()] = (*it);
44
45 return std::nullopt;
46 }
47 return std::optional<AccountID>(accountID);
48}
49
50Expected<Issue, error_code_i>
52{
53 try
54 {
55 return issueFromJson(v);
56 }
57 catch (std::runtime_error const& ex)
58 {
59 JLOG(j.debug()) << "getIssue " << ex.what();
60 }
62}
63
66{
67 // 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC
68 using namespace std::chrono;
69 return date::format(
70 "%Y-%Om-%dT%H:%M:%OS%z",
71 date::sys_time<system_clock::duration>(
72 system_clock::time_point{tp.time_since_epoch() + epoch_offset}));
73}
74
77{
78 auto const& params(context.params);
79 Json::Value result;
80
82 result = RPC::lookupLedger(ledger, context);
83 if (!ledger)
84 return result;
85
86 struct ValuesFromContextParams
87 {
89 Issue issue1;
90 Issue issue2;
92 };
93
94 auto getValuesFromContextParams =
100
101 constexpr auto invalid = [](Json::Value const& params) -> bool {
102 return (params.isMember(jss::asset) !=
103 params.isMember(jss::asset2)) ||
104 (params.isMember(jss::asset) ==
105 params.isMember(jss::amm_account));
106 };
107
108 // NOTE, identical check for apVersion >= 3 below
109 if (context.apiVersion < 3 && invalid(params))
111
112 if (params.isMember(jss::asset))
113 {
114 if (auto const i = getIssue(params[jss::asset], context.j))
115 issue1 = *i;
116 else
117 return Unexpected(i.error());
118 }
119
120 if (params.isMember(jss::asset2))
121 {
122 if (auto const i = getIssue(params[jss::asset2], context.j))
123 issue2 = *i;
124 else
125 return Unexpected(i.error());
126 }
127
128 if (params.isMember(jss::amm_account))
129 {
130 auto const id = getAccount(params[jss::amm_account], result);
131 if (!id)
133 auto const sle = ledger->read(keylet::account(*id));
134 if (!sle)
136 ammID = sle->getFieldH256(sfAMMID);
137 if (ammID->isZero())
139 }
140
141 if (params.isMember(jss::account))
142 {
143 accountID = getAccount(params[jss::account], result);
144 if (!accountID || !ledger->read(keylet::account(*accountID)))
146 }
147
148 // NOTE, identical check for apVersion < 3 above
149 if (context.apiVersion >= 3 && invalid(params))
151
152 XRPL_ASSERT(
153 (issue1.has_value() == issue2.has_value()) &&
154 (issue1.has_value() != ammID.has_value()),
155 "ripple::doAMMInfo : issue1 and issue2 do match");
156
157 auto const ammKeylet = [&]() {
158 if (issue1 && issue2)
159 return keylet::amm(*issue1, *issue2);
160 XRPL_ASSERT(ammID, "ripple::doAMMInfo::ammKeylet : ammID is set");
161 return keylet::amm(*ammID);
162 }();
163 auto const amm = ledger->read(ammKeylet);
164 if (!amm)
166 if (!issue1 && !issue2)
167 {
168 issue1 = (*amm)[sfAsset].get<Issue>();
169 issue2 = (*amm)[sfAsset2].get<Issue>();
170 }
171
172 return ValuesFromContextParams{
173 accountID, *issue1, *issue2, std::move(amm)};
174 };
175
176 auto const r = getValuesFromContextParams();
177 if (!r)
178 {
179 RPC::inject_error(r.error(), result);
180 return result;
181 }
182
183 auto const& [accountID, issue1, issue2, amm] = *r;
184
185 auto const ammAccountID = amm->getAccountID(sfAccount);
186
187 // provide funds if frozen, specify asset_frozen flag
188 auto const [asset1Balance, asset2Balance] = ammPoolHolds(
189 *ledger,
190 ammAccountID,
191 issue1,
192 issue2,
194 context.j);
195 auto const lptAMMBalance = accountID
196 ? ammLPHolds(*ledger, *amm, *accountID, context.j)
197 : (*amm)[sfLPTokenBalance];
198
199 Json::Value ammResult;
200 asset1Balance.setJson(ammResult[jss::amount]);
201 asset2Balance.setJson(ammResult[jss::amount2]);
202 lptAMMBalance.setJson(ammResult[jss::lp_token]);
203 ammResult[jss::trading_fee] = (*amm)[sfTradingFee];
204 ammResult[jss::account] = to_string(ammAccountID);
205 Json::Value voteSlots(Json::arrayValue);
206 if (amm->isFieldPresent(sfVoteSlots))
207 {
208 for (auto const& voteEntry : amm->getFieldArray(sfVoteSlots))
209 {
210 Json::Value vote;
211 vote[jss::account] = to_string(voteEntry.getAccountID(sfAccount));
212 vote[jss::trading_fee] = voteEntry[sfTradingFee];
213 vote[jss::vote_weight] = voteEntry[sfVoteWeight];
214 voteSlots.append(std::move(vote));
215 }
216 }
217 if (voteSlots.size() > 0)
218 ammResult[jss::vote_slots] = std::move(voteSlots);
219 XRPL_ASSERT(
220 !ledger->rules().enabled(fixInnerObjTemplate) ||
221 amm->isFieldPresent(sfAuctionSlot),
222 "ripple::doAMMInfo : auction slot is set");
223 if (amm->isFieldPresent(sfAuctionSlot))
224 {
225 auto const& auctionSlot =
226 static_cast<STObject const&>(amm->peekAtField(sfAuctionSlot));
227 if (auctionSlot.isFieldPresent(sfAccount))
228 {
229 Json::Value auction;
230 auto const timeSlot = ammAuctionTimeSlot(
231 ledger->info().parentCloseTime.time_since_epoch().count(),
232 auctionSlot);
233 auction[jss::time_interval] =
234 timeSlot ? *timeSlot : AUCTION_SLOT_TIME_INTERVALS;
235 auctionSlot[sfPrice].setJson(auction[jss::price]);
236 auction[jss::discounted_fee] = auctionSlot[sfDiscountedFee];
237 auction[jss::account] =
238 to_string(auctionSlot.getAccountID(sfAccount));
239 auction[jss::expiration] = to_iso8601(NetClock::time_point{
240 NetClock::duration{auctionSlot[sfExpiration]}});
241 if (auctionSlot.isFieldPresent(sfAuthAccounts))
242 {
243 Json::Value auth;
244 for (auto const& acct :
245 auctionSlot.getFieldArray(sfAuthAccounts))
246 {
247 Json::Value jv;
248 jv[jss::account] = to_string(acct.getAccountID(sfAccount));
249 auth.append(jv);
250 }
251 auction[jss::auth_accounts] = auth;
252 }
253 ammResult[jss::auction_slot] = std::move(auction);
254 }
255 }
256
257 if (!isXRP(asset1Balance))
258 ammResult[jss::asset_frozen] =
259 isFrozen(*ledger, ammAccountID, issue1.currency, issue1.account);
260 if (!isXRP(asset2Balance))
261 ammResult[jss::asset2_frozen] =
262 isFrozen(*ledger, ammAccountID, issue2.currency, issue2.account);
263
264 result[jss::amm] = std::move(ammResult);
265 if (!result.isMember(jss::ledger_index) &&
266 !result.isMember(jss::ledger_hash))
267 result[jss::ledger_current_index] = ledger->info().seq;
268 result[jss::validated] = context.ledgerMaster.isValidated(*ledger);
269
270 return result;
271}
272
273} // namespace ripple
Represents a JSON value.
Definition json_value.h:149
Value & append(Value const &value)
Append value to array at the end.
UInt size() const
Number of values in array or object.
std::string asString() const
Returns the unquoted string value.
bool isMember(char const *key) const
Return true if the object has a member named key.
A generic endpoint for log messages.
Definition Journal.h:60
Stream debug() const
Definition Journal.h:328
A currency issued by an account.
Definition Issue.h:33
bool isValidated(ReadView const &ledger)
T is_same_v
@ arrayValue
array value (ordered list)
Definition json_value.h:44
void inject_error(error_code_i code, JsonValue &json)
Add or update the json update to reflect the error code.
Definition ErrorCodes.h:233
Json::Value accountFromString(AccountID &result, std::string const &strIdent, bool bStrict)
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.
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
Definition Indexes.cpp:446
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:184
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
@ fhIGNORE_FREEZE
Definition View.h:77
bool isXRP(AccountID const &c)
Definition AccountID.h:90
std::uint16_t constexpr AUCTION_SLOT_TIME_INTERVALS
Definition AMMCore.h:35
std::optional< std::uint8_t > ammAuctionTimeSlot(std::uint64_t current, STObject const &auctionSlot)
Get time slot of the auction slot.
Definition AMMCore.cpp:108
@ rpcACT_NOT_FOUND
Definition ErrorCodes.h:70
@ rpcISSUE_MALFORMED
Definition ErrorCodes.h:146
@ rpcACT_MALFORMED
Definition ErrorCodes.h:90
@ rpcINVALID_PARAMS
Definition ErrorCodes.h:84
Issue getIssue(T const &amt)
std::optional< AccountID > getAccount(Json::Value const &v, Json::Value &result)
Definition AMMInfo.cpp:35
Json::Value doAMMInfo(RPC::JsonContext &context)
Definition AMMInfo.cpp:76
bool isFrozen(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer)
Definition View.cpp:247
STAmount ammLPHolds(ReadView const &view, Currency const &cur1, Currency const &cur2, AccountID const &ammAccount, AccountID const &lpAccount, beast::Journal const j)
Get the balance of LP tokens.
Definition AMMUtils.cpp:113
Issue issueFromJson(Json::Value const &v)
Definition Issue.cpp:95
std::pair< STAmount, STAmount > ammPoolHolds(ReadView const &view, AccountID const &ammAccountID, Issue const &issue1, Issue const &issue2, FreezeHandling freezeHandling, beast::Journal const j)
Get AMM pool balances.
Definition AMMUtils.cpp:31
@ invalid
Timely, but invalid signature.
static constexpr std::chrono::seconds epoch_offset
Clock for measuring the network time.
Definition chrono.h:55
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:630
std::string to_iso8601(NetClock::time_point tp)
Definition AMMInfo.cpp:65
T has_value(T... args)
unsigned int apiVersion
Definition Context.h:49
beast::Journal const j
Definition Context.h:40
LedgerMaster & ledgerMaster
Definition Context.h:44
T time_since_epoch(T... args)
T what(T... args)