rippled
Loading...
Searching...
No Matches
AMMUtils.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2023 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19#include <xrpld/app/misc/AMMUtils.h>
20#include <xrpld/ledger/Sandbox.h>
21#include <xrpl/basics/Log.h>
22#include <xrpl/protocol/AMMCore.h>
23#include <xrpl/protocol/STAccount.h>
24#include <xrpl/protocol/STObject.h>
25
26namespace ripple {
27
30 ReadView const& view,
32 Issue const& issue1,
33 Issue const& issue2,
34 FreezeHandling freezeHandling,
35 beast::Journal const j)
36{
37 auto const assetInBalance =
38 accountHolds(view, ammAccountID, issue1, freezeHandling, j);
39 auto const assetOutBalance =
40 accountHolds(view, ammAccountID, issue2, freezeHandling, j);
41 return std::make_pair(assetInBalance, assetOutBalance);
42}
43
44Expected<std::tuple<STAmount, STAmount, STAmount>, TER>
46 ReadView const& view,
47 SLE const& ammSle,
48 std::optional<Issue> const& optIssue1,
49 std::optional<Issue> const& optIssue2,
50 FreezeHandling freezeHandling,
51 beast::Journal const j)
52{
53 auto const issues = [&]() -> std::optional<std::pair<Issue, Issue>> {
54 auto const issue1 = ammSle[sfAsset].get<Issue>();
55 auto const issue2 = ammSle[sfAsset2].get<Issue>();
56 if (optIssue1 && optIssue2)
57 {
59 *optIssue1,
60 *optIssue2,
61 std::make_optional(std::make_pair(issue1, issue2))))
62 {
63 // This error can only be hit if the AMM is corrupted
64 // LCOV_EXCL_START
65 JLOG(j.debug()) << "ammHolds: Invalid optIssue1 or optIssue2 "
66 << *optIssue1 << " " << *optIssue2;
67 return std::nullopt;
68 // LCOV_EXCL_STOP
69 }
70 return std::make_optional(std::make_pair(*optIssue1, *optIssue2));
71 }
72 auto const singleIssue =
73 [&issue1, &issue2, &j](
74 Issue checkIssue,
75 const char* label) -> std::optional<std::pair<Issue, Issue>> {
76 if (checkIssue == issue1)
77 return std::make_optional(std::make_pair(issue1, issue2));
78 else if (checkIssue == issue2)
79 return std::make_optional(std::make_pair(issue2, issue1));
80 // Unreachable unless AMM corrupted.
81 // LCOV_EXCL_START
82 JLOG(j.debug())
83 << "ammHolds: Invalid " << label << " " << checkIssue;
84 return std::nullopt;
85 // LCOV_EXCL_STOP
86 };
87 if (optIssue1)
88 {
89 return singleIssue(*optIssue1, "optIssue1");
90 }
91 else if (optIssue2)
92 {
93 // Cannot have Amount2 without Amount.
94 return singleIssue(*optIssue2, "optIssue2"); // LCOV_EXCL_LINE
95 }
96 return std::make_optional(std::make_pair(issue1, issue2));
97 }();
98 if (!issues)
100 auto const [asset1, asset2] = ammPoolHolds(
101 view,
102 ammSle.getAccountID(sfAccount),
103 issues->first,
104 issues->second,
105 freezeHandling,
106 j);
107 return std::make_tuple(asset1, asset2, ammSle[sfLPTokenBalance]);
108}
109
110STAmount
112 ReadView const& view,
113 Currency const& cur1,
114 Currency const& cur2,
115 AccountID const& ammAccount,
116 AccountID const& lpAccount,
117 beast::Journal const j)
118{
119 // This function looks similar to `accountHolds`. However, it only checks if
120 // a LPToken holder has enough balance. On the other hand, `accountHolds`
121 // checks if the underlying assets of LPToken are frozen with the
122 // fixFrozenLPTokenTransfer amendment
123
124 auto const currency = ammLPTCurrency(cur1, cur2);
125 STAmount amount;
126
127 auto const sle = view.read(keylet::line(lpAccount, ammAccount, currency));
128 if (!sle)
129 {
130 amount.clear(Issue{currency, ammAccount});
131 JLOG(j.trace()) << "ammLPHolds: no SLE "
132 << " lpAccount=" << to_string(lpAccount)
133 << " amount=" << amount.getFullText();
134 }
135 else if (isFrozen(view, lpAccount, currency, ammAccount))
136 {
137 amount.clear(Issue{currency, ammAccount});
138 JLOG(j.trace()) << "ammLPHolds: frozen currency "
139 << " lpAccount=" << to_string(lpAccount)
140 << " amount=" << amount.getFullText();
141 }
142 else
143 {
144 amount = sle->getFieldAmount(sfBalance);
145 if (lpAccount > ammAccount)
146 {
147 // Put balance in account terms.
148 amount.negate();
149 }
150 amount.setIssuer(ammAccount);
151
152 JLOG(j.trace()) << "ammLPHolds:"
153 << " lpAccount=" << to_string(lpAccount)
154 << " amount=" << amount.getFullText();
155 }
156
157 return view.balanceHook(lpAccount, ammAccount, amount);
158}
159
160STAmount
162 ReadView const& view,
163 SLE const& ammSle,
164 AccountID const& lpAccount,
165 beast::Journal const j)
166{
167 return ammLPHolds(
168 view,
169 ammSle[sfAsset].get<Issue>().currency,
170 ammSle[sfAsset2].get<Issue>().currency,
171 ammSle[sfAccount],
172 lpAccount,
173 j);
174}
175
177getTradingFee(ReadView const& view, SLE const& ammSle, AccountID const& account)
178{
179 using namespace std::chrono;
180 XRPL_ASSERT(
181 !view.rules().enabled(fixInnerObjTemplate) ||
182 ammSle.isFieldPresent(sfAuctionSlot),
183 "ripple::getTradingFee : auction present");
184 if (ammSle.isFieldPresent(sfAuctionSlot))
185 {
186 auto const& auctionSlot =
187 static_cast<STObject const&>(ammSle.peekAtField(sfAuctionSlot));
188 // Not expired
189 if (auto const expiration = auctionSlot[~sfExpiration];
190 duration_cast<seconds>(
192 .count() < expiration)
193 {
194 if (auctionSlot[~sfAccount] == account)
195 return auctionSlot[sfDiscountedFee];
196 if (auctionSlot.isFieldPresent(sfAuthAccounts))
197 {
198 for (auto const& acct :
199 auctionSlot.getFieldArray(sfAuthAccounts))
200 if (acct[~sfAccount] == account)
201 return auctionSlot[sfDiscountedFee];
202 }
203 }
204 }
205 return ammSle[sfTradingFee];
206}
207
208STAmount
210 ReadView const& view,
211 AccountID const& ammAccountID,
212 Issue const& issue)
213{
214 if (isXRP(issue))
215 {
216 if (auto const sle = view.read(keylet::account(ammAccountID)))
217 return (*sle)[sfBalance];
218 }
219 else if (auto const sle = view.read(
221 sle &&
222 !isFrozen(view, ammAccountID, issue.currency, issue.account))
223 {
224 auto amount = (*sle)[sfBalance];
225 if (ammAccountID > issue.account)
226 amount.negate();
227 amount.setIssuer(issue.account);
228 return amount;
229 }
230
231 return STAmount{issue};
232}
233
234static TER
236 Sandbox& sb,
237 AccountID const& ammAccountID,
238 std::uint16_t maxTrustlinesToDelete,
240{
242 sb,
244 [&](LedgerEntryType nodeType,
245 uint256 const&,
247 // Skip AMM
248 if (nodeType == LedgerEntryType::ltAMM)
249 return {tesSUCCESS, SkipEntry::Yes};
250 // Should only have the trustlines
251 if (nodeType != LedgerEntryType::ltRIPPLE_STATE)
252 {
253 // LCOV_EXCL_START
254 JLOG(j.error())
255 << "deleteAMMTrustLines: deleting non-trustline "
256 << nodeType;
257 return {tecINTERNAL, SkipEntry::No};
258 // LCOV_EXCL_STOP
259 }
260
261 // Trustlines must have zero balance
262 if (sleItem->getFieldAmount(sfBalance) != beast::zero)
263 {
264 // LCOV_EXCL_START
265 JLOG(j.error())
266 << "deleteAMMTrustLines: deleting trustline with "
267 "non-zero balance.";
268 return {tecINTERNAL, SkipEntry::No};
269 // LCOV_EXCL_STOP
270 }
271
272 return {
273 deleteAMMTrustLine(sb, sleItem, ammAccountID, j),
275 },
276 j,
277 maxTrustlinesToDelete);
278}
279
280TER
282 Sandbox& sb,
283 Issue const& asset,
284 Issue const& asset2,
286{
287 auto ammSle = sb.peek(keylet::amm(asset, asset2));
288 if (!ammSle)
289 {
290 // LCOV_EXCL_START
291 JLOG(j.error()) << "deleteAMMAccount: AMM object does not exist "
292 << asset << " " << asset2;
293 return tecINTERNAL;
294 // LCOV_EXCL_STOP
295 }
296
297 auto const ammAccountID = (*ammSle)[sfAccount];
298 auto sleAMMRoot = sb.peek(keylet::account(ammAccountID));
299 if (!sleAMMRoot)
300 {
301 // LCOV_EXCL_START
302 JLOG(j.error()) << "deleteAMMAccount: AMM account does not exist "
304 return tecINTERNAL;
305 // LCOV_EXCL_STOP
306 }
307
308 if (auto const ter =
310 ter != tesSUCCESS)
311 return ter;
312
313 auto const ownerDirKeylet = keylet::ownerDir(ammAccountID);
314 if (!sb.dirRemove(
315 ownerDirKeylet, (*ammSle)[sfOwnerNode], ammSle->key(), false))
316 {
317 // LCOV_EXCL_START
318 JLOG(j.error()) << "deleteAMMAccount: failed to remove dir link";
319 return tecINTERNAL;
320 // LCOV_EXCL_STOP
321 }
322 if (sb.exists(ownerDirKeylet) && !sb.emptyDirDelete(ownerDirKeylet))
323 {
324 // LCOV_EXCL_START
325 JLOG(j.error()) << "deleteAMMAccount: cannot delete root dir node of "
327 return tecINTERNAL;
328 // LCOV_EXCL_STOP
329 }
330
331 sb.erase(ammSle);
332 sb.erase(sleAMMRoot);
333
334 return tesSUCCESS;
335}
336
337void
339 ApplyView& view,
340 std::shared_ptr<SLE>& ammSle,
341 AccountID const& account,
342 Issue const& lptIssue,
343 std::uint16_t tfee)
344{
345 auto const& rules = view.rules();
346 // AMM creator gets the voting slot.
347 STArray voteSlots;
348 STObject voteEntry = STObject::makeInnerObject(sfVoteEntry);
349 if (tfee != 0)
350 voteEntry.setFieldU16(sfTradingFee, tfee);
351 voteEntry.setFieldU32(sfVoteWeight, VOTE_WEIGHT_SCALE_FACTOR);
352 voteEntry.setAccountID(sfAccount, account);
353 voteSlots.push_back(voteEntry);
354 ammSle->setFieldArray(sfVoteSlots, voteSlots);
355 // AMM creator gets the auction slot for free.
356 // AuctionSlot is created on AMMCreate and updated on AMMDeposit
357 // when AMM is in an empty state
358 if (rules.enabled(fixInnerObjTemplate) &&
359 !ammSle->isFieldPresent(sfAuctionSlot))
360 {
361 STObject auctionSlot = STObject::makeInnerObject(sfAuctionSlot);
362 ammSle->set(std::move(auctionSlot));
363 }
364 STObject& auctionSlot = ammSle->peekFieldObject(sfAuctionSlot);
365 auctionSlot.setAccountID(sfAccount, account);
366 // current + sec in 24h
367 auto const expiration = std::chrono::duration_cast<std::chrono::seconds>(
369 .count() +
371 auctionSlot.setFieldU32(sfExpiration, expiration);
372 auctionSlot.setFieldAmount(sfPrice, STAmount{lptIssue, 0});
373 // Set the fee
374 if (tfee != 0)
375 ammSle->setFieldU16(sfTradingFee, tfee);
376 else if (ammSle->isFieldPresent(sfTradingFee))
377 ammSle->makeFieldAbsent(sfTradingFee); // LCOV_EXCL_LINE
378 if (auto const dfee = tfee / AUCTION_SLOT_DISCOUNTED_FEE_FRACTION)
379 auctionSlot.setFieldU16(sfDiscountedFee, dfee);
380 else if (auctionSlot.isFieldPresent(sfDiscountedFee))
381 auctionSlot.makeFieldAbsent(sfDiscountedFee); // LCOV_EXCL_LINE
382}
383
384Expected<bool, TER>
386 ReadView const& view,
387 Issue const& ammIssue,
388 AccountID const& lpAccount)
389{
390 // Liquidity Provider (LP) must have one LPToken trustline
391 std::uint8_t nLPTokenTrustLines = 0;
392 // There are at most two IOU trustlines. One or both could be to the LP
393 // if LP is the issuer, or a different account if LP is not an issuer.
394 // For instance, if AMM has two tokens USD and EUR and LP is not the issuer
395 // of the tokens then the trustlines are between AMM account and the issuer.
396 std::uint8_t nIOUTrustLines = 0;
397 // There is only one AMM object
398 bool hasAMM = false;
399 // AMM LP has at most three trustlines and only one AMM object must exist.
400 // If there are more than five objects then it's either an error or
401 // there are more than one LP. Ten pages should be sufficient to include
402 // five objects.
403 std::uint8_t limit = 10;
404 auto const root = keylet::ownerDir(ammIssue.account);
405 auto currentIndex = root;
406
407 // Iterate over AMM owner directory objects.
408 while (limit-- >= 1)
409 {
410 auto const ownerDir = view.read(currentIndex);
411 if (!ownerDir)
412 return Unexpected<TER>(tecINTERNAL); // LCOV_EXCL_LINE
413 for (auto const& key : ownerDir->getFieldV256(sfIndexes))
414 {
415 auto const sle = view.read(keylet::child(key));
416 if (!sle)
417 return Unexpected<TER>(tecINTERNAL); // LCOV_EXCL_LINE
418 // Only one AMM object
419 if (sle->getFieldU16(sfLedgerEntryType) == ltAMM)
420 {
421 if (hasAMM)
422 return Unexpected<TER>(tecINTERNAL); // LCOV_EXCL_LINE
423 hasAMM = true;
424 continue;
425 }
426 if (sle->getFieldU16(sfLedgerEntryType) != ltRIPPLE_STATE)
427 return Unexpected<TER>(tecINTERNAL); // LCOV_EXCL_LINE
428 auto const lowLimit = sle->getFieldAmount(sfLowLimit);
429 auto const highLimit = sle->getFieldAmount(sfHighLimit);
430 auto const isLPTrustline = lowLimit.getIssuer() == lpAccount ||
431 highLimit.getIssuer() == lpAccount;
432 auto const isLPTokenTrustline =
433 lowLimit.issue() == ammIssue || highLimit.issue() == ammIssue;
434
435 // Liquidity Provider trustline
436 if (isLPTrustline)
437 {
438 // LPToken trustline
439 if (isLPTokenTrustline)
440 {
441 if (++nLPTokenTrustLines > 1)
442 return Unexpected<TER>(tecINTERNAL); // LCOV_EXCL_LINE
443 }
444 else if (++nIOUTrustLines > 2)
445 return Unexpected<TER>(tecINTERNAL); // LCOV_EXCL_LINE
446 }
447 // Another Liquidity Provider LPToken trustline
448 else if (isLPTokenTrustline)
449 return false;
450 else if (++nIOUTrustLines > 2)
451 return Unexpected<TER>(tecINTERNAL); // LCOV_EXCL_LINE
452 }
453 auto const uNodeNext = ownerDir->getFieldU64(sfIndexNext);
454 if (uNodeNext == 0)
455 {
456 if (nLPTokenTrustLines != 1 || nIOUTrustLines == 0 ||
457 nIOUTrustLines > 2)
458 return Unexpected<TER>(tecINTERNAL); // LCOV_EXCL_LINE
459 return true;
460 }
461 currentIndex = keylet::page(root, uNodeNext);
462 }
463 return Unexpected<TER>(tecINTERNAL); // LCOV_EXCL_LINE
464}
465
466} // namespace ripple
A generic endpoint for log messages.
Definition: Journal.h:59
Stream error() const
Definition: Journal.h:335
Stream debug() const
Definition: Journal.h:317
Stream trace() const
Severity stream access functions.
Definition: Journal.h:311
Writeable view to a ledger, for applying a transaction.
Definition: ApplyView.h:140
bool dirRemove(Keylet const &directory, std::uint64_t page, uint256 const &key, bool keepRoot)
Remove an entry from a directory.
Definition: ApplyView.cpp:189
bool emptyDirDelete(Keylet const &directory)
Remove the specified directory, if it is empty.
Definition: ApplyView.cpp:125
A currency issued by an account.
Definition: Issue.h:36
AccountID account
Definition: Issue.h:39
Currency currency
Definition: Issue.h:38
A view into a ledger.
Definition: ReadView.h:55
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
virtual STAmount balanceHook(AccountID const &account, AccountID const &issuer, STAmount const &amount) const
Definition: ReadView.h:182
virtual LedgerInfo const & info() const =0
Returns information about the ledger.
virtual Rules const & rules() const =0
Returns the tx processing rules.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition: Rules.cpp:122
void setIssuer(AccountID const &uIssuer)
Definition: STAmount.h:569
std::string getFullText() const override
Definition: STAmount.cpp:505
void push_back(STObject const &object)
Definition: STArray.h:212
AccountID getAccountID(SField const &field) const
Definition: STObject.cpp:621
void makeFieldAbsent(SField const &field)
Definition: STObject.cpp:540
void setFieldU16(SField const &field, std::uint16_t)
Definition: STObject.cpp:705
void setFieldAmount(SField const &field, STAmount const &)
Definition: STObject.cpp:759
const STBase & peekAtField(SField const &field) const
Definition: STObject.cpp:399
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:454
static STObject makeInnerObject(SField const &name)
Definition: STObject.cpp:65
void setAccountID(SField const &field, AccountID const &)
Definition: STObject.cpp:741
void setFieldU32(SField const &field, std::uint32_t)
Definition: STObject.cpp:711
Discardable, editable view to a ledger.
Definition: Sandbox.h:35
void erase(std::shared_ptr< SLE > const &sle) override
Remove a peeked SLE.
bool exists(Keylet const &k) const override
Determine if a state item exists.
std::shared_ptr< SLE > peek(Keylet const &k) override
Prepare to modify the SLE associated with key.
T make_optional(T... args)
T make_pair(T... args)
T make_tuple(T... args)
Keylet child(uint256 const &key) noexcept
Any item that can be in an owner dir.
Definition: Indexes.cpp:166
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
Definition: Indexes.cpp:422
Keylet line(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition: Indexes.cpp:220
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:160
Keylet page(uint256 const &root, std::uint64_t index=0) noexcept
A page in a directory.
Definition: Indexes.cpp:356
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:350
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:106
FreezeHandling
Controls the treatment of frozen account balances.
Definition: View.h:80
std::uint32_t constexpr TOTAL_TIME_SLOT_SECS
Definition: AMMCore.h:34
bool isXRP(AccountID const &c)
Definition: AccountID.h:91
TER deleteAMMTrustLine(ApplyView &view, std::shared_ptr< SLE > sleState, std::optional< AccountID > const &ammAccountID, beast::Journal j)
Delete trustline to AMM.
Definition: View.cpp:2050
Currency ammLPTCurrency(Currency const &cur1, Currency const &cur2)
Calculate Liquidity Provider Token (LPT) Currency.
Definition: AMMCore.cpp:42
std::uint16_t getTradingFee(ReadView const &view, SLE const &ammSle, AccountID const &account)
Get AMM trading fee for the given account.
Definition: AMMUtils.cpp:177
TER deleteAMMAccount(Sandbox &view, Issue const &asset, Issue const &asset2, beast::Journal j)
Delete trustlines to AMM.
Definition: AMMUtils.cpp:281
Expected< bool, TER > isOnlyLiquidityProvider(ReadView const &view, Issue const &ammIssue, AccountID const &lpAccount)
Return true if the Liquidity Provider is the only AMM provider, false otherwise.
Definition: AMMUtils.cpp:385
bool isFrozen(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer)
Definition: View.cpp:238
AccountID ammAccountID(std::uint16_t prefix, uint256 const &parentHash, uint256 const &ammID)
Calculate AMM account ID.
Definition: AMMCore.cpp:30
void initializeFeeAuctionVote(ApplyView &view, std::shared_ptr< SLE > &ammSle, AccountID const &account, Issue const &lptIssue, std::uint16_t tfee)
Initialize Auction and Voting slots and set the trading/discounted fee.
Definition: AMMUtils.cpp:338
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:111
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:29
static TER deleteAMMTrustLines(Sandbox &sb, AccountID const &ammAccountID, std::uint16_t maxTrustlinesToDelete, beast::Journal j)
Definition: AMMUtils.cpp:235
@ tecINTERNAL
Definition: TER.h:297
@ tecAMM_INVALID_TOKENS
Definition: TER.h:318
std::uint32_t constexpr VOTE_WEIGHT_SCALE_FACTOR
Definition: AMMCore.h:45
@ tesSUCCESS
Definition: TER.h:242
NotTEC invalidAMMAssetPair(Issue const &issue1, Issue const &issue2, std::optional< std::pair< Issue, Issue > > const &pair=std::nullopt)
Definition: AMMCore.cpp:79
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:308
Expected< std::tuple< STAmount, STAmount, STAmount >, TER > ammHolds(ReadView const &view, SLE const &ammSle, std::optional< Issue > const &optIssue1, std::optional< Issue > const &optIssue2, FreezeHandling freezeHandling, beast::Journal const j)
Get AMM pool and LP token balances.
Definition: AMMUtils.cpp:45
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
LedgerEntryType
Identifiers for on-ledger objects.
Definition: LedgerFormats.h:54
TER cleanupOnAccountDelete(ApplyView &view, Keylet const &ownerDirKeylet, EntryDeleter const &deleter, beast::Journal j, std::optional< uint16_t > maxNodesToDelete)
Definition: View.cpp:1972
STAmount ammAccountHolds(ReadView const &view, AccountID const &ammAccountID, Issue const &issue)
Returns total amount held by AMM for the given token.
Definition: AMMUtils.cpp:209
Number root(Number f, unsigned d)
Definition: Number.cpp:630
std::uint16_t constexpr maxDeletableAMMTrustLines
The maximum number of trustlines to delete as part of AMM account deletion cleanup.
Definition: Protocol.h:130
TERSubset< CanCvtToTER > TER
Definition: TER.h:627
std::uint32_t constexpr AUCTION_SLOT_DISCOUNTED_FEE_FRACTION
Definition: AMMCore.h:38
NetClock::time_point parentCloseTime
Definition: LedgerHeader.h:42
T time_since_epoch(T... args)