From 9659b9baffe68ea936868df644854a05a22fe6bb Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Sun, 22 Mar 2026 22:33:48 -0700 Subject: [PATCH] fix issues --- .../xrpl/ledger/helpers/RippleStateHelpers.h | 13 ++++++++ src/libxrpl/tx/paths/OfferStream.cpp | 9 +++--- .../tx/transactors/check/CheckCreate.cpp | 26 +++++++++++---- .../tx/transactors/dex/OfferCreate.cpp | 29 +++++------------ .../tx/transactors/nft/NFTokenAcceptOffer.cpp | 32 +++++-------------- .../tx/transactors/nft/NFTokenUtils.cpp | 11 ++----- 6 files changed, 55 insertions(+), 65 deletions(-) diff --git a/include/xrpl/ledger/helpers/RippleStateHelpers.h b/include/xrpl/ledger/helpers/RippleStateHelpers.h index 753860beac..a6a545efa7 100644 --- a/include/xrpl/ledger/helpers/RippleStateHelpers.h +++ b/include/xrpl/ledger/helpers/RippleStateHelpers.h @@ -91,6 +91,19 @@ public: beast::Journal j, SpendableHandling includeFullBalance = shSIMPLE_BALANCE) const override; + /** Returns the funds available for account to pay for an amount. + * + * If the account is the issuer of the currency, it can always + * afford to pay (returns saDefault as-is). Otherwise, returns + * the result of accountHolds. + */ + [[nodiscard]] STAmount + accountFunds( + AccountID const& id, + STAmount const& saDefault, + FreezeHandling freezeHandling, + beast::Journal j) const; + [[nodiscard]] TER canAddHolding() const override; diff --git a/src/libxrpl/tx/paths/OfferStream.cpp b/src/libxrpl/tx/paths/OfferStream.cpp index cb6cf1565f..80ee35df28 100644 --- a/src/libxrpl/tx/paths/OfferStream.cpp +++ b/src/libxrpl/tx/paths/OfferStream.cpp @@ -79,13 +79,11 @@ accountFundsHelper( ReadView const& view, AccountID const& id, STAmount const& saDefault, - Issue const& issue, + Issue const&, FreezeHandling freezeHandling, beast::Journal j) { - if (!saDefault.native() && saDefault.getIssuer() == id) - return saDefault; - return IOUToken(view, issue).accountHolds(id, freezeHandling, j); + return IOUToken(view, saDefault.issue()).accountFunds(id, saDefault, freezeHandling, j); } static IOUAmount @@ -102,6 +100,7 @@ accountFundsHelper( // self funded return amtDefault; } + return toAmount(IOUToken(view, issue).accountHolds(id, freezeHandling, j)); } @@ -109,7 +108,7 @@ static XRPAmount accountFundsHelper( ReadView const& view, AccountID const& id, - XRPAmount const& amtDefault, + XRPAmount const&, Issue const& issue, FreezeHandling freezeHandling, beast::Journal j) diff --git a/src/libxrpl/tx/transactors/check/CheckCreate.cpp b/src/libxrpl/tx/transactors/check/CheckCreate.cpp index 79c5858674..926fcab722 100644 --- a/src/libxrpl/tx/transactors/check/CheckCreate.cpp +++ b/src/libxrpl/tx/transactors/check/CheckCreate.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -85,6 +84,7 @@ CheckCreate::preclaim(PreclaimContext const& ctx) if (!sendMax.native()) { IOUToken const iouToken(ctx.view, sendMax.issue()); + auto const issuerId = iouToken.getIssuer(); // The currency may not be globally frozen if (iouToken.isGlobalFrozen()) @@ -98,15 +98,27 @@ CheckCreate::preclaim(PreclaimContext const& ctx) // Note that we DO allow create check for a currency that the // account does not yet have a trustline to. AccountID const srcId{ctx.tx.getAccountID(sfAccount)}; - if (iouToken.isFrozen(srcId)) + if (issuerId != srcId) { - JLOG(ctx.j.warn()) << "Creating a check for frozen trustline."; - return tecFROZEN; + // Check if the issuer froze the line + auto const sleTrust = + ctx.view.read(keylet::line(srcId, issuerId, sendMax.getCurrency())); + if (sleTrust && sleTrust->isFlag((issuerId > srcId) ? lsfHighFreeze : lsfLowFreeze)) + { + JLOG(ctx.j.warn()) << "Creating a check for frozen trustline."; + return tecFROZEN; + } } - if (iouToken.isFrozen(dstId)) + if (issuerId != dstId) { - JLOG(ctx.j.warn()) << "Creating a check for destination frozen trustline."; - return tecFROZEN; + // Check if dst froze the line. + auto const sleTrust = + ctx.view.read(keylet::line(issuerId, dstId, sendMax.getCurrency())); + if (sleTrust && sleTrust->isFlag((dstId > issuerId) ? lsfHighFreeze : lsfLowFreeze)) + { + JLOG(ctx.j.warn()) << "Creating a check for destination frozen trustline."; + return tecFROZEN; + } } } } diff --git a/src/libxrpl/tx/transactors/dex/OfferCreate.cpp b/src/libxrpl/tx/transactors/dex/OfferCreate.cpp index 4b85fc52eb..895609e2a1 100644 --- a/src/libxrpl/tx/transactors/dex/OfferCreate.cpp +++ b/src/libxrpl/tx/transactors/dex/OfferCreate.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -155,14 +154,8 @@ OfferCreate::preclaim(PreclaimContext const& ctx) return tecFROZEN; } - // Check account funds: issuer can always afford their own currency - auto const funds = [&]() -> STAmount { - if (!saTakerGets.native() && saTakerGets.getIssuer() == id) - return saTakerGets; - return makeTokenBase(ctx.view, saTakerGets.asset()) - ->accountHolds(id, fhZERO_IF_FROZEN, viewJ); - }(); - if (funds <= beast::zero) + if (IOUToken(ctx.view, saTakerGets.issue()) + .accountFunds(id, saTakerGets, fhZERO_IF_FROZEN, viewJ) <= beast::zero) { JLOG(ctx.j.debug()) << "delay: Offers must be at least partially funded."; return tecUNFUNDED_OFFER; @@ -289,12 +282,9 @@ OfferCreate::flowCross( // We check this in preclaim, but when selling XRP charged fees can // cause a user's available balance to go to 0 (by causing it to dip // below the reserve) so we check this case again. - STAmount const inStartBalance = [&]() -> STAmount { - if (!takerAmount.in.native() && takerAmount.in.getIssuer() == accountID_) - return takerAmount.in; - return makeTokenBase(psb, takerAmount.in.asset()) - ->accountHolds(accountID_, fhZERO_IF_FROZEN, j_); - }(); + STAmount const inStartBalance = + IOUToken(psb, takerAmount.in.issue()) + .accountFunds(accountID_, takerAmount.in, fhZERO_IF_FROZEN, j_); if (inStartBalance <= beast::zero) { // The account balance can't cover even part of the offer. @@ -396,12 +386,9 @@ OfferCreate::flowCross( auto afterCross = takerAmount; // If !tesSUCCESS offer unchanged if (isTesSuccess(result.result())) { - STAmount const takerInBalance = [&]() -> STAmount { - if (!takerAmount.in.native() && takerAmount.in.getIssuer() == accountID_) - return takerAmount.in; - return makeTokenBase(psb, takerAmount.in.asset()) - ->accountHolds(accountID_, fhZERO_IF_FROZEN, j_); - }(); + STAmount const takerInBalance = + IOUToken(psb, takerAmount.in.issue()) + .accountFunds(accountID_, takerAmount.in, fhZERO_IF_FROZEN, j_); if (takerInBalance <= beast::zero) { diff --git a/src/libxrpl/tx/transactors/nft/NFTokenAcceptOffer.cpp b/src/libxrpl/tx/transactors/nft/NFTokenAcceptOffer.cpp index 757b0c0b94..ce0084a05a 100644 --- a/src/libxrpl/tx/transactors/nft/NFTokenAcceptOffer.cpp +++ b/src/libxrpl/tx/transactors/nft/NFTokenAcceptOffer.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include @@ -171,14 +171,8 @@ NFTokenAcceptOffer::preclaim(PreclaimContext const& ctx) // own currency auto const needed = bo->at(sfAmount); - auto const funds = [&]() -> STAmount { - auto const owner = (*bo)[sfOwner]; - if (!needed.native() && needed.getIssuer() == owner) - return needed; - return makeTokenBase(ctx.view, needed.asset()) - ->accountHolds(owner, fhZERO_IF_FROZEN, ctx.j); - }(); - if (funds < needed) + if (IOUToken(ctx.view, needed.issue()) + .accountFunds((*bo)[sfOwner], needed, fhZERO_IF_FROZEN, ctx.j) < needed) return tecINSUFFICIENT_FUNDS; // Check that the account accepting the buy offer (he's selling the NFT) @@ -246,14 +240,8 @@ NFTokenAcceptOffer::preclaim(PreclaimContext const& ctx) // mode, because then we are confirming that the broker can // cover what the buyer will pay, which doesn't make sense, causes // an unnecessary tec, and is also resolved with this amendment. - auto const funds = [&]() -> STAmount { - auto const account = ctx.tx[sfAccount]; - if (!needed.native() && needed.getIssuer() == account) - return needed; - return makeTokenBase(ctx.view, needed.asset()) - ->accountHolds(account, fhZERO_IF_FROZEN, ctx.j); - }(); - if (funds < needed) + if (IOUToken(ctx.view, needed.issue()) + .accountFunds(ctx.tx[sfAccount], needed, fhZERO_IF_FROZEN, ctx.j) < needed) return tecINSUFFICIENT_FUNDS; } @@ -341,14 +329,10 @@ NFTokenAcceptOffer::pay(AccountID const& from, AccountID const& to, STAmount con // just confirm that the end state is OK. if (!isTesSuccess(result)) return result; - auto const checkFunds = [&](AccountID const& account) -> STAmount { - if (!amount.native() && amount.getIssuer() == account) - return amount; - return makeTokenBase(view(), amount.asset())->accountHolds(account, fhZERO_IF_FROZEN, j_); - }; - if (checkFunds(from).signum() < 0) + IOUToken const token(view(), amount.issue()); + if (token.accountFunds(from, amount, fhZERO_IF_FROZEN, j_).signum() < 0) return tecINSUFFICIENT_FUNDS; - if (checkFunds(to).signum() < 0) + if (token.accountFunds(to, amount, fhZERO_IF_FROZEN, j_).signum() < 0) return tecINSUFFICIENT_FUNDS; return tesSUCCESS; } diff --git a/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp b/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp index 3007c76e5d..75d7d8dd8c 100644 --- a/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp +++ b/src/libxrpl/tx/transactors/nft/NFTokenUtils.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -873,13 +872,9 @@ tokenOfferCreatePreclaim( { // We allow an IOU issuer to make a buy offer // using their own currency. - auto const funds = [&]() -> STAmount { - if (!amount.native() && amount.getIssuer() == acctID) - return amount; - return makeTokenBase(view, amount.asset()) - ->accountHolds(acctID, FreezeHandling::fhZERO_IF_FROZEN, j); - }(); - if (funds.signum() <= 0) + if (IOUToken(view, amount.issue()) + .accountFunds(acctID, amount, FreezeHandling::fhZERO_IF_FROZEN, j) + .signum() <= 0) return tecUNFUNDED_OFFER; }