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