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