20#include <xrpld/app/tx/detail/NFTokenAcceptOffer.h>
21#include <xrpld/app/tx/detail/NFTokenUtils.h>
22#include <xrpld/ledger/View.h>
23#include <xrpl/protocol/Feature.h>
24#include <xrpl/protocol/Rate.h>
25#include <xrpl/protocol/TxFlags.h>
26#include <xrpl/protocol/st.h>
42 auto const bo = ctx.
tx[~sfNFTokenBuyOffer];
43 auto const so = ctx.
tx[~sfNFTokenSellOffer];
51 if (
auto const bf = ctx.
tx[~sfNFTokenBrokerFee])
56 if (*bf <= beast::zero)
83 if ((*offerSLE)[sfAmount].negative() &&
92 auto const [bo, err1] = checkOffer(ctx.
tx[~sfNFTokenBuyOffer]);
95 auto const [so, err2] = checkOffer(ctx.
tx[~sfNFTokenSellOffer]);
103 if ((*bo)[sfNFTokenID] != (*so)[sfNFTokenID])
107 if ((*bo)[sfAmount].issue() != (*so)[sfAmount].issue())
113 ((*bo)[sfOwner] == (*so)[sfOwner]))
118 if ((*so)[sfAmount] > (*bo)[sfAmount])
122 if (
auto const dest = bo->at(~sfDestination))
128 if (*dest != ctx.
tx[sfAccount])
131 else if (*dest != so->at(sfOwner) && *dest != ctx.
tx[sfAccount])
136 if (
auto const dest = so->at(~sfDestination))
142 if (*dest != ctx.
tx[sfAccount])
145 else if (*dest != bo->at(sfOwner) && *dest != ctx.
tx[sfAccount])
153 if (
auto const brokerFee = ctx.
tx[~sfNFTokenBrokerFee])
155 if (brokerFee->issue() != (*bo)[sfAmount].issue())
158 if (brokerFee >= (*bo)[sfAmount])
161 if ((*so)[sfAmount] > (*bo)[sfAmount] - *brokerFee)
172 if ((*bo)[sfOwner] == ctx.
tx[sfAccount])
185 if (
auto const dest = bo->at(~sfDestination);
186 dest.has_value() && *dest != ctx.
tx[sfAccount])
194 auto const needed = bo->at(sfAmount);
206 needed.getCurrency(),
219 if ((*so)[sfOwner] == ctx.
tx[sfAccount])
231 if (
auto const dest = so->at(~sfDestination);
232 dest.has_value() && *dest != ctx.
tx[sfAccount])
237 auto const needed = so->at(sfAmount);
243 needed.getCurrency(),
274 if (!needed.native())
281 needed.asset().get<
Issue>());
296 uint256 const& tokenID = offer->at(sfNFTokenID);
297 STAmount const& amount = offer->at(sfAmount);
319 if (amount < beast::zero)
329 if (!
view().rules().enabled(fixNonFungibleTokensV1_2))
352 view(), seller, nftokenID, std::move(tokenAndPage->page));
361 sleBuyer->getFieldU32(sfOwnerCount);
363 auto const insertRet =
372 if (
view().rules().enabled(fixNFTokenReserve))
379 auto const buyerBalance = sleBuyer->getFieldAmount(sfBalance);
381 auto const buyerOwnerCountAfter = sleBuyer->getFieldU32(sfOwnerCount);
382 if (buyerOwnerCountAfter > buyerOwnerCountBefore)
384 if (
auto const reserve =
385 view().fees().accountReserve(buyerOwnerCountAfter);
386 buyerBalance < reserve)
398 AccountID const owner = (*offer)[sfOwner];
402 auto const nftokenID = (*offer)[sfNFTokenID];
404 if (
auto amount = offer->getFieldAmount(sfAmount); amount != beast::zero)
412 cut != beast::zero && seller != issuer && buyer != issuer)
439 auto bo = loadToken(
ctx_.
tx[~sfNFTokenBuyOffer]);
440 auto so = loadToken(
ctx_.
tx[~sfNFTokenSellOffer]);
444 JLOG(
j_.
fatal()) <<
"Unable to delete buy offer '"
445 <<
to_string(bo->key()) <<
"': ignoring";
451 JLOG(
j_.
fatal()) <<
"Unable to delete sell offer '"
452 <<
to_string(so->key()) <<
"': ignoring";
462 auto const nftokenID = (*so)[sfNFTokenID];
481 if (
auto const cut =
ctx_.
tx[~sfNFTokenBrokerFee];
482 cut && cut.value() != beast::zero)
484 if (
auto const r =
pay(buyer,
account_, cut.value());
488 amount -= cut.
value();
493 amount != beast::zero && fee != 0)
498 seller != issuer && buyer != issuer)
508 if (amount > beast::zero)
544 "NFTokenAcceptOffer::checkAcceptAsset : valid to check.");
550 <<
"delay: can't receive IOUs from non-existent issuer: "
564 auto const trustLine =
574 bool const deepFrozen =
A generic endpoint for log messages.
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
A currency issued by an account.
TER acceptOffer(std::shared_ptr< SLE > const &offer)
static TER preclaim(PreclaimContext const &ctx)
TER pay(AccountID const &from, AccountID const &to, STAmount const &amount)
TER transferNFToken(AccountID const &buyer, AccountID const &seller, uint256 const &nfTokenID)
static TER checkAcceptAsset(ReadView const &view, ApplyFlags const flags, AccountID const id, beast::Journal const j, Issue const &issue)
static NotTEC preflight(PreflightContext const &ctx)
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
virtual Rules const & rules() const =0
Returns the tx processing rules.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
STAmount const & value() const noexcept
AccountID const & getIssuer() const
Issue const & issue() const
bool native() const noexcept
std::uint32_t getFlags() const
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.
Keylet nftoffer(AccountID const &owner, std::uint32_t seq)
An offer from an account to buy or sell an NFT.
std::uint16_t getTransferFee(uint256 const &id)
std::uint16_t getFlags(uint256 const &id)
TER removeToken(ApplyView &view, AccountID const &owner, uint256 const &nftokenID)
Remove the token from the owner's token directory.
AccountID getIssuer(uint256 const &id)
bool deleteTokenOffer(ApplyView &view, std::shared_ptr< SLE > const &offer)
Deletes the given token offer.
std::optional< TokenAndPage > findTokenAndPage(ApplyView &view, AccountID const &owner, uint256 const &nftokenID)
TER insertToken(ApplyView &view, AccountID owner, STObject &&nft)
Insert the token in the owner's token directory.
std::optional< STObject > findToken(ReadView const &view, AccountID const &owner, uint256 const &nftokenID)
Finds the specified token in the owner's token directory.
constexpr std::uint16_t const flagCreateTrustLines
Rate transferFeeAsRate(std::uint16_t fee)
Given a transfer fee (in basis points) convert it to a transfer rate.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
bool isXRP(AccountID const &c)
STAmount multiply(STAmount const &amount, Rate const &rate)
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
@ tecNFTOKEN_OFFER_TYPE_MISMATCH
@ tecNFTOKEN_BUY_SELL_MISMATCH
@ tecINSUFFICIENT_PAYMENT
@ tecINSUFFICIENT_RESERVE
@ tecCANT_ACCEPT_OWN_NFTOKEN_OFFER
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
std::string to_string(base_uint< Bits, Tag > const &a)
bool hasExpired(ReadView const &view, std::optional< std::uint32_t > const &exp)
Determines whether the given expiration time has passed.
constexpr std::uint32_t const tfNFTokenAcceptOfferMask
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
Calls static accountSendIOU if saAmount represents Issue.
TERSubset< CanCvtToNotTEC > NotTEC
State information when determining if a tx is likely to claim a fee.
State information when preflighting a tx.