1#include <xrpl/ledger/helpers/RippleStateHelpers.h>
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/base_uint.h>
5#include <xrpl/beast/utility/Journal.h>
6#include <xrpl/beast/utility/Zero.h>
7#include <xrpl/beast/utility/instrumentation.h>
8#include <xrpl/ledger/ApplyView.h>
9#include <xrpl/ledger/ReadView.h>
10#include <xrpl/ledger/helpers/AccountRootHelpers.h>
11#include <xrpl/ledger/helpers/DirectoryHelpers.h>
12#include <xrpl/ledger/helpers/SponsorHelpers.h>
13#include <xrpl/ledger/helpers/TokenHelpers.h>
14#include <xrpl/protocol/AccountID.h>
15#include <xrpl/protocol/AmountConversions.h>
16#include <xrpl/protocol/Feature.h>
17#include <xrpl/protocol/IOUAmount.h>
18#include <xrpl/protocol/Indexes.h>
19#include <xrpl/protocol/Issue.h>
20#include <xrpl/protocol/LedgerFormats.h>
21#include <xrpl/protocol/Rules.h>
22#include <xrpl/protocol/SField.h>
23#include <xrpl/protocol/STAmount.h>
24#include <xrpl/protocol/STLedgerEntry.h>
25#include <xrpl/protocol/TER.h>
26#include <xrpl/protocol/UintTypes.h>
27#include <xrpl/protocol/XRPAmount.h>
55 result = sleRippleState->getFieldAmount(account < issuer ? sfLowLimit : sfHighLimit);
56 result.get<
Issue>().account = account;
59 XRPL_ASSERT(result.getIssuer() == account,
"xrpl::creditLimit : result issuer match");
62 "xrpl::creditLimit : result currency "
86 result = sleRippleState->getFieldAmount(sfBalance);
89 result.get<
Issue>().account = account;
92 XRPL_ASSERT(result.getIssuer() == account,
"xrpl::creditBalance : result issuer match");
95 "xrpl::creditBalance : result currency "
115 if (issuer != account)
119 if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
137 if (sle && sle->isFlag(lsfGlobalFreeze))
139 if (issuer != account)
143 if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
161 if (issuer == account)
172 return sle->isFlag(lsfHighDeepFreeze) || sle->isFlag(lsfLowDeepFreeze);
190 bool const bNoRipple,
202 JLOG(j.
trace()) <<
"trustCreate: " <<
to_string(uSrcAccountID) <<
", "
205 auto const& uLowAccountID = !bSrcHigh ? uSrcAccountID : uDstAccountID;
206 auto const& uHighAccountID = bSrcHigh ? uSrcAccountID : uDstAccountID;
207 if (uLowAccountID == uHighAccountID)
210 UNREACHABLE(
"xrpl::trustCreate : trust line to self");
217 view.
insert(sleRippleState);
231 bool const bSetDst = saLimit.
getIssuer() == uDstAccountID;
232 bool const bSetHigh = bSrcHigh ^ bSetDst;
234 XRPL_ASSERT(sleAccount,
"xrpl::trustCreate : non-null SLE");
239 sleAccount->getAccountID(sfAccount) == (bSetHigh ? uHighAccountID : uLowAccountID),
240 "xrpl::trustCreate : matching account ID");
241 auto const slePeer = view.
peek(
keylet::account(bSetHigh ? uLowAccountID : uHighAccountID));
246 sleRippleState->setFieldU64(sfLowNode, *lowNode);
247 sleRippleState->setFieldU64(sfHighNode, *highNode);
249 sleRippleState->setFieldAmount(bSetHigh ? sfHighLimit : sfLowLimit, saLimit);
250 sleRippleState->setFieldAmount(
251 bSetHigh ? sfLowLimit : sfHighLimit,
254 if (uQualityIn != 0u)
255 sleRippleState->setFieldU32(bSetHigh ? sfHighQualityIn : sfLowQualityIn, uQualityIn);
257 if (uQualityOut != 0u)
258 sleRippleState->setFieldU32(bSetHigh ? sfHighQualityOut : sfLowQualityOut, uQualityOut);
260 std::uint32_t uFlags = bSetHigh ? lsfHighReserve : lsfLowReserve;
264 uFlags |= (bSetHigh ? lsfHighAuth : lsfLowAuth);
268 uFlags |= (bSetHigh ? lsfHighNoRipple : lsfLowNoRipple);
272 uFlags |= (bSetHigh ? lsfHighFreeze : lsfLowFreeze);
276 uFlags |= (bSetHigh ? lsfHighDeepFreeze : lsfLowDeepFreeze);
279 if (!slePeer->isFlag(lsfDefaultRipple))
282 uFlags |= (bSetHigh ? lsfLowNoRipple : lsfHighNoRipple);
285 sleRippleState->setFieldU32(sfFlags, uFlags);
291 sleRippleState->setFieldAmount(sfBalance, bSetHigh ? -saBalance : saBalance);
307 std::uint64_t const uLowNode = sleRippleState->getFieldU64(sfLowNode);
308 std::uint64_t const uHighNode = sleRippleState->getFieldU64(sfHighNode);
310 JLOG(j.
trace()) <<
"trustDelete: Deleting ripple line: low";
317 JLOG(j.
trace()) <<
"trustDelete: Deleting ripple line: high";
327 JLOG(j.
trace()) <<
"trustDelete: Deleting ripple line: state";
328 view.
erase(sleRippleState);
356 auto const senderReserveFlag = bSenderHigh ? lsfHighReserve : lsfLowReserve;
357 auto const senderNoRippleFlag = bSenderHigh ? lsfHighNoRipple : lsfLowNoRipple;
358 auto const senderFreezeFlag = bSenderHigh ? lsfHighFreeze : lsfLowFreeze;
359 auto const receiverReserveFlag = bSenderHigh ? lsfLowReserve : lsfHighReserve;
366 && state->
isFlag(senderReserveFlag)
368 && state->
isFlag(senderNoRippleFlag) != sle->isFlag(lsfDefaultRipple) &&
369 !state->
isFlag(senderFreezeFlag) &&
372 && (state->
getFieldU32(!bSenderHigh ? sfLowQualityIn : sfHighQualityIn) == 0u)
374 && (state->
getFieldU32(!bSenderHigh ? sfLowQualityOut : sfHighQualityOut) == 0u))
379 auto const currentSponsor =
407 "xrpl::issueIOU : neither account nor issuer is XRP");
410 XRPL_ASSERT(issue == amount.
get<
Issue>(),
"xrpl::issueIOU : matching issue");
413 XRPL_ASSERT(issue.
account != account,
"xrpl::issueIOU : not issuer account");
417 bool const bSenderHigh = issue.
account > account;
421 if (
auto state = view.
peek(index))
423 STAmount finalBalance = state->getFieldAmount(sfBalance);
428 STAmount const startBalance = finalBalance;
430 finalBalance -= amount;
432 auto const mustDelete =
443 state->setFieldAmount(sfBalance, finalBalance);
449 bSenderHigh ? account : issue.
account,
450 bSenderHigh ? issue.
account : account,
468 if (!receiverAccount)
471 bool const noRipple = !receiverAccount->isFlag(lsfDefaultRipple);
502 "xrpl::redeemIOU : neither account nor issuer is XRP");
505 XRPL_ASSERT(issue == amount.
get<
Issue>(),
"xrpl::redeemIOU : matching issue");
508 XRPL_ASSERT(issue.
account != account,
"xrpl::redeemIOU : not issuer account");
512 bool const bSenderHigh = account > issue.
account;
516 STAmount finalBalance = state->getFieldAmount(sfBalance);
521 STAmount const startBalance = finalBalance;
523 finalBalance -= amount;
525 auto const mustDelete =
526 updateTrustLine(view, state, bSenderHigh, account, startBalance, finalBalance, j);
536 state->setFieldAmount(sfBalance, finalBalance);
543 bSenderHigh ? issue.
account : account,
544 bSenderHigh ? account : issue.
account,
556 JLOG(j.
fatal()) <<
"redeemIOU: " <<
to_string(account) <<
" attempts to "
557 <<
"redeem " << amount.
getFullText() <<
" but no trust line exists!";
583 issuerAccount && issuerAccount->isFlag(lsfRequireAuth))
587 return trustLine->isFlag((account > issue.
account) ? lsfLowAuth : lsfHighAuth)
603 auto const& issuerId = issue.
getIssuer();
604 if (issuerId == from || issuerId == to)
607 if (sleIssuer ==
nullptr)
610 auto const isRippleDisabled = [&](
AccountID account) ->
bool {
616 bool const issuerHigh = issuerId > account;
617 return line->isFlag(issuerHigh ? lsfHighNoRipple : lsfLowNoRipple);
619 return !sleIssuer->isFlag(lsfDefaultRipple);
623 if (isRippleDisabled(from) && isRippleDisabled(to))
647 auto const& issuerId = issue.
getIssuer();
648 auto const& currency = issue.
currency;
652 auto const& srcId = issuerId;
653 auto const& dstId = accountID;
654 auto const high = srcId > dstId;
658 if (!sleDst || !sleSrc)
660 if (!sleSrc->isFlag(lsfDefaultRipple))
669 return sponsorExp.error();
670 auto const sponsorSle = *sponsorExp;
678 {.ownerCountDelta = 1},
697 STAmount{Issue{currency, noAccount()}},
698 STAmount{Issue{currency, dstId}},
718 auto const balance = sle->getFieldAmount(sfBalance);
719 if (balance.xrp() != 0)
728 bool const accountIsIssuer = accountID == issue.
account;
732 if (!accountIsIssuer && line->at(sfBalance)->iou() !=
beast::kZero)
736 if (line->isFlag(lsfLowReserve))
749 line->clearFlag(lsfLowReserve);
753 if (line->isFlag(lsfHighReserve))
766 line->clearFlag(lsfHighReserve);
773 line->at(sfLowLimit)->getIssuer(),
774 line->at(sfHighLimit)->getIssuer(),
785 if (!sleState || sleState->getType() != ltRIPPLE_STATE)
789 sleState->getFieldAmount(sfLowLimit).getIssuer(),
790 sleState->getFieldAmount(sfHighLimit).getIssuer());
793 if (!sleLow || !sleHigh)
796 bool const ammLow = sleLow->isFieldPresent(sfAMMID);
797 bool const ammHigh = sleHigh->isFieldPresent(sfAMMID);
800 if (ammLow && ammHigh)
804 if (!ammLow && !ammHigh)
808 if (ammAccountID && (low != *ammAccountID && high != *ammAccountID))
811 auto const sponsorSle =
816 JLOG(j.
error()) <<
"deleteAMMTrustLine: failed to delete the trustline.";
820 auto const uFlags = !ammLow ? lsfLowReserve : lsfHighReserve;
821 if (!sleState->isFlag(uFlags))
837 keylet::ownerDir(ammAccountID), (*sleMpt)[sfOwnerNode], sleMpt->key(),
false))
A generic endpoint for log messages.
Stream trace() const
Severity stream access functions.
Writeable view to a ledger, for applying a transaction.
virtual SLE::pointer peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void insert(SLE::ref sle)=0
Insert a new state SLE.
bool dirRemove(Keylet const &directory, std::uint64_t page, uint256 const &key, bool keepRoot)
Remove an entry from a directory.
virtual void creditHookIOU(AccountID const &from, AccountID const &to, STAmount const &amount, STAmount const &preCreditBalance)
virtual void erase(SLE::ref sle)=0
Remove a peeked SLE.
std::optional< std::uint64_t > dirInsert(Keylet const &directory, uint256 const &key, std::function< void(SLE::ref)> const &describe)
Insert an entry to a directory.
virtual void update(SLE::ref sle)=0
Indicate changes to a peeked SLE.
A currency issued by an account.
AccountID const & getIssuer() const
virtual Rules const & rules() const =0
Returns the tx processing rules.
virtual SLE::const_pointer 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.
constexpr TIss const & get() const
std::string getFullText() const override
STAmount zeroed() const
Returns a zero value with the same issuer and currency.
AccountID const & getIssuer() const
std::shared_ptr< STLedgerEntry > const & ref
std::shared_ptr< STLedgerEntry > pointer
std::uint32_t getFieldU32(SField const &field) const
bool isFlag(std::uint32_t) const
bool clearFlag(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 account(AccountID const &id) noexcept
AccountID root.
Keylet trustLine(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
bool isXRP(AccountID const &c)
void increaseOwnerCount(ApplyView &view, SLE::ref accountSle, SLE::ref sponsorSle, std::uint32_t count, beast::Journal j)
Increase owner-count fields when the caller supplies the sponsor.
bool isIndividualFrozen(ReadView const &view, AccountID const &account, MPTIssue const &mptIssue)
Returns true if account's MPToken for mptIssue carries the individual-lock flag (lsfMPTLocked).
TER deleteAMMTrustLine(ApplyView &view, SLE::pointer sleState, std::optional< AccountID > const &ammAccountID, beast::Journal j)
Delete trustline to AMM.
TER removeEmptyHolding(ApplyViewContext ctx, AccountID const &accountID, MPTIssue const &mptIssue, beast::Journal journal)
TER deleteAMMMPToken(ApplyView &view, SLE::pointer sleMPT, AccountID const &ammAccountID, beast::Journal j)
Delete AMMs MPToken.
BaseUInt< 160, detail::CurrencyTag > Currency
Currency is a hash representing a specific currency.
TER addEmptyHolding(ApplyViewContext ctx, AccountID const &accountID, XRPAmount priorBalance, MPTIssue const &mptIssue, beast::Journal journal)
TER trustDelete(ApplyView &view, SLE::ref sleRippleState, AccountID const &uLowAccountID, AccountID const &uHighAccountID, beast::Journal j)
TER canTransfer(ReadView const &view, MPTIssue const &mptIssue, AccountID const &from, AccountID const &to, WaiveMPTCanTransfer waive=WaiveMPTCanTransfer::No, std::uint8_t depth=0)
Check whether to may receive the given MPT from from.
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.
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, SLE::ref sponsorSle, beast::Journal j)
Create a trust line.
bool isDeepFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
std::string to_string(BaseUInt< Bits, Tag > const &a)
std::expected< SLE::pointer, TER > getEffectiveTxReserveSponsor(ApplyViewContext ctx, SLE::const_ref accountSle)
The transaction's reserve sponsor for the given account, if applicable.
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.
void addSponsorToLedgerEntry(SLE::ref sle, SLE::const_ref sponsorSle, SF_ACCOUNT const &field=sfSponsor)
Stamp a reserve sponsor onto a ledger entry using an explicit sponsor SLE.
void removeSponsorFromLedgerEntry(SLE::ref sle, SF_ACCOUNT const &field=sfSponsor)
Remove the reserve sponsor field from a ledger entry.
void decreaseOwnerCount(ApplyView &view, SLE::ref accountSle, SLE::ref sponsorSle, std::uint32_t count, beast::Journal j)
Decrease owner-count fields when the caller supplies the sponsor.
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
TER issueIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, SLE::ref sponsorSle, beast::Journal j)
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.
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Returns a function that sets the owner on a directory SLE.
bool isFrozen(ReadView const &view, AccountID const &account, MPTIssue const &mptIssue, std::uint8_t depth=0)
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
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 checkReserve(ApplyViewContext ctx, SLE::const_ref accSle, XRPAmount accBalance, SLE::const_ref sponsorSle, Adjustment adj, beast::Journal j, TER insufReserveCode=tecINSUFFICIENT_RESERVE)
Check if an account has sufficient reserve.
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
TERSubset< CanCvtToTER > TER
TER requireAuth(ReadView const &view, MPTIssue const &mptIssue, AccountID const &account, AuthType authType=AuthType::Legacy, std::uint8_t depth=0)
Check if the account lacks required authorization for MPT.
@ tecNO_LINE_INSUF_RESERVE
SLE::pointer getLedgerEntryReserveSponsor(ApplyView &view, SLE::const_ref sle, SF_ACCOUNT const &field=sfSponsor)
Return a mutable SLE for the reserve sponsor recorded on a ledger entry.
Bundles the mutable ledger view and the transaction being applied.