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>(system_clock::time_point{tp.time_since_epoch() + epoch_offset}));
37}
38
41{
42 auto const& params(context.params);
43 Json::Value result;
44
46 result = RPC::lookupLedger(ledger, context);
47 if (!ledger)
48 return result;
49
50 struct ValuesFromContextParams
51 {
53 Issue issue1;
54 Issue issue2;
56 };
57
58 auto getValuesFromContextParams = [&]() -> Expected<ValuesFromContextParams, error_code_i> {
63
64 constexpr auto invalid = [](Json::Value const& params) -> bool {
65 return (params.isMember(jss::asset) != params.isMember(jss::asset2)) ||
66 (params.isMember(jss::asset) == params.isMember(jss::amm_account));
67 };
68
69 // NOTE, identical check for apVersion >= 3 below
70 if (context.apiVersion < 3 && invalid(params))
72
73 if (params.isMember(jss::asset))
74 {
75 if (auto const i = getIssue(params[jss::asset], context.j))
76 issue1 = *i;
77 else
78 return Unexpected(i.error());
79 }
80
81 if (params.isMember(jss::asset2))
82 {
83 if (auto const i = getIssue(params[jss::asset2], context.j))
84 issue2 = *i;
85 else
86 return Unexpected(i.error());
87 }
88
89 if (params.isMember(jss::amm_account))
90 {
91 auto const id = parseBase58<AccountID>((params[jss::amm_account].asString()));
92 if (!id)
94 auto const sle = ledger->read(keylet::account(*id));
95 if (!sle)
97 ammID = sle->getFieldH256(sfAMMID);
98 if (ammID->isZero())
100 }
101
102 if (params.isMember(jss::account))
103 {
104 accountID = parseBase58<AccountID>(params[jss::account].asString());
105 if (!accountID || !ledger->read(keylet::account(*accountID)))
107 }
108
109 // NOTE, identical check for apVersion < 3 above
110 if (context.apiVersion >= 3 && invalid(params))
112
113 XRPL_ASSERT(
114 (issue1.has_value() == issue2.has_value()) && (issue1.has_value() != ammID.has_value()),
115 "xrpl::doAMMInfo : issue1 and issue2 do match");
116
117 auto const ammKeylet = [&]() {
118 if (issue1 && issue2)
119 return keylet::amm(*issue1, *issue2);
120 XRPL_ASSERT(ammID, "xrpl::doAMMInfo::ammKeylet : ammID is set");
121 return keylet::amm(*ammID);
122 }();
123 auto const amm = ledger->read(ammKeylet);
124 if (!amm)
126 if (!issue1 && !issue2)
127 {
128 issue1 = (*amm)[sfAsset].get<Issue>();
129 issue2 = (*amm)[sfAsset2].get<Issue>();
130 }
131
132 return ValuesFromContextParams{accountID, *issue1, *issue2, std::move(amm)};
133 };
134
135 auto const r = getValuesFromContextParams();
136 if (!r)
137 {
138 RPC::inject_error(r.error(), result);
139 return result;
140 }
141
142 auto const& [accountID, issue1, issue2, amm] = *r;
143
144 auto const ammAccountID = amm->getAccountID(sfAccount);
145
146 // provide funds if frozen, specify asset_frozen flag
147 auto const [asset1Balance, asset2Balance] =
148 ammPoolHolds(*ledger, ammAccountID, issue1, issue2, FreezeHandling::fhIGNORE_FREEZE, context.j);
149 auto const lptAMMBalance = accountID ? ammLPHolds(*ledger, *amm, *accountID, context.j) : (*amm)[sfLPTokenBalance];
150
151 Json::Value ammResult;
152 asset1Balance.setJson(ammResult[jss::amount]);
153 asset2Balance.setJson(ammResult[jss::amount2]);
154 lptAMMBalance.setJson(ammResult[jss::lp_token]);
155 ammResult[jss::trading_fee] = (*amm)[sfTradingFee];
156 ammResult[jss::account] = to_string(ammAccountID);
157 Json::Value voteSlots(Json::arrayValue);
158 if (amm->isFieldPresent(sfVoteSlots))
159 {
160 for (auto const& voteEntry : amm->getFieldArray(sfVoteSlots))
161 {
162 Json::Value vote;
163 vote[jss::account] = to_string(voteEntry.getAccountID(sfAccount));
164 vote[jss::trading_fee] = voteEntry[sfTradingFee];
165 vote[jss::vote_weight] = voteEntry[sfVoteWeight];
166 voteSlots.append(std::move(vote));
167 }
168 }
169 if (voteSlots.size() > 0)
170 ammResult[jss::vote_slots] = std::move(voteSlots);
171 XRPL_ASSERT(
172 !ledger->rules().enabled(fixInnerObjTemplate) || amm->isFieldPresent(sfAuctionSlot),
173 "xrpl::doAMMInfo : auction slot is set");
174 if (amm->isFieldPresent(sfAuctionSlot))
175 {
176 auto const& auctionSlot = static_cast<STObject const&>(amm->peekAtField(sfAuctionSlot));
177 if (auctionSlot.isFieldPresent(sfAccount))
178 {
179 Json::Value auction;
180 auto const timeSlot =
181 ammAuctionTimeSlot(ledger->header().parentCloseTime.time_since_epoch().count(), auctionSlot);
182 auction[jss::time_interval] = timeSlot ? *timeSlot : AUCTION_SLOT_TIME_INTERVALS;
183 auctionSlot[sfPrice].setJson(auction[jss::price]);
184 auction[jss::discounted_fee] = auctionSlot[sfDiscountedFee];
185 auction[jss::account] = to_string(auctionSlot.getAccountID(sfAccount));
186 auction[jss::expiration] = to_iso8601(NetClock::time_point{NetClock::duration{auctionSlot[sfExpiration]}});
187 if (auctionSlot.isFieldPresent(sfAuthAccounts))
188 {
189 Json::Value auth;
190 for (auto const& acct : auctionSlot.getFieldArray(sfAuthAccounts))
191 {
192 Json::Value jv;
193 jv[jss::account] = to_string(acct.getAccountID(sfAccount));
194 auth.append(jv);
195 }
196 auction[jss::auth_accounts] = auth;
197 }
198 ammResult[jss::auction_slot] = std::move(auction);
199 }
200 }
201
202 if (!isXRP(asset1Balance))
203 ammResult[jss::asset_frozen] = isFrozen(*ledger, ammAccountID, issue1.currency, issue1.account);
204 if (!isXRP(asset2Balance))
205 ammResult[jss::asset2_frozen] = isFrozen(*ledger, ammAccountID, issue2.currency, issue2.account);
206
207 result[jss::amm] = std::move(ammResult);
208 if (!result.isMember(jss::ledger_index) && !result.isMember(jss::ledger_hash))
209 result[jss::ledger_current_index] = ledger->header().seq;
210 result[jss::validated] = context.ledgerMaster.isValidated(*ledger);
211
212 return result;
213}
214
215} // 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:301
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:393
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:160
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:40
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:598
Issue issueFromJson(Json::Value const &v)
Definition Issue.cpp:82
bool isFrozen(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer)
Definition View.cpp:194
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:77
@ 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:80
@ 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)