rippled
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/safe_cast.h>
6#include <xrpl/json/json_value.h>
7#include <xrpl/ledger/ReadView.h>
8#include <xrpl/protocol/AMMCore.h>
9#include <xrpl/protocol/Issue.h>
10#include <xrpl/tx/transactors/dex/AMMUtils.h>
11
12#include <grpcpp/support/status.h>
13
14namespace xrpl {
15
16Expected<Issue, error_code_i>
18{
19 try
20 {
21 return issueFromJson(v);
22 }
23 catch (std::runtime_error const& ex)
24 {
25 JLOG(j.debug()) << "getIssue " << ex.what();
26 }
28}
29
32{
33 // 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC
34 using namespace std::chrono;
35 return date::format(
36 "%Y-%Om-%dT%H:%M:%OS%z",
37 date::sys_time<system_clock::duration>(
38 system_clock::time_point{tp.time_since_epoch() + epoch_offset}));
39}
40
43{
44 auto const& params(context.params);
45 Json::Value result;
46
48 result = RPC::lookupLedger(ledger, context);
49 if (!ledger)
50 return result;
51
52 struct ValuesFromContextParams
53 {
55 Issue issue1;
56 Issue issue2;
58 };
59
60 auto getValuesFromContextParams = [&]() -> Expected<ValuesFromContextParams, error_code_i> {
65
66 constexpr auto invalid = [](Json::Value const& params) -> bool {
67 return (params.isMember(jss::asset) != params.isMember(jss::asset2)) ||
68 (params.isMember(jss::asset) == params.isMember(jss::amm_account));
69 };
70
71 // NOTE, identical check for apVersion >= 3 below
72 if (context.apiVersion < 3 && invalid(params))
74
75 if (params.isMember(jss::asset))
76 {
77 if (auto const i = getIssue(params[jss::asset], context.j))
78 {
79 issue1 = *i;
80 }
81 else
82 {
83 return Unexpected(i.error());
84 }
85 }
86
87 if (params.isMember(jss::asset2))
88 {
89 if (auto const i = getIssue(params[jss::asset2], context.j))
90 {
91 issue2 = *i;
92 }
93 else
94 {
95 return Unexpected(i.error());
96 }
97 }
98
99 if (params.isMember(jss::amm_account))
100 {
101 auto const id = parseBase58<AccountID>((params[jss::amm_account].asString()));
102 if (!id)
104 auto const sle = ledger->read(keylet::account(*id));
105 if (!sle)
107 ammID = sle->getFieldH256(sfAMMID);
108 if (ammID->isZero())
110 }
111
112 if (params.isMember(jss::account))
113 {
114 accountID = parseBase58<AccountID>(params[jss::account].asString());
115 if (!accountID || !ledger->read(keylet::account(*accountID)))
117 }
118
119 // NOTE, identical check for apVersion < 3 above
120 if (context.apiVersion >= 3 && invalid(params))
122
123 XRPL_ASSERT(
124 (issue1.has_value() == issue2.has_value()) && (issue1.has_value() != ammID.has_value()),
125 "xrpl::doAMMInfo : issue1 and issue2 do match");
126
127 auto const ammKeylet = [&]() {
128 if (issue1 && issue2)
129 return keylet::amm(*issue1, *issue2);
130 XRPL_ASSERT(ammID, "xrpl::doAMMInfo::ammKeylet : ammID is set");
131 return keylet::amm(*ammID);
132 }();
133 auto const amm = ledger->read(ammKeylet);
134 if (!amm)
136 if (!issue1 && !issue2)
137 {
138 issue1 = (*amm)[sfAsset].get<Issue>();
139 issue2 = (*amm)[sfAsset2].get<Issue>();
140 }
141
142 return ValuesFromContextParams{accountID, *issue1, *issue2, amm};
143 };
144
145 auto const r = getValuesFromContextParams();
146 if (!r)
147 {
148 RPC::inject_error(r.error(), result);
149 return result;
150 }
151
152 auto const& [accountID, issue1, issue2, amm] = *r;
153
154 auto const ammAccountID = amm->getAccountID(sfAccount);
155
156 // provide funds if frozen, specify asset_frozen flag
157 auto const [asset1Balance, asset2Balance] = ammPoolHolds(
158 *ledger, ammAccountID, issue1, issue2, FreezeHandling::fhIGNORE_FREEZE, context.j);
159 auto const lptAMMBalance =
160 accountID ? ammLPHolds(*ledger, *amm, *accountID, context.j) : (*amm)[sfLPTokenBalance];
161
162 Json::Value ammResult;
163 asset1Balance.setJson(ammResult[jss::amount]);
164 asset2Balance.setJson(ammResult[jss::amount2]);
165 lptAMMBalance.setJson(ammResult[jss::lp_token]);
166 ammResult[jss::trading_fee] = (*amm)[sfTradingFee];
167 ammResult[jss::account] = to_string(ammAccountID);
168 Json::Value voteSlots(Json::arrayValue);
169 if (amm->isFieldPresent(sfVoteSlots))
170 {
171 for (auto const& voteEntry : amm->getFieldArray(sfVoteSlots))
172 {
173 Json::Value vote;
174 vote[jss::account] = to_string(voteEntry.getAccountID(sfAccount));
175 vote[jss::trading_fee] = voteEntry[sfTradingFee];
176 vote[jss::vote_weight] = voteEntry[sfVoteWeight];
177 voteSlots.append(std::move(vote));
178 }
179 }
180 if (voteSlots.size() > 0)
181 ammResult[jss::vote_slots] = std::move(voteSlots);
182 XRPL_ASSERT(
183 !ledger->rules().enabled(fixInnerObjTemplate) || amm->isFieldPresent(sfAuctionSlot),
184 "xrpl::doAMMInfo : auction slot is set");
185 if (amm->isFieldPresent(sfAuctionSlot))
186 {
187 auto const& auctionSlot = safe_downcast<STObject const&>(amm->peekAtField(sfAuctionSlot));
188 if (auctionSlot.isFieldPresent(sfAccount))
189 {
190 Json::Value auction;
191 auto const timeSlot = ammAuctionTimeSlot(
192 ledger->header().parentCloseTime.time_since_epoch().count(), auctionSlot);
193 auction[jss::time_interval] = timeSlot ? *timeSlot : AUCTION_SLOT_TIME_INTERVALS;
194 auctionSlot[sfPrice].setJson(auction[jss::price]);
195 auction[jss::discounted_fee] = auctionSlot[sfDiscountedFee];
196 auction[jss::account] = to_string(auctionSlot.getAccountID(sfAccount));
197 auction[jss::expiration] =
198 to_iso8601(NetClock::time_point{NetClock::duration{auctionSlot[sfExpiration]}});
199 if (auctionSlot.isFieldPresent(sfAuthAccounts))
200 {
201 Json::Value auth;
202 for (auto const& acct : auctionSlot.getFieldArray(sfAuthAccounts))
203 {
204 Json::Value jv;
205 jv[jss::account] = to_string(acct.getAccountID(sfAccount));
206 auth.append(jv);
207 }
208 auction[jss::auth_accounts] = auth;
209 }
210 ammResult[jss::auction_slot] = std::move(auction);
211 }
212 }
213
214 if (!isXRP(asset1Balance))
215 {
216 ammResult[jss::asset_frozen] =
217 isFrozen(*ledger, ammAccountID, issue1.currency, issue1.account);
218 }
219 if (!isXRP(asset2Balance))
220 {
221 ammResult[jss::asset2_frozen] =
222 isFrozen(*ledger, ammAccountID, issue2.currency, issue2.account);
223 }
224
225 result[jss::amm] = std::move(ammResult);
226 if (!result.isMember(jss::ledger_index) && !result.isMember(jss::ledger_hash))
227 result[jss::ledger_current_index] = ledger->header().seq;
228 result[jss::validated] = context.ledgerMaster.isValidated(*ledger);
229
230 return result;
231}
232
233} // namespace xrpl
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.
A generic endpoint for log messages.
Definition Journal.h:40
Stream debug() const
Definition Journal.h:301
A currency issued by an account.
Definition Issue.h:13
bool isValidated(ReadView const &ledger)
@ arrayValue
array value (ordered list)
Definition json_value.h:25
void inject_error(error_code_i code, Json::Value &json)
Add or update the json update to reflect the error code.
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.
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
Definition Indexes.cpp:404
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:165
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::uint16_t constexpr AUCTION_SLOT_TIME_INTERVALS
Definition AMMCore.h:15
@ fhIGNORE_FREEZE
std::string to_iso8601(NetClock::time_point tp)
Definition AMMInfo.cpp:31
bool isXRP(AccountID const &c)
Definition AccountID.h:70
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602
Json::Value doAMMInfo(RPC::JsonContext &)
Definition AMMInfo.cpp:42
bool isFrozen(ReadView const &view, AccountID const &account, MPTIssue const &mptIssue, int depth=0)
Issue issueFromJson(Json::Value const &v)
Definition Issue.cpp:88
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:12
static constexpr std::chrono::seconds epoch_offset
Clock for measuring the network time.
Definition chrono.h:33
std::optional< std::uint8_t > ammAuctionTimeSlot(std::uint64_t current, STObject const &auctionSlot)
Get time slot of the auction slot.
Definition AMMCore.cpp:83
@ rpcISSUE_MALFORMED
Definition ErrorCodes.h:126
@ rpcACT_NOT_FOUND
Definition ErrorCodes.h:50
@ rpcINVALID_PARAMS
Definition ErrorCodes.h:64
@ rpcACT_MALFORMED
Definition ErrorCodes.h:70
Issue getIssue(T const &amt)
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:87
@ invalid
Timely, but invalid signature.
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 what(T... args)