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/TokenHelpers.h>
13#include <xrpl/protocol/AccountID.h>
14#include <xrpl/protocol/AmountConversions.h>
15#include <xrpl/protocol/Feature.h>
16#include <xrpl/protocol/IOUAmount.h>
17#include <xrpl/protocol/Indexes.h>
18#include <xrpl/protocol/Issue.h>
19#include <xrpl/protocol/LedgerFormats.h>
20#include <xrpl/protocol/Rules.h>
21#include <xrpl/protocol/SField.h>
22#include <xrpl/protocol/STAmount.h>
23#include <xrpl/protocol/STLedgerEntry.h>
24#include <xrpl/protocol/TER.h>
25#include <xrpl/protocol/UintTypes.h>
26#include <xrpl/protocol/XRPAmount.h>
54 result = sleRippleState->getFieldAmount(account < issuer ? sfLowLimit : sfHighLimit);
55 result.get<
Issue>().account = account;
58 XRPL_ASSERT(result.getIssuer() == account,
"xrpl::creditLimit : result issuer match");
61 "xrpl::creditLimit : result currency "
85 result = sleRippleState->getFieldAmount(sfBalance);
88 result.get<
Issue>().account = account;
91 XRPL_ASSERT(result.getIssuer() == account,
"xrpl::creditBalance : result issuer match");
94 "xrpl::creditBalance : result currency "
114 if (issuer != account)
118 if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
136 if (sle && sle->isFlag(lsfGlobalFreeze))
138 if (issuer != account)
142 if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
160 if (issuer == account)
171 return sle->isFlag(lsfHighDeepFreeze) || sle->isFlag(lsfLowDeepFreeze);
189 bool const bNoRipple,
200 JLOG(j.
trace()) <<
"trustCreate: " <<
to_string(uSrcAccountID) <<
", "
203 auto const& uLowAccountID = !bSrcHigh ? uSrcAccountID : uDstAccountID;
204 auto const& uHighAccountID = bSrcHigh ? uSrcAccountID : uDstAccountID;
205 if (uLowAccountID == uHighAccountID)
208 UNREACHABLE(
"xrpl::trustCreate : trust line to self");
215 view.
insert(sleRippleState);
229 bool const bSetDst = saLimit.
getIssuer() == uDstAccountID;
230 bool const bSetHigh = bSrcHigh ^ bSetDst;
232 XRPL_ASSERT(sleAccount,
"xrpl::trustCreate : non-null SLE");
237 sleAccount->getAccountID(sfAccount) == (bSetHigh ? uHighAccountID : uLowAccountID),
238 "xrpl::trustCreate : matching account ID");
239 auto const slePeer = view.
peek(
keylet::account(bSetHigh ? uLowAccountID : uHighAccountID));
244 sleRippleState->setFieldU64(sfLowNode, *lowNode);
245 sleRippleState->setFieldU64(sfHighNode, *highNode);
247 sleRippleState->setFieldAmount(bSetHigh ? sfHighLimit : sfLowLimit, saLimit);
248 sleRippleState->setFieldAmount(
249 bSetHigh ? sfLowLimit : sfHighLimit,
252 if (uQualityIn != 0u)
253 sleRippleState->setFieldU32(bSetHigh ? sfHighQualityIn : sfLowQualityIn, uQualityIn);
255 if (uQualityOut != 0u)
256 sleRippleState->setFieldU32(bSetHigh ? sfHighQualityOut : sfLowQualityOut, uQualityOut);
258 std::uint32_t uFlags = bSetHigh ? lsfHighReserve : lsfLowReserve;
262 uFlags |= (bSetHigh ? lsfHighAuth : lsfLowAuth);
266 uFlags |= (bSetHigh ? lsfHighNoRipple : lsfLowNoRipple);
270 uFlags |= (bSetHigh ? lsfHighFreeze : lsfLowFreeze);
274 uFlags |= (bSetHigh ? lsfHighDeepFreeze : lsfLowDeepFreeze);
277 if (!slePeer->isFlag(lsfDefaultRipple))
280 uFlags |= (bSetHigh ? lsfLowNoRipple : lsfHighNoRipple);
283 sleRippleState->setFieldU32(sfFlags, uFlags);
287 sleRippleState->setFieldAmount(sfBalance, bSetHigh ? -saBalance : saBalance);
303 std::uint64_t const uLowNode = sleRippleState->getFieldU64(sfLowNode);
304 std::uint64_t const uHighNode = sleRippleState->getFieldU64(sfHighNode);
306 JLOG(j.
trace()) <<
"trustDelete: Deleting ripple line: low";
313 JLOG(j.
trace()) <<
"trustDelete: Deleting ripple line: high";
320 JLOG(j.
trace()) <<
"trustDelete: Deleting ripple line: state";
321 view.
erase(sleRippleState);
349 auto const senderReserveFlag = bSenderHigh ? lsfHighReserve : lsfLowReserve;
350 auto const senderNoRippleFlag = bSenderHigh ? lsfHighNoRipple : lsfLowNoRipple;
351 auto const senderFreezeFlag = bSenderHigh ? lsfHighFreeze : lsfLowFreeze;
352 auto const receiverReserveFlag = bSenderHigh ? lsfLowReserve : lsfHighReserve;
355 if (before > beast::kZero
357 &&
after <= beast::kZero
359 && state->
isFlag(senderReserveFlag)
361 && state->
isFlag(senderNoRippleFlag) != sle->isFlag(lsfDefaultRipple) &&
362 !state->
isFlag(senderFreezeFlag) &&
365 && (state->
getFieldU32(!bSenderHigh ? sfLowQualityIn : sfHighQualityIn) == 0u)
367 && (state->
getFieldU32(!bSenderHigh ? sfLowQualityOut : sfHighQualityOut) == 0u))
394 "xrpl::issueIOU : neither account nor issuer is XRP");
397 XRPL_ASSERT(issue == amount.
get<
Issue>(),
"xrpl::issueIOU : matching issue");
400 XRPL_ASSERT(issue.
account != account,
"xrpl::issueIOU : not issuer account");
404 bool const bSenderHigh = issue.
account > account;
408 if (
auto state = view.
peek(index))
410 STAmount finalBalance = state->getFieldAmount(sfBalance);
415 STAmount const startBalance = finalBalance;
417 finalBalance -= amount;
419 auto const mustDelete =
430 state->setFieldAmount(sfBalance, finalBalance);
436 bSenderHigh ? account : issue.
account,
437 bSenderHigh ? issue.
account : account,
455 if (!receiverAccount)
458 bool const noRipple = !receiverAccount->isFlag(lsfDefaultRipple);
488 "xrpl::redeemIOU : neither account nor issuer is XRP");
491 XRPL_ASSERT(issue == amount.
get<
Issue>(),
"xrpl::redeemIOU : matching issue");
494 XRPL_ASSERT(issue.
account != account,
"xrpl::redeemIOU : not issuer account");
498 bool const bSenderHigh = account > issue.
account;
502 STAmount finalBalance = state->getFieldAmount(sfBalance);
507 STAmount const startBalance = finalBalance;
509 finalBalance -= amount;
511 auto const mustDelete =
512 updateTrustLine(view, state, bSenderHigh, account, startBalance, finalBalance, j);
522 state->setFieldAmount(sfBalance, finalBalance);
529 bSenderHigh ? issue.
account : account,
530 bSenderHigh ? account : issue.
account,
542 JLOG(j.
fatal()) <<
"redeemIOU: " <<
to_string(account) <<
" attempts to "
543 <<
"redeem " << amount.
getFullText() <<
" but no trust line exists!";
569 issuerAccount && issuerAccount->isFlag(lsfRequireAuth))
573 return trustLine->isFlag((account > issue.
account) ? lsfLowAuth : lsfHighAuth)
589 auto const& issuerId = issue.
getIssuer();
590 if (issuerId == from || issuerId == to)
593 if (sleIssuer ==
nullptr)
596 auto const isRippleDisabled = [&](
AccountID account) ->
bool {
602 bool const issuerHigh = issuerId > account;
603 return line->isFlag(issuerHigh ? lsfHighNoRipple : lsfLowNoRipple);
605 return !sleIssuer->isFlag(lsfDefaultRipple);
609 if (isRippleDisabled(from) && isRippleDisabled(to))
633 auto const& issuerId = issue.
getIssuer();
634 auto const& currency = issue.
currency;
638 auto const& srcId = issuerId;
639 auto const& dstId = accountID;
640 auto const high = srcId > dstId;
644 if (!sleDst || !sleSrc)
646 if (!sleSrc->isFlag(lsfDefaultRipple))
649 if (view.
read(index))
668 STAmount{Issue{currency, noAccount()}},
669 STAmount{Issue{currency, dstId}},
688 auto const balance = sle->getFieldAmount(sfBalance);
689 if (balance.xrp() != 0)
698 bool const accountIsIssuer = accountID == issue.
account;
702 if (!accountIsIssuer && line->at(sfBalance)->iou() != beast::kZero)
706 if (line->isFlag(lsfLowReserve))
717 line->clearFlag(lsfLowReserve);
720 if (line->isFlag(lsfHighReserve))
731 line->clearFlag(lsfHighReserve);
735 view, line, line->at(sfLowLimit)->getIssuer(), line->at(sfHighLimit)->getIssuer(), journal);
745 if (!sleState || sleState->getType() != ltRIPPLE_STATE)
749 sleState->getFieldAmount(sfLowLimit).getIssuer(),
750 sleState->getFieldAmount(sfHighLimit).getIssuer());
753 if (!sleLow || !sleHigh)
756 bool const ammLow = sleLow->isFieldPresent(sfAMMID);
757 bool const ammHigh = sleHigh->isFieldPresent(sfAMMID);
760 if (ammLow && ammHigh)
764 if (!ammLow && !ammHigh)
768 if (ammAccountID && (low != *ammAccountID && high != *ammAccountID))
773 JLOG(j.
error()) <<
"deleteAMMTrustLine: failed to delete the trustline.";
777 auto const uFlags = !ammLow ? lsfLowReserve : lsfHighReserve;
778 if (!sleState->isFlag(uFlags))
794 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 Fees const & fees() const =0
Returns the fees for the base ledger.
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)
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)
TER deleteAMMTrustLine(ApplyView &view, SLE::pointer sleState, std::optional< AccountID > const &ammAccountID, beast::Journal j)
Delete trustline to AMM.
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 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 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.
bool isDeepFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
std::string to_string(BaseUInt< Bits, Tag > const &a)
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 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.
void adjustOwnerCount(ApplyView &view, SLE::ref sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
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 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
TER removeEmptyHolding(ApplyView &view, AccountID const &accountID, MPTIssue const &mptIssue, beast::Journal journal)
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.