rippled
NFTokenAcceptOffer.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2021 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/tx/impl/NFTokenAcceptOffer.h>
21 #include <ripple/app/tx/impl/details/NFTokenUtils.h>
22 #include <ripple/ledger/View.h>
23 #include <ripple/protocol/Feature.h>
24 #include <ripple/protocol/Rate.h>
25 #include <ripple/protocol/TxFlags.h>
26 #include <ripple/protocol/st.h>
27 
28 namespace ripple {
29 
30 NotTEC
32 {
34  return temDISABLED;
35 
36  if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
37  return ret;
38 
40  return temINVALID_FLAG;
41 
42  auto const bo = ctx.tx[~sfNFTokenBuyOffer];
43  auto const so = ctx.tx[~sfNFTokenSellOffer];
44 
45  // At least one of these MUST be specified
46  if (!bo && !so)
47  return temMALFORMED;
48 
49  // The `BrokerFee` field must not be present in direct mode but may be
50  // present and greater than zero in brokered mode.
51  if (auto const bf = ctx.tx[~sfNFTokenBrokerFee])
52  {
53  if (!bo || !so)
54  return temMALFORMED;
55 
56  if (*bf <= beast::zero)
57  return temMALFORMED;
58  }
59 
60  return preflight2(ctx);
61 }
62 
63 TER
65 {
66  auto const checkOffer = [&ctx](std::optional<uint256> id)
68  if (id)
69  {
70  if (id->isZero())
71  return {nullptr, tecOBJECT_NOT_FOUND};
72 
73  auto offerSLE = ctx.view.read(keylet::nftoffer(*id));
74 
75  if (!offerSLE)
76  return {nullptr, tecOBJECT_NOT_FOUND};
77 
78  if (hasExpired(ctx.view, (*offerSLE)[~sfExpiration]))
79  return {nullptr, tecEXPIRED};
80 
81  // The initial implementation had a bug that allowed a negative
82  // amount. The fixNFTokenNegOffer amendment fixes that.
83  if ((*offerSLE)[sfAmount].negative() &&
85  return {nullptr, temBAD_OFFER};
86 
87  return {std::move(offerSLE), tesSUCCESS};
88  }
89  return {nullptr, tesSUCCESS};
90  };
91 
92  auto const [bo, err1] = checkOffer(ctx.tx[~sfNFTokenBuyOffer]);
93  if (!isTesSuccess(err1))
94  return err1;
95  auto const [so, err2] = checkOffer(ctx.tx[~sfNFTokenSellOffer]);
96  if (!isTesSuccess(err2))
97  return err2;
98 
99  if (bo && so)
100  {
101  // Brokered mode:
102  // The two offers being brokered must be for the same token:
103  if ((*bo)[sfNFTokenID] != (*so)[sfNFTokenID])
105 
106  // The two offers being brokered must be for the same asset:
107  if ((*bo)[sfAmount].issue() != (*so)[sfAmount].issue())
109 
110  // The two offers may not form a loop. A broker may not sell the
111  // token to the current owner of the token.
113  ((*bo)[sfOwner] == (*so)[sfOwner]))
115 
116  // Ensure that the buyer is willing to pay at least as much as the
117  // seller is requesting:
118  if ((*so)[sfAmount] > (*bo)[sfAmount])
120 
121  // If the buyer specified a destination
122  if (auto const dest = bo->at(~sfDestination))
123  {
124  // Before this fix the destination could be either the seller or
125  // a broker. After, it must be whoever is submitting the tx.
127  {
128  if (*dest != ctx.tx[sfAccount])
129  return tecNO_PERMISSION;
130  }
131  else if (*dest != so->at(sfOwner) && *dest != ctx.tx[sfAccount])
133  }
134 
135  // If the seller specified a destination
136  if (auto const dest = so->at(~sfDestination))
137  {
138  // Before this fix the destination could be either the seller or
139  // a broker. After, it must be whoever is submitting the tx.
141  {
142  if (*dest != ctx.tx[sfAccount])
143  return tecNO_PERMISSION;
144  }
145  else if (*dest != bo->at(sfOwner) && *dest != ctx.tx[sfAccount])
147  }
148 
149  // The broker can specify an amount that represents their cut; if they
150  // have, ensure that the seller will get at least as much as they want
151  // to get *after* this fee is accounted for (but before the issuer's
152  // cut, if any).
153  if (auto const brokerFee = ctx.tx[~sfNFTokenBrokerFee])
154  {
155  if (brokerFee->issue() != (*bo)[sfAmount].issue())
157 
158  if (brokerFee >= (*bo)[sfAmount])
160 
161  if ((*so)[sfAmount] > (*bo)[sfAmount] - *brokerFee)
163  }
164  }
165 
166  if (bo)
167  {
168  if (((*bo)[sfFlags] & lsfSellNFToken) == lsfSellNFToken)
170 
171  // An account can't accept an offer it placed:
172  if ((*bo)[sfOwner] == ctx.tx[sfAccount])
174 
175  // If not in bridged mode, the account must own the token:
176  if (!so &&
177  !nft::findToken(ctx.view, ctx.tx[sfAccount], (*bo)[sfNFTokenID]))
178  return tecNO_PERMISSION;
179 
180  // If not in bridged mode...
181  if (!so)
182  {
183  // If the offer has a Destination field, the acceptor must be the
184  // Destination.
185  if (auto const dest = bo->at(~sfDestination);
186  dest.has_value() && *dest != ctx.tx[sfAccount])
187  return tecNO_PERMISSION;
188  }
189 
190  // The account offering to buy must have funds:
191  //
192  // After this amendment, we allow an IOU issuer to buy an NFT with their
193  // own currency
194  auto const needed = bo->at(sfAmount);
196  {
197  if (accountFunds(
198  ctx.view, (*bo)[sfOwner], needed, fhZERO_IF_FROZEN, ctx.j) <
199  needed)
200  return tecINSUFFICIENT_FUNDS;
201  }
202  else if (
203  accountHolds(
204  ctx.view,
205  (*bo)[sfOwner],
206  needed.getCurrency(),
207  needed.getIssuer(),
209  ctx.j) < needed)
210  return tecINSUFFICIENT_FUNDS;
211  }
212 
213  if (so)
214  {
215  if (((*so)[sfFlags] & lsfSellNFToken) != lsfSellNFToken)
217 
218  // An account can't accept an offer it placed:
219  if ((*so)[sfOwner] == ctx.tx[sfAccount])
221 
222  // The seller must own the token.
223  if (!nft::findToken(ctx.view, (*so)[sfOwner], (*so)[sfNFTokenID]))
224  return tecNO_PERMISSION;
225 
226  // If not in bridged mode...
227  if (!bo)
228  {
229  // If the offer has a Destination field, the acceptor must be the
230  // Destination.
231  if (auto const dest = so->at(~sfDestination);
232  dest.has_value() && *dest != ctx.tx[sfAccount])
233  return tecNO_PERMISSION;
234  }
235 
236  // The account offering to buy must have funds:
237  auto const needed = so->at(sfAmount);
239  {
240  if (accountHolds(
241  ctx.view,
242  ctx.tx[sfAccount],
243  needed.getCurrency(),
244  needed.getIssuer(),
246  ctx.j) < needed)
247  return tecINSUFFICIENT_FUNDS;
248  }
249  else if (!bo)
250  {
251  // After this amendment, we allow buyers to buy with their own
252  // issued currency.
253  //
254  // In the case of brokered mode, this check is essentially
255  // redundant, since we have already confirmed that buy offer is >
256  // than the sell offer, and that the buyer can cover the buy
257  // offer.
258  //
259  // We also _must not_ check the tx submitter in brokered
260  // mode, because then we are confirming that the broker can
261  // cover what the buyer will pay, which doesn't make sense, causes
262  // an unncessary tec, and is also resolved with this amendment.
263  if (accountFunds(
264  ctx.view,
265  ctx.tx[sfAccount],
266  needed,
268  ctx.j) < needed)
269  return tecINSUFFICIENT_FUNDS;
270  }
271  }
272 
273  return tesSUCCESS;
274 }
275 
276 TER
278  AccountID const& from,
279  AccountID const& to,
280  STAmount const& amount)
281 {
282  // This should never happen, but it's easy and quick to check.
283  if (amount < beast::zero)
284  return tecINTERNAL;
285 
286  auto const result = accountSend(view(), from, to, amount, j_);
287 
288  // After this amendment, if any payment would cause a non-IOU-issuer to
289  // have a negative balance, or an IOU-issuer to have a positive balance in
290  // their own currency, we know that something went wrong. This was
291  // originally found in the context of IOU transfer fees. Since there are
292  // several payouts in this tx, just confirm that the end state is OK.
293  if (!view().rules().enabled(fixNonFungibleTokensV1_2))
294  return result;
295  if (result != tesSUCCESS)
296  return result;
297  if (accountFunds(view(), from, amount, fhZERO_IF_FROZEN, j_).signum() < 0)
298  return tecINSUFFICIENT_FUNDS;
299  if (accountFunds(view(), to, amount, fhZERO_IF_FROZEN, j_).signum() < 0)
300  return tecINSUFFICIENT_FUNDS;
301  return tesSUCCESS;
302 }
303 
304 TER
306  AccountID const& buyer,
307  AccountID const& seller,
308  uint256 const& nftokenID)
309 {
310  auto tokenAndPage = nft::findTokenAndPage(view(), seller, nftokenID);
311 
312  if (!tokenAndPage)
313  return tecINTERNAL;
314 
315  if (auto const ret = nft::removeToken(
316  view(), seller, nftokenID, std::move(tokenAndPage->page));
317  !isTesSuccess(ret))
318  return ret;
319 
320  auto const sleBuyer = view().read(keylet::account(buyer));
321  if (!sleBuyer)
322  return tecINTERNAL;
323 
324  std::uint32_t const buyerOwnerCountBefore =
325  sleBuyer->getFieldU32(sfOwnerCount);
326 
327  auto const insertRet =
328  nft::insertToken(view(), buyer, std::move(tokenAndPage->token));
329 
330  // if fixNFTokenReserve is enabled, check if the buyer has sufficient
331  // reserve to own a new object, if their OwnerCount changed.
332  //
333  // There was an issue where the buyer accepts a sell offer, the ledger
334  // didn't check if the buyer has enough reserve, meaning that buyer can get
335  // NFTs free of reserve.
336  if (view().rules().enabled(fixNFTokenReserve))
337  {
338  // To check if there is sufficient reserve, we cannot use mPriorBalance
339  // because NFT is sold for a price. So we must use the balance after
340  // the deduction of the potential offer price. A small caveat here is
341  // that the balance has already deducted the transaction fee, meaning
342  // that the reserve requirement is a few drops higher.
343  auto const buyerBalance = sleBuyer->getFieldAmount(sfBalance);
344 
345  auto const buyerOwnerCountAfter = sleBuyer->getFieldU32(sfOwnerCount);
346  if (buyerOwnerCountAfter > buyerOwnerCountBefore)
347  {
348  if (auto const reserve =
349  view().fees().accountReserve(buyerOwnerCountAfter);
350  buyerBalance < reserve)
352  }
353  }
354 
355  return insertRet;
356 }
357 
358 TER
360 {
361  bool const isSell = offer->isFlag(lsfSellNFToken);
362  AccountID const owner = (*offer)[sfOwner];
363  AccountID const& seller = isSell ? owner : account_;
364  AccountID const& buyer = isSell ? account_ : owner;
365 
366  auto const nftokenID = (*offer)[sfNFTokenID];
367 
368  if (auto amount = offer->getFieldAmount(sfAmount); amount != beast::zero)
369  {
370  // Calculate the issuer's cut from this sale, if any:
371  if (auto const fee = nft::getTransferFee(nftokenID); fee != 0)
372  {
373  auto const cut = multiply(amount, nft::transferFeeAsRate(fee));
374 
375  if (auto const issuer = nft::getIssuer(nftokenID);
376  cut != beast::zero && seller != issuer && buyer != issuer)
377  {
378  if (auto const r = pay(buyer, issuer, cut); !isTesSuccess(r))
379  return r;
380  amount -= cut;
381  }
382  }
383 
384  // Send the remaining funds to the seller of the NFT
385  if (auto const r = pay(buyer, seller, amount); !isTesSuccess(r))
386  return r;
387  }
388 
389  // Now transfer the NFT:
390  return transferNFToken(buyer, seller, nftokenID);
391 }
392 
393 TER
395 {
396  auto const loadToken = [this](std::optional<uint256> const& id) {
398  if (id)
399  sle = view().peek(keylet::nftoffer(*id));
400  return sle;
401  };
402 
403  auto bo = loadToken(ctx_.tx[~sfNFTokenBuyOffer]);
404  auto so = loadToken(ctx_.tx[~sfNFTokenSellOffer]);
405 
406  if (bo && !nft::deleteTokenOffer(view(), bo))
407  {
408  JLOG(j_.fatal()) << "Unable to delete buy offer '"
409  << to_string(bo->key()) << "': ignoring";
410  return tecINTERNAL;
411  }
412 
413  if (so && !nft::deleteTokenOffer(view(), so))
414  {
415  JLOG(j_.fatal()) << "Unable to delete sell offer '"
416  << to_string(so->key()) << "': ignoring";
417  return tecINTERNAL;
418  }
419 
420  // Bridging two different offers
421  if (bo && so)
422  {
423  AccountID const buyer = (*bo)[sfOwner];
424  AccountID const seller = (*so)[sfOwner];
425 
426  auto const nftokenID = (*so)[sfNFTokenID];
427 
428  // The amount is what the buyer of the NFT pays:
429  STAmount amount = (*bo)[sfAmount];
430 
431  // Three different folks may be paid. The order of operations is
432  // important.
433  //
434  // o The broker is paid the cut they requested.
435  // o The issuer's cut is calculated from what remains after the
436  // broker is paid. The issuer can take up to 50% of the remainder.
437  // o Finally, the seller gets whatever is left.
438  //
439  // It is important that the issuer's cut be calculated after the
440  // broker's portion is already removed. Calculating the issuer's
441  // cut before the broker's cut is removed can result in more money
442  // being paid out than the seller authorized. That would be bad!
443 
444  // Send the broker the amount they requested.
445  if (auto const cut = ctx_.tx[~sfNFTokenBrokerFee];
446  cut && cut.value() != beast::zero)
447  {
448  if (auto const r = pay(buyer, account_, cut.value());
449  !isTesSuccess(r))
450  return r;
451 
452  amount -= cut.value();
453  }
454 
455  // Calculate the issuer's cut, if any.
456  if (auto const fee = nft::getTransferFee(nftokenID);
457  amount != beast::zero && fee != 0)
458  {
459  auto cut = multiply(amount, nft::transferFeeAsRate(fee));
460 
461  if (auto const issuer = nft::getIssuer(nftokenID);
462  seller != issuer && buyer != issuer)
463  {
464  if (auto const r = pay(buyer, issuer, cut); !isTesSuccess(r))
465  return r;
466 
467  amount -= cut;
468  }
469  }
470 
471  // And send whatever remains to the seller.
472  if (amount > beast::zero)
473  {
474  if (auto const r = pay(buyer, seller, amount); !isTesSuccess(r))
475  return r;
476  }
477 
478  // Now transfer the NFT:
479  return transferNFToken(buyer, seller, nftokenID);
480  }
481 
482  if (bo)
483  return acceptOffer(bo);
484 
485  if (so)
486  return acceptOffer(so);
487 
488  return tecINTERNAL;
489 }
490 
491 } // namespace ripple
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:338
ripple::sfOwnerCount
const SF_UINT32 sfOwnerCount
ripple::tecOBJECT_NOT_FOUND
@ tecOBJECT_NOT_FOUND
Definition: TER.h:309
ripple::preflight2
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:133
ripple::fixNFTokenNegOffer
const uint256 fixNFTokenNegOffer
ripple::Rules::enabled
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition: Rules.cpp:94
ripple::temBAD_OFFER
@ temBAD_OFFER
Definition: TER.h:94
std::shared_ptr
STL class.
ripple::PreclaimContext::view
ReadView const & view
Definition: Transactor.h:56
ripple::fhZERO_IF_FROZEN
@ fhZERO_IF_FROZEN
Definition: View.h:79
ripple::accountSend
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
Definition: View.cpp:1142
ripple::PreclaimContext::j
const beast::Journal j
Definition: Transactor.h:60
ripple::ApplyView::peek
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
ripple::sfDestination
const SF_ACCOUNT sfDestination
ripple::tfNFTokenAcceptOfferMask
constexpr const std::uint32_t tfNFTokenAcceptOfferMask
Definition: TxFlags.h:161
ripple::sfAmount
const SF_AMOUNT sfAmount
ripple::sfNFTokenID
const SF_UINT256 sfNFTokenID
ripple::Transactor::j_
const beast::Journal j_
Definition: Transactor.h:89
ripple::nft::findTokenAndPage
std::optional< TokenAndPage > findTokenAndPage(ApplyView &view, AccountID const &owner, uint256 const &nftokenID)
Definition: NFTokenUtils.cpp:505
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:643
ripple::NFTokenAcceptOffer::pay
TER pay(AccountID const &from, AccountID const &to, STAmount const &amount)
Definition: NFTokenAcceptOffer.cpp:277
std::pair
ripple::tecINSUFFICIENT_FUNDS
@ tecINSUFFICIENT_FUNDS
Definition: TER.h:308
ripple::sfOwner
const SF_ACCOUNT sfOwner
ripple::nft::transferFeeAsRate
Rate transferFeeAsRate(std::uint16_t fee)
Given a transfer fee (in basis points) convert it to a transfer rate.
Definition: Rate2.cpp:39
ripple::NFTokenAcceptOffer::preflight
static NotTEC preflight(PreflightContext const &ctx)
Definition: NFTokenAcceptOffer.cpp:31
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:226
ripple::keylet::nftoffer
Keylet nftoffer(AccountID const &owner, std::uint32_t seq)
An offer from an account to buy or sell an NFT.
Definition: Indexes.cpp:365
ripple::NFTokenAcceptOffer::preclaim
static TER preclaim(PreclaimContext const &ctx)
Definition: NFTokenAcceptOffer.cpp:64
ripple::hasExpired
bool hasExpired(ReadView const &view, std::optional< std::uint32_t > const &exp)
Determines whether the given expiration time has passed.
Definition: View.cpp:162
ripple::nft::findToken
std::optional< STObject > findToken(ReadView const &view, AccountID const &owner, uint256 const &nftokenID)
Finds the specified token in the owner's token directory.
Definition: NFTokenUtils.cpp:483
ripple::tecCANT_ACCEPT_OWN_NFTOKEN_OFFER
@ tecCANT_ACCEPT_OWN_NFTOKEN_OFFER
Definition: TER.h:307
ripple::nft::removeToken
TER removeToken(ApplyView &view, AccountID const &owner, uint256 const &nftokenID)
Remove the token from the owner's token directory.
Definition: NFTokenUtils.cpp:349
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:81
ripple::lsfSellNFToken
@ lsfSellNFToken
Definition: LedgerFormats.h:310
ripple::sfExpiration
const SF_UINT32 sfExpiration
ripple::nft::getIssuer
AccountID getIssuer(uint256 const &id)
Definition: nft.h:119
ripple::base_uint< 160, detail::AccountIDTag >
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:110
ripple::tecNFTOKEN_OFFER_TYPE_MISMATCH
@ tecNFTOKEN_OFFER_TYPE_MISMATCH
Definition: TER.h:306
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:143
ripple::TERSubset< CanCvtToTER >
ripple::STAmount::value
STAmount const & value() const noexcept
Definition: STAmount.h:443
ripple::fixNFTokenReserve
const uint256 fixNFTokenReserve
ripple::STAmount
Definition: STAmount.h:46
ripple::tecINTERNAL
@ tecINTERNAL
Definition: TER.h:293
ripple::STObject::getFlags
std::uint32_t getFlags() const
Definition: STObject.cpp:497
std::uint32_t
ripple::NFTokenAcceptOffer::acceptOffer
TER acceptOffer(std::shared_ptr< SLE > const &offer)
Definition: NFTokenAcceptOffer.cpp:359
ripple::ReadView::read
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
ripple::PreclaimContext::tx
STTx const & tx
Definition: Transactor.h:58
ripple::accountFunds
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
Definition: View.cpp:282
ripple::multiply
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:47
ripple::PreclaimContext
State information when determining if a tx is likely to claim a fee.
Definition: Transactor.h:52
ripple::sfNFTokenBuyOffer
const SF_UINT256 sfNFTokenBuyOffer
ripple::NFTokenAcceptOffer::doApply
TER doApply() override
Definition: NFTokenAcceptOffer.cpp:394
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::featureNonFungibleTokensV1
const uint256 featureNonFungibleTokensV1
ripple::tecNFTOKEN_BUY_SELL_MISMATCH
@ tecNFTOKEN_BUY_SELL_MISMATCH
Definition: TER.h:305
ripple::tecINSUFFICIENT_PAYMENT
@ tecINSUFFICIENT_PAYMENT
Definition: TER.h:310
ripple::Transactor::view
ApplyView & view()
Definition: Transactor.h:107
ripple::tecEXPIRED
@ tecEXPIRED
Definition: TER.h:297
ripple::temDISABLED
@ temDISABLED
Definition: TER.h:113
ripple::ReadView::rules
virtual Rules const & rules() const =0
Returns the tx processing rules.
ripple::sfFlags
const SF_UINT32 sfFlags
ripple::tecNO_PERMISSION
@ tecNO_PERMISSION
Definition: TER.h:288
ripple::sfBalance
const SF_AMOUNT sfBalance
ripple::tecINSUFFICIENT_RESERVE
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:290
ripple::Transactor::ctx_
ApplyContext & ctx_
Definition: Transactor.h:88
std::optional
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:86
ripple::fixNonFungibleTokensV1_2
const uint256 fixNonFungibleTokensV1_2
ripple::PreflightContext::tx
STTx const & tx
Definition: Transactor.h:35
ripple::nft::getTransferFee
std::uint16_t getTransferFee(uint256 const &id)
Definition: nft.h:67
ripple::PreflightContext
State information when preflighting a tx.
Definition: Transactor.h:31
ripple::PreflightContext::rules
const Rules rules
Definition: Transactor.h:36
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:238
ripple::Transactor::account_
const AccountID account_
Definition: Transactor.h:91
ripple::sfNFTokenSellOffer
const SF_UINT256 sfNFTokenSellOffer
ripple::nft::insertToken
TER insertToken(ApplyView &view, AccountID owner, STObject &&nft)
Insert the token in the owner's token directory.
Definition: NFTokenUtils.cpp:243
ripple::ApplyContext::tx
STTx const & tx
Definition: ApplyContext.h:48
ripple::nft::deleteTokenOffer
bool deleteTokenOffer(ApplyView &view, std::shared_ptr< SLE > const &offer)
Deletes the given token offer.
Definition: NFTokenUtils.cpp:605
ripple::sfNFTokenBrokerFee
const SF_AMOUNT sfNFTokenBrokerFee
ripple::NFTokenAcceptOffer::transferNFToken
TER transferNFToken(AccountID const &buyer, AccountID const &seller, uint256 const &nfTokenID)
Definition: NFTokenAcceptOffer.cpp:305
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:574