1#include <xrpl/ledger/helpers/RippleStateHelpers.h>
3#include <xrpl/basics/Log.h>
4#include <xrpl/ledger/ApplyView.h>
5#include <xrpl/ledger/ReadView.h>
6#include <xrpl/ledger/helpers/AccountRootHelpers.h>
7#include <xrpl/ledger/helpers/DirectoryHelpers.h>
8#include <xrpl/protocol/AmountConversions.h>
9#include <xrpl/protocol/Feature.h>
10#include <xrpl/protocol/Indexes.h>
11#include <xrpl/protocol/LedgerFormats.h>
12#include <xrpl/protocol/Rules.h>
35 result = sleRippleState->getFieldAmount(account < issuer ? sfLowLimit : sfHighLimit);
36 result.setIssuer(account);
39 XRPL_ASSERT(result.getIssuer() == account,
"xrpl::creditLimit : result issuer match");
40 XRPL_ASSERT(result.getCurrency() == currency,
"xrpl::creditLimit : result currency match");
63 result = sleRippleState->getFieldAmount(sfBalance);
66 result.setIssuer(account);
69 XRPL_ASSERT(result.getIssuer() == account,
"xrpl::creditBalance : result issuer match");
70 XRPL_ASSERT(result.getCurrency() == currency,
"xrpl::creditBalance : result currency match");
89 if (issuer != account)
93 if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
111 if (sle && sle->isFlag(lsfGlobalFreeze))
113 if (issuer != account)
117 if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
135 if (issuer == account)
146 return sle->isFlag(lsfHighDeepFreeze) || sle->isFlag(lsfLowDeepFreeze);
164 bool const bNoRipple,
175 JLOG(j.
trace()) <<
"trustCreate: " <<
to_string(uSrcAccountID) <<
", "
178 auto const& uLowAccountID = !bSrcHigh ? uSrcAccountID : uDstAccountID;
179 auto const& uHighAccountID = bSrcHigh ? uSrcAccountID : uDstAccountID;
180 if (uLowAccountID == uHighAccountID)
183 UNREACHABLE(
"xrpl::trustCreate : trust line to self");
190 view.
insert(sleRippleState);
204 bool const bSetDst = saLimit.
getIssuer() == uDstAccountID;
205 bool const bSetHigh = bSrcHigh ^ bSetDst;
207 XRPL_ASSERT(sleAccount,
"xrpl::trustCreate : non-null SLE");
212 sleAccount->getAccountID(sfAccount) == (bSetHigh ? uHighAccountID : uLowAccountID),
213 "xrpl::trustCreate : matching account ID");
214 auto const slePeer = view.
peek(
keylet::account(bSetHigh ? uLowAccountID : uHighAccountID));
219 sleRippleState->setFieldU64(sfLowNode, *lowNode);
220 sleRippleState->setFieldU64(sfHighNode, *highNode);
222 sleRippleState->setFieldAmount(bSetHigh ? sfHighLimit : sfLowLimit, saLimit);
223 sleRippleState->setFieldAmount(
224 bSetHigh ? sfLowLimit : sfHighLimit,
227 if (uQualityIn != 0u)
228 sleRippleState->setFieldU32(bSetHigh ? sfHighQualityIn : sfLowQualityIn, uQualityIn);
230 if (uQualityOut != 0u)
231 sleRippleState->setFieldU32(bSetHigh ? sfHighQualityOut : sfLowQualityOut, uQualityOut);
233 std::uint32_t uFlags = bSetHigh ? lsfHighReserve : lsfLowReserve;
237 uFlags |= (bSetHigh ? lsfHighAuth : lsfLowAuth);
241 uFlags |= (bSetHigh ? lsfHighNoRipple : lsfLowNoRipple);
245 uFlags |= (bSetHigh ? lsfHighFreeze : lsfLowFreeze);
249 uFlags |= (bSetHigh ? lsfHighDeepFreeze : lsfLowDeepFreeze);
252 if ((slePeer->getFlags() & lsfDefaultRipple) == 0)
255 uFlags |= (bSetHigh ? lsfLowNoRipple : lsfHighNoRipple);
258 sleRippleState->setFieldU32(sfFlags, uFlags);
262 sleRippleState->setFieldAmount(sfBalance, bSetHigh ? -saBalance : saBalance);
264 view.
creditHook(uSrcAccountID, uDstAccountID, saBalance, saBalance.
zeroed());
278 std::uint64_t const uLowNode = sleRippleState->getFieldU64(sfLowNode);
279 std::uint64_t const uHighNode = sleRippleState->getFieldU64(sfHighNode);
281 JLOG(j.
trace()) <<
"trustDelete: Deleting ripple line: low";
288 JLOG(j.
trace()) <<
"trustDelete: Deleting ripple line: high";
295 JLOG(j.
trace()) <<
"trustDelete: Deleting ripple line: state";
296 view.
erase(sleRippleState);
326 if (before > beast::zero
328 &&
after <= beast::zero
330 && ((flags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve)) != 0u)
332 &&
static_cast<bool>(flags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
333 static_cast<bool>(sle->getFlags() & lsfDefaultRipple) &&
334 ((flags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) == 0u) &&
337 && (state->
getFieldU32(!bSenderHigh ? sfLowQualityIn : sfHighQualityIn) == 0u)
339 && (state->
getFieldU32(!bSenderHigh ? sfLowQualityOut : sfHighQualityOut) == 0u))
347 state->
setFieldU32(sfFlags, flags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve));
351 && ((flags & (bSenderHigh ? lsfLowReserve : lsfHighReserve)) == 0u))
367 "xrpl::issueIOU : neither account nor issuer is XRP");
370 XRPL_ASSERT(issue == amount.issue(),
"xrpl::issueIOU : matching issue");
373 XRPL_ASSERT(issue.
account != account,
"xrpl::issueIOU : not issuer account");
375 JLOG(j.
trace()) <<
"issueIOU: " <<
to_string(account) <<
": " << amount.getFullText();
377 bool const bSenderHigh = issue.
account > account;
381 if (
auto state = view.
peek(index))
383 STAmount final_balance = state->getFieldAmount(sfBalance);
388 STAmount const start_balance = final_balance;
390 final_balance -= amount;
393 view, state, bSenderHigh, issue.
account, start_balance, final_balance, j);
403 state->setFieldAmount(sfBalance, final_balance);
409 bSenderHigh ? account : issue.
account,
410 bSenderHigh ? issue.
account : account,
428 if (!receiverAccount)
431 bool const noRipple = (receiverAccount->getFlags() & lsfDefaultRipple) == 0;
461 "xrpl::redeemIOU : neither account nor issuer is XRP");
464 XRPL_ASSERT(issue == amount.issue(),
"xrpl::redeemIOU : matching issue");
467 XRPL_ASSERT(issue.
account != account,
"xrpl::redeemIOU : not issuer account");
469 JLOG(j.
trace()) <<
"redeemIOU: " <<
to_string(account) <<
": " << amount.getFullText();
471 bool const bSenderHigh = account > issue.
account;
475 STAmount final_balance = state->getFieldAmount(sfBalance);
480 STAmount const start_balance = final_balance;
482 final_balance -= amount;
484 auto const must_delete =
485 updateTrustLine(view, state, bSenderHigh, account, start_balance, final_balance, j);
495 state->setFieldAmount(sfBalance, final_balance);
502 bSenderHigh ? issue.
account : account,
503 bSenderHigh ? account : issue.
account,
515 JLOG(j.
fatal()) <<
"redeemIOU: " <<
to_string(account) <<
" attempts to "
516 <<
"redeem " << amount.getFullText() <<
" but no trust line exists!";
542 issuerAccount && (((*issuerAccount)[sfFlags] & lsfRequireAuth) != 0u))
546 return (((*trustLine)[sfFlags] &
547 ((account > issue.
account) ? lsfLowAuth : lsfHighAuth)) != 0u)
563 auto const& issuerId = issue.
getIssuer();
564 if (issuerId == from || issuerId == to)
567 if (sleIssuer ==
nullptr)
570 auto const isRippleDisabled = [&](
AccountID account) ->
bool {
576 bool const issuerHigh = issuerId > account;
577 return line->isFlag(issuerHigh ? lsfHighNoRipple : lsfLowNoRipple);
579 return !sleIssuer->isFlag(lsfDefaultRipple);
583 if (isRippleDisabled(from) && isRippleDisabled(to))
607 auto const& issuerId = issue.
getIssuer();
608 auto const& currency = issue.
currency;
612 auto const& srcId = issuerId;
613 auto const& dstId = accountID;
614 auto const high = srcId > dstId;
615 auto const index =
keylet::line(srcId, dstId, currency);
618 if (!sleDst || !sleSrc)
620 if (!sleSrc->isFlag(lsfDefaultRipple))
623 if (view.
read(index))
642 STAmount{Issue{currency, noAccount()}},
643 STAmount{Issue{currency, dstId}},
658 auto const sle = view.
read(keylet::account(accountID));
662 auto const balance = sle->getFieldAmount(sfBalance);
663 if (balance.xrp() != 0)
672 bool const accountIsIssuer = accountID == issue.
account;
673 auto const line = view.
peek(keylet::line(accountID, issue));
676 if (!accountIsIssuer && line->at(sfBalance)->iou() != beast::zero)
680 if (line->isFlag(lsfLowReserve))
683 auto sleLowAccount = view.
peek(keylet::account(line->at(sfLowLimit)->getIssuer()));
691 line->clearFlag(lsfLowReserve);
694 if (line->isFlag(lsfHighReserve))
697 auto sleHighAccount = view.
peek(keylet::account(line->at(sfHighLimit)->getIssuer()));
705 line->clearFlag(lsfHighReserve);
709 view, line, line->at(sfLowLimit)->getIssuer(), line->at(sfHighLimit)->getIssuer(), journal);
719 if (!sleState || sleState->getType() != ltRIPPLE_STATE)
723 sleState->getFieldAmount(sfLowLimit).getIssuer(),
724 sleState->getFieldAmount(sfHighLimit).getIssuer());
725 auto sleLow = view.
peek(keylet::account(low));
726 auto sleHigh = view.
peek(keylet::account(high));
727 if (!sleLow || !sleHigh)
730 bool const ammLow = sleLow->isFieldPresent(sfAMMID);
731 bool const ammHigh = sleHigh->isFieldPresent(sfAMMID);
734 if (ammLow && ammHigh)
738 if (!ammLow && !ammHigh)
742 if (ammAccountID && (low != *ammAccountID && high != *ammAccountID))
747 JLOG(j.
error()) <<
"deleteAMMTrustLine: failed to delete the trustline.";
751 auto const uFlags = !ammLow ? lsfLowReserve : lsfHighReserve;
752 if ((sleState->getFlags() & uFlags) == 0u)
A generic endpoint for log messages.
Stream trace() const
Severity stream access functions.
Writeable view to a ledger, for applying a transaction.
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
bool dirRemove(Keylet const &directory, std::uint64_t page, uint256 const &key, bool keepRoot)
Remove an entry from a directory.
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
virtual void insert(std::shared_ptr< SLE > const &sle)=0
Insert a new state SLE.
virtual void creditHook(AccountID const &from, AccountID const &to, STAmount const &amount, STAmount const &preCreditBalance)
std::optional< std::uint64_t > dirInsert(Keylet const &directory, uint256 const &key, std::function< void(std::shared_ptr< SLE > const &)> const &describe)
Insert an entry to a directory.
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
A currency issued by an account.
AccountID const & getIssuer() const
virtual Rules const & rules() const =0
Returns the tx processing rules.
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
std::string getFullText() const override
STAmount zeroed() const
Returns a zero value with the same issuer and currency.
Currency const & getCurrency() const
AccountID const & getIssuer() const
std::uint32_t getFieldU32(SField const &field) const
void setFieldU32(SField const &field, std::uint32_t)
STAmount const & getFieldAmount(SField const &field) const
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Keylet line(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
Keylet account(AccountID const &id) noexcept
AccountID root.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
bool isXRP(AccountID const &c)
TER issueIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
bool isIndividualFrozen(ReadView const &view, AccountID const &account, MPTIssue const &mptIssue)
std::string to_string(base_uint< Bits, Tag > const &a)
TER trustCreate(ApplyView &view, bool const bSrcHigh, AccountID const &uSrcAccountID, AccountID const &uDstAccountID, uint256 const &uIndex, SLE::ref sleAccount, bool const bAuth, bool const bNoRipple, bool const bFreeze, bool bDeepFreeze, STAmount const &saBalance, STAmount const &saLimit, std::uint32_t uQualityIn, std::uint32_t uQualityOut, beast::Journal j)
Create a trust line.
TER addEmptyHolding(ApplyView &view, AccountID const &accountID, XRPAmount priorBalance, MPTIssue const &mptIssue, beast::Journal journal)
TER deleteAMMTrustLine(ApplyView &view, std::shared_ptr< SLE > sleState, std::optional< AccountID > const &ammAccountID, beast::Journal j)
Delete trustline to AMM.
STAmount creditLimit(ReadView const &view, AccountID const &account, AccountID const &issuer, Currency const ¤cy)
Calculate the maximum amount of IOUs that an account can hold.
bool isDeepFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
IOUAmount creditLimit2(ReadView const &v, AccountID const &acc, AccountID const &iss, Currency const &cur)
bool isGlobalFrozen(ReadView const &view, AccountID const &issuer)
Check if the issuer has the global freeze flag set.
bool isFrozen(ReadView const &view, AccountID const &account, MPTIssue const &mptIssue, int depth=0)
TERSubset< CanCvtToTER > TER
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
STAmount creditBalance(ReadView const &view, AccountID const &account, AccountID const &issuer, Currency const ¤cy)
Returns the amount of IOUs issued by issuer that are held by an account.
TER canTransfer(ReadView const &view, MPTIssue const &mptIssue, AccountID const &from, AccountID const &to)
Check if the destination account is allowed to receive MPT.
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Returns a function that sets the owner on a directory SLE.
AccountID const & noAccount()
A placeholder for empty accounts.
static bool updateTrustLine(ApplyView &view, SLE::pointer state, bool bSenderHigh, AccountID const &sender, STAmount const &before, STAmount const &after, beast::Journal j)
TER redeemIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
IOUAmount toAmount< IOUAmount >(STAmount const &amt)
bool isTesSuccess(TER x) noexcept
@ tecNO_LINE_INSUF_RESERVE
TER trustDelete(ApplyView &view, std::shared_ptr< SLE > const &sleRippleState, AccountID const &uLowAccountID, AccountID const &uHighAccountID, beast::Journal j)
TER removeEmptyHolding(ApplyView &view, AccountID const &accountID, MPTIssue const &mptIssue, beast::Journal journal)
TER requireAuth(ReadView const &view, MPTIssue const &mptIssue, AccountID const &account, AuthType authType=AuthType::Legacy, int depth=0)
Check if the account lacks required authorization for MPT.
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.