fix issues

This commit is contained in:
Mayukha Vadari
2026-03-22 22:33:48 -07:00
parent 44c6c52319
commit 9659b9baff
6 changed files with 55 additions and 65 deletions

View File

@@ -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;

View File

@@ -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<IOUAmount>(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)

View File

@@ -1,7 +1,6 @@
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/TER.h>
@@ -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;
}
}
}
}

View File

@@ -3,7 +3,6 @@
#include <xrpl/ledger/OrderBookDB.h>
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/TER.h>
@@ -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)
{

View File

@@ -1,6 +1,6 @@
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Rate.h>
#include <xrpl/protocol/TxFlags.h>
@@ -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;
}

View File

@@ -3,7 +3,6 @@
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/STArray.h>
#include <xrpl/protocol/TxFlags.h>
@@ -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;
}