xrpld
Loading...
Searching...
No Matches
AMMInfo.cpp
1#include <xrpld/app/ledger/LedgerMaster.h>
2#include <xrpld/rpc/Context.h>
3#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
4
5#include <xrpl/basics/Log.h>
6#include <xrpl/basics/base_uint.h>
7#include <xrpl/basics/chrono.h>
8#include <xrpl/basics/safe_cast.h>
9#include <xrpl/beast/utility/Journal.h>
10#include <xrpl/beast/utility/instrumentation.h>
11#include <xrpl/core/ServiceRegistry.h>
12#include <xrpl/json/json_value.h>
13#include <xrpl/ledger/ReadView.h>
14#include <xrpl/ledger/helpers/AMMHelpers.h>
15#include <xrpl/ledger/helpers/TokenHelpers.h>
16#include <xrpl/protocol/AMMCore.h>
17#include <xrpl/protocol/AccountID.h>
18#include <xrpl/protocol/Asset.h>
19#include <xrpl/protocol/ErrorCodes.h>
20#include <xrpl/protocol/Feature.h> // IWYU pragma: keep
21#include <xrpl/protocol/Indexes.h>
22#include <xrpl/protocol/SField.h>
23#include <xrpl/protocol/STAmount.h>
24#include <xrpl/protocol/jss.h>
25
26#include <date/date.h>
27
28#include <chrono>
29#include <expected>
30#include <memory>
31#include <optional>
32#include <stdexcept>
33#include <string>
34#include <utility>
35
36namespace xrpl {
37
38std::expected<Asset, ErrorCodeI>
40{
41 try
42 {
43 return assetFromJson(v);
44 }
45 catch (std::runtime_error const& ex)
46 {
47 JLOG(j.debug()) << "getAsset " << ex.what();
48 }
50}
51
54{
55 // 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC
56 using namespace std::chrono;
57 return date::format(
58 "%Y-%Om-%dT%H:%M:%OS%z",
59 date::sys_time<system_clock::duration>(
60 system_clock::time_point{tp.time_since_epoch() + kEpochOffset}));
61}
62
65{
66 auto const& params(context.params);
67 json::Value result;
68
70 result = RPC::lookupLedger(ledger, context);
71 if (!ledger)
72 return result;
73
74 struct ValuesFromContextParams
75 {
77 Asset asset1;
78 Asset asset2;
80 };
81
82 auto getValuesFromContextParams = [&]() -> std::expected<ValuesFromContextParams, ErrorCodeI> {
87
88 static constexpr auto kInvalid = [](json::Value const& params) -> bool {
89 return (params.isMember(jss::asset) != params.isMember(jss::asset2)) ||
90 (params.isMember(jss::asset) == params.isMember(jss::amm_account));
91 };
92
93 // NOTE, identical check for apVersion >= 3 below
94 if (context.apiVersion < 3 && kInvalid(params))
96
97 if (params.isMember(jss::asset))
98 {
99 if (auto const i = getAsset(params[jss::asset], context.j))
100 {
101 asset1 = *i;
102 }
103 else
104 {
105 return std::unexpected(i.error());
106 }
107 }
108
109 if (params.isMember(jss::asset2))
110 {
111 if (auto const i = getAsset(params[jss::asset2], context.j))
112 {
113 asset2 = *i;
114 }
115 else
116 {
117 return std::unexpected(i.error());
118 }
119 }
120
121 if (params.isMember(jss::amm_account))
122 {
123 auto const& ammAccount = params[jss::amm_account];
124 if (!ammAccount.isString())
126 auto const id = parseBase58<AccountID>(ammAccount.asString());
127 if (!id)
129 auto const sle = ledger->read(keylet::account(*id));
130 if (!sle)
132 ammID = sle->getFieldH256(sfAMMID);
133 if (ammID->isZero())
135 }
136
137 if (params.isMember(jss::account))
138 {
139 auto const& localAccount = params[jss::account];
140 if (!localAccount.isString())
142 accountID = parseBase58<AccountID>(localAccount.asString());
143 if (!accountID || !ledger->read(keylet::account(*accountID)))
145 }
146
147 // NOTE, identical check for apVersion < 3 above
148 if (context.apiVersion >= 3 && kInvalid(params))
150
151 XRPL_ASSERT(
152 (asset1.has_value() == asset2.has_value()) && (asset1.has_value() != ammID.has_value()),
153 "xrpl::doAMMInfo : asset1 and asset2 do match");
154
155 auto const ammKeylet = [&]() {
156 if (asset1 && asset2)
157 return keylet::amm(*asset1, *asset2);
158 XRPL_ASSERT(ammID, "xrpl::doAMMInfo::ammKeylet : ammID is set");
159 return keylet::amm(*ammID);
160 }();
161 auto const amm = ledger->read(ammKeylet);
162 if (!amm)
164 if (!asset1 && !asset2)
165 {
166 asset1 = (*amm)[sfAsset];
167 asset2 = (*amm)[sfAsset2];
168 }
169
170 return ValuesFromContextParams{
171 .accountID = accountID, .asset1 = *asset1, .asset2 = *asset2, .amm = amm};
172 };
173
174 auto const r = getValuesFromContextParams();
175 if (!r)
176 {
177 RPC::injectError(r.error(), result);
178 return result;
179 }
180
181 auto const& [accountID, asset1, asset2, 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,
188 ammAccountID,
189 asset1,
190 asset2,
193 context.j);
194 auto const lptAMMBalance =
195 accountID ? ammLPHolds(*ledger, *amm, *accountID, context.j) : (*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);
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) || amm->isFieldPresent(sfAuctionSlot),
219 "xrpl::doAMMInfo : auction slot is set");
220 if (amm->isFieldPresent(sfAuctionSlot))
221 {
222 auto const& auctionSlot = safeDowncast<STObject const&>(amm->peekAtField(sfAuctionSlot));
223 if (auctionSlot.isFieldPresent(sfAccount))
224 {
225 json::Value auction;
226 auto const timeSlot = ammAuctionTimeSlot(
227 ledger->header().parentCloseTime.time_since_epoch().count(), auctionSlot);
228 auction[jss::time_interval] = timeSlot ? *timeSlot : kAuctionSlotTimeIntervals;
229 auctionSlot[sfPrice].setJson(auction[jss::price]);
230 auction[jss::discounted_fee] = auctionSlot[sfDiscountedFee];
231 auction[jss::account] = to_string(auctionSlot.getAccountID(sfAccount));
232 auction[jss::expiration] =
233 toIso8601(NetClock::time_point{NetClock::duration{auctionSlot[sfExpiration]}});
234 if (auctionSlot.isFieldPresent(sfAuthAccounts))
235 {
236 json::Value auth;
237 for (auto const& acct : auctionSlot.getFieldArray(sfAuthAccounts))
238 {
239 json::Value jv;
240 jv[jss::account] = to_string(acct.getAccountID(sfAccount));
241 auth.append(jv);
242 }
243 auction[jss::auth_accounts] = auth;
244 }
245 ammResult[jss::auction_slot] = std::move(auction);
246 }
247 }
248
249 if (!isXRP(asset1Balance))
250 {
251 ammResult[jss::asset_frozen] = isFrozen(*ledger, ammAccountID, asset1);
252 }
253 if (!isXRP(asset2Balance))
254 {
255 ammResult[jss::asset2_frozen] = isFrozen(*ledger, ammAccountID, asset2);
256 }
257
258 result[jss::amm] = std::move(ammResult);
259 if (!result.isMember(jss::ledger_index) && !result.isMember(jss::ledger_hash))
260 result[jss::ledger_current_index] = ledger->header().seq;
261 result[jss::validated] = context.ledgerMaster.isValidated(*ledger);
262
263 return result;
264}
265
266} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:38
Stream debug() const
Definition Journal.h:297
Represents a JSON value.
Definition json_value.h:130
Value & append(Value const &value)
Append value to array at the end.
UInt size() const
Number of values in array or object.
bool isMember(char const *key) const
Return true if the object has a member named key.
bool isValidated(ReadView const &ledger)
std::chrono::time_point< NetClock > time_point
Definition chrono.h:46
std::chrono::duration< rep, period > duration
Definition chrono.h:45
std::shared_ptr< STLedgerEntry const > const_pointer
@ Array
array value (ordered list)
Definition json_value.h:25
Status lookupLedger(std::shared_ptr< ReadView const > &ledger, JsonContext const &context, json::Value &result)
Looks up a ledger from a request and fills a json::Value with ledger data.
void injectError(ErrorCodeI code, json::Value &json)
Add or update the json update to reflect the error code.
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
Definition Indexes.cpp:425
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:186
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
static constexpr std::chrono::seconds kEpochOffset
Clock for measuring the network time.
Definition chrono.h:33
STAmount ammLPHolds(ReadView const &view, Asset const &asset1, Asset const &asset2, AccountID const &ammAccount, AccountID const &lpAccount, beast::Journal const j)
Get the balance of LP tokens.
@ RpcActNotFound
Definition ErrorCodes.h:52
@ RpcActMalformed
Definition ErrorCodes.h:72
@ RpcIssueMalformed
Definition ErrorCodes.h:128
@ RpcInvalidParams
Definition ErrorCodes.h:66
Dest safeDowncast(Src *s) noexcept
Definition safe_cast.h:78
bool isXRP(AccountID const &c)
Definition AccountID.h:70
std::string toIso8601(NetClock::time_point tp)
Definition AMMInfo.cpp:53
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633
std::pair< STAmount, STAmount > ammPoolHolds(ReadView const &view, AccountID const &ammAccountID, Asset const &asset1, Asset const &asset2, FreezeHandling freezeHandling, AuthHandling authHandling, beast::Journal const j)
Get AMM pool balances.
Asset getAsset(T const &amt)
json::Value doAMMInfo(RPC::JsonContext &)
Definition AMMInfo.cpp:64
bool isFrozen(ReadView const &view, AccountID const &account, MPTIssue const &mptIssue, std::uint8_t depth=0)
constexpr std::uint16_t kAuctionSlotTimeIntervals
Definition AMMCore.h:15
std::optional< std::uint8_t > ammAuctionTimeSlot(std::uint64_t current, STObject const &auctionSlot)
Get time slot of the auction slot.
Definition AMMCore.cpp:110
Asset assetFromJson(json::Value const &jv)
Definition Asset.cpp:59
T has_value(T... args)
beast::Journal const j
Definition Context.h:20
unsigned int apiVersion
Definition Context.h:29
LedgerMaster & ledgerMaster
Definition Context.h:24
json::Value params
Definition Context.h:43
T time_since_epoch(T... args)
T unexpected(T... args)
T what(T... args)