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