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
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 ripple {
14
17{
18 std::string strIdent(v.asString());
19 AccountID accountID;
20
21 if (auto jv = RPC::accountFromString(accountID, strIdent))
22 {
23 for (auto it = jv.begin(); it != jv.end(); ++it)
24 result[it.memberName()] = (*it);
25
26 return std::nullopt;
27 }
28 return std::optional<AccountID>(accountID);
29}
30
31Expected<Issue, error_code_i>
33{
34 try
35 {
36 return issueFromJson(v);
37 }
38 catch (std::runtime_error const& ex)
39 {
40 JLOG(j.debug()) << "getIssue " << ex.what();
41 }
43}
44
47{
48 // 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC
49 using namespace std::chrono;
50 return date::format(
51 "%Y-%Om-%dT%H:%M:%OS%z",
52 date::sys_time<system_clock::duration>(
53 system_clock::time_point{tp.time_since_epoch() + epoch_offset}));
54}
55
58{
59 auto const& params(context.params);
60 Json::Value result;
61
63 result = RPC::lookupLedger(ledger, context);
64 if (!ledger)
65 return result;
66
67 struct ValuesFromContextParams
68 {
70 Issue issue1;
71 Issue issue2;
73 };
74
75 auto getValuesFromContextParams =
81
82 constexpr auto invalid = [](Json::Value const& params) -> bool {
83 return (params.isMember(jss::asset) !=
84 params.isMember(jss::asset2)) ||
85 (params.isMember(jss::asset) ==
86 params.isMember(jss::amm_account));
87 };
88
89 // NOTE, identical check for apVersion >= 3 below
90 if (context.apiVersion < 3 && invalid(params))
92
93 if (params.isMember(jss::asset))
94 {
95 if (auto const i = getIssue(params[jss::asset], context.j))
96 issue1 = *i;
97 else
98 return Unexpected(i.error());
99 }
100
101 if (params.isMember(jss::asset2))
102 {
103 if (auto const i = getIssue(params[jss::asset2], context.j))
104 issue2 = *i;
105 else
106 return Unexpected(i.error());
107 }
108
109 if (params.isMember(jss::amm_account))
110 {
111 auto const id = getAccount(params[jss::amm_account], result);
112 if (!id)
114 auto const sle = ledger->read(keylet::account(*id));
115 if (!sle)
117 ammID = sle->getFieldH256(sfAMMID);
118 if (ammID->isZero())
120 }
121
122 if (params.isMember(jss::account))
123 {
124 accountID = getAccount(params[jss::account], result);
125 if (!accountID || !ledger->read(keylet::account(*accountID)))
127 }
128
129 // NOTE, identical check for apVersion < 3 above
130 if (context.apiVersion >= 3 && invalid(params))
132
133 XRPL_ASSERT(
134 (issue1.has_value() == issue2.has_value()) &&
135 (issue1.has_value() != ammID.has_value()),
136 "ripple::doAMMInfo : issue1 and issue2 do match");
137
138 auto const ammKeylet = [&]() {
139 if (issue1 && issue2)
140 return keylet::amm(*issue1, *issue2);
141 XRPL_ASSERT(ammID, "ripple::doAMMInfo::ammKeylet : ammID is set");
142 return keylet::amm(*ammID);
143 }();
144 auto const amm = ledger->read(ammKeylet);
145 if (!amm)
147 if (!issue1 && !issue2)
148 {
149 issue1 = (*amm)[sfAsset].get<Issue>();
150 issue2 = (*amm)[sfAsset2].get<Issue>();
151 }
152
153 return ValuesFromContextParams{
154 accountID, *issue1, *issue2, std::move(amm)};
155 };
156
157 auto const r = getValuesFromContextParams();
158 if (!r)
159 {
160 RPC::inject_error(r.error(), result);
161 return result;
162 }
163
164 auto const& [accountID, issue1, issue2, amm] = *r;
165
166 auto const ammAccountID = amm->getAccountID(sfAccount);
167
168 // provide funds if frozen, specify asset_frozen flag
169 auto const [asset1Balance, asset2Balance] = ammPoolHolds(
170 *ledger,
171 ammAccountID,
172 issue1,
173 issue2,
175 context.j);
176 auto const lptAMMBalance = accountID
177 ? ammLPHolds(*ledger, *amm, *accountID, context.j)
178 : (*amm)[sfLPTokenBalance];
179
180 Json::Value ammResult;
181 asset1Balance.setJson(ammResult[jss::amount]);
182 asset2Balance.setJson(ammResult[jss::amount2]);
183 lptAMMBalance.setJson(ammResult[jss::lp_token]);
184 ammResult[jss::trading_fee] = (*amm)[sfTradingFee];
185 ammResult[jss::account] = to_string(ammAccountID);
186 Json::Value voteSlots(Json::arrayValue);
187 if (amm->isFieldPresent(sfVoteSlots))
188 {
189 for (auto const& voteEntry : amm->getFieldArray(sfVoteSlots))
190 {
191 Json::Value vote;
192 vote[jss::account] = to_string(voteEntry.getAccountID(sfAccount));
193 vote[jss::trading_fee] = voteEntry[sfTradingFee];
194 vote[jss::vote_weight] = voteEntry[sfVoteWeight];
195 voteSlots.append(std::move(vote));
196 }
197 }
198 if (voteSlots.size() > 0)
199 ammResult[jss::vote_slots] = std::move(voteSlots);
200 XRPL_ASSERT(
201 !ledger->rules().enabled(fixInnerObjTemplate) ||
202 amm->isFieldPresent(sfAuctionSlot),
203 "ripple::doAMMInfo : auction slot is set");
204 if (amm->isFieldPresent(sfAuctionSlot))
205 {
206 auto const& auctionSlot =
207 static_cast<STObject const&>(amm->peekAtField(sfAuctionSlot));
208 if (auctionSlot.isFieldPresent(sfAccount))
209 {
210 Json::Value auction;
211 auto const timeSlot = ammAuctionTimeSlot(
212 ledger->info().parentCloseTime.time_since_epoch().count(),
213 auctionSlot);
214 auction[jss::time_interval] =
215 timeSlot ? *timeSlot : AUCTION_SLOT_TIME_INTERVALS;
216 auctionSlot[sfPrice].setJson(auction[jss::price]);
217 auction[jss::discounted_fee] = auctionSlot[sfDiscountedFee];
218 auction[jss::account] =
219 to_string(auctionSlot.getAccountID(sfAccount));
220 auction[jss::expiration] = to_iso8601(NetClock::time_point{
221 NetClock::duration{auctionSlot[sfExpiration]}});
222 if (auctionSlot.isFieldPresent(sfAuthAccounts))
223 {
224 Json::Value auth;
225 for (auto const& acct :
226 auctionSlot.getFieldArray(sfAuthAccounts))
227 {
228 Json::Value jv;
229 jv[jss::account] = to_string(acct.getAccountID(sfAccount));
230 auth.append(jv);
231 }
232 auction[jss::auth_accounts] = auth;
233 }
234 ammResult[jss::auction_slot] = std::move(auction);
235 }
236 }
237
238 if (!isXRP(asset1Balance))
239 ammResult[jss::asset_frozen] =
240 isFrozen(*ledger, ammAccountID, issue1.currency, issue1.account);
241 if (!isXRP(asset2Balance))
242 ammResult[jss::asset2_frozen] =
243 isFrozen(*ledger, ammAccountID, issue2.currency, issue2.account);
244
245 result[jss::amm] = std::move(ammResult);
246 if (!result.isMember(jss::ledger_index) &&
247 !result.isMember(jss::ledger_hash))
248 result[jss::ledger_current_index] = ledger->info().seq;
249 result[jss::validated] = context.ledgerMaster.isValidated(*ledger);
250
251 return result;
252}
253
254} // 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:16
Json::Value doAMMInfo(RPC::JsonContext &context)
Definition AMMInfo.cpp:57
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:46
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)