rippled
NFTokenBurn.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/NFTokenBurn.h>
21 #include <ripple/app/tx/impl/details/NFTokenUtils.h>
22 #include <ripple/ledger/Directory.h>
23 #include <ripple/ledger/View.h>
24 #include <ripple/protocol/Feature.h>
25 #include <ripple/protocol/Protocol.h>
26 #include <ripple/protocol/TxFlags.h>
27 #include <ripple/protocol/st.h>
28 #include <boost/endian/conversion.hpp>
29 #include <array>
30 
31 namespace ripple {
32 
33 NotTEC
35 {
37  return temDISABLED;
38 
39  if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
40  return ret;
41 
42  if (ctx.tx.getFlags() & tfUniversalMask)
43  return temINVALID_FLAG;
44 
45  return preflight2(ctx);
46 }
47 
48 TER
50 {
51  auto const owner = [&ctx]() {
52  if (ctx.tx.isFieldPresent(sfOwner))
53  return ctx.tx.getAccountID(sfOwner);
54 
55  return ctx.tx[sfAccount];
56  }();
57 
58  if (!nft::findToken(ctx.view, owner, ctx.tx[sfNFTokenID]))
59  return tecNO_ENTRY;
60 
61  // The owner of a token can always burn it, but the issuer can only
62  // do so if the token is marked as burnable.
63  if (auto const account = ctx.tx[sfAccount]; owner != account)
64  {
66  return tecNO_PERMISSION;
67 
68  if (auto const issuer = nft::getIssuer(ctx.tx[sfNFTokenID]);
69  issuer != account)
70  {
71  if (auto const sle = ctx.view.read(keylet::account(issuer)); sle)
72  {
73  if (auto const minter = (*sle)[~sfNFTokenMinter];
74  minter != account)
75  return tecNO_PERMISSION;
76  }
77  }
78  }
79 
81  {
82  // If there are too many offers, then burning the token would produce
83  // too much metadata. Disallow burning a token with too many offers.
84  return nft::notTooManyOffers(ctx.view, ctx.tx[sfNFTokenID]);
85  }
86 
87  return tesSUCCESS;
88 }
89 
90 TER
92 {
93  // Remove the token, effectively burning it:
94  auto const ret = nft::removeToken(
95  view(),
99 
100  // Should never happen since preclaim() verified the token is present.
101  if (!isTesSuccess(ret))
102  return ret;
103 
104  if (auto issuer =
106  {
107  (*issuer)[~sfBurnedNFTokens] =
108  (*issuer)[~sfBurnedNFTokens].value_or(0) + 1;
109  view().update(issuer);
110  }
111 
113  {
114  // Delete up to 500 offers in total.
115  // Because the number of sell offers is likely to be less than
116  // the number of buy offers, we prioritize the deletion of sell
117  // offers in order to clean up sell offer directory
118  std::size_t const deletedSellOffers = nft::removeTokenOffersWithLimit(
119  view(),
122 
123  if (maxDeletableTokenOfferEntries > deletedSellOffers)
124  {
126  view(),
128  maxDeletableTokenOfferEntries - deletedSellOffers);
129  }
130  }
131  else
132  {
133  // Deletion of all offers.
135  view(),
138 
140  view(),
143  }
144 
145  return tesSUCCESS;
146 }
147 
148 } // namespace ripple
ripple::NFTokenBurn::preflight
static NotTEC preflight(PreflightContext const &ctx)
Definition: NFTokenBurn.cpp:34
ripple::preflight2
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:130
ripple::nft::getFlags
std::uint16_t getFlags(uint256 const &id)
Definition: NFTokenUtils.h:120
ripple::Rules::enabled
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition: Rules.cpp:94
ripple::PreclaimContext::view
ReadView const & view
Definition: Transactor.h:56
ripple::maxDeletableTokenOfferEntries
constexpr std::size_t maxDeletableTokenOfferEntries
The maximum number of offers in an offer directory for NFT to be burnable.
Definition: Protocol.h:70
ripple::sfNFTokenID
const SF_UINT256 sfNFTokenID
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:597
ripple::nft::removeTokenOffersWithLimit
std::size_t removeTokenOffersWithLimit(ApplyView &view, Keylet const &directory, std::size_t maxDeletableOffers)
Delete up to a specified number of offers from the specified token offer directory.
Definition: NFTokenUtils.cpp:528
ripple::sfOwner
const SF_ACCOUNT sfOwner
ripple::nft::notTooManyOffers
TER notTooManyOffers(ReadView const &view, uint256 const &nftokenID)
Returns tesSUCCESS if NFToken has few enough offers that it can be burned.
Definition: NFTokenUtils.cpp:578
ripple::NFTokenBurn::doApply
TER doApply() override
Definition: NFTokenBurn.cpp:91
ripple::ApplyView::update
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
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::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:78
ripple::NFTokenBurn::preclaim
static TER preclaim(PreclaimContext const &ctx)
Definition: NFTokenBurn.cpp:49
ripple::nft::getIssuer
AccountID getIssuer(uint256 const &id)
Definition: NFTokenUtils.h:180
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:109
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:133
ripple::sfNFTokenMinter
const SF_ACCOUNT sfNFTokenMinter
ripple::STObject::getAccountID
AccountID getAccountID(SField const &field) const
Definition: STObject.cpp:589
ripple::TERSubset< CanCvtToTER >
array
ripple::keylet::nft_sells
Keylet nft_sells(uint256 const &id) noexcept
The directory of sell offers for the specified NFT.
Definition: Indexes.cpp:368
ripple::STObject::getFlags
std::uint32_t getFlags() const
Definition: STObject.cpp:481
ripple::keylet::nft_buys
Keylet nft_buys(uint256 const &id) noexcept
The directory of buy offers for the specified NFT.
Definition: Indexes.cpp:362
ripple::ReadView::read
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
ripple::ApplyContext::view
ApplyView & view()
Definition: ApplyContext.h:54
ripple::PreclaimContext::tx
STTx const & tx
Definition: Transactor.h:58
ripple::PreclaimContext
State information when determining if a tx is likely to claim a fee.
Definition: Transactor.h:52
ripple::nft::flagBurnable
constexpr const std::uint16_t flagBurnable
Definition: NFTokenUtils.h:51
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::Transactor::view
ApplyView & view()
Definition: Transactor.h:107
ripple::temDISABLED
@ temDISABLED
Definition: TER.h:112
ripple::ReadView::rules
virtual Rules const & rules() const =0
Returns the tx processing rules.
ripple::STObject::isFieldPresent
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:428
ripple::tecNO_PERMISSION
@ tecNO_PERMISSION
Definition: TER.h:272
ripple::Transactor::ctx_
ApplyContext & ctx_
Definition: Transactor.h:88
std::size_t
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::tecNO_ENTRY
@ tecNO_ENTRY
Definition: TER.h:273
ripple::fixNonFungibleTokensV1_2
const uint256 fixNonFungibleTokensV1_2
ripple::PreflightContext::tx
STTx const & tx
Definition: Transactor.h:35
ripple::PreflightContext
State information when preflighting a tx.
Definition: Transactor.h:31
ripple::sfBurnedNFTokens
const SF_UINT32 sfBurnedNFTokens
ripple::PreflightContext::rules
const Rules rules
Definition: Transactor.h:36
ripple::tfUniversalMask
constexpr std::uint32_t tfUniversalMask
Definition: TxFlags.h:60
std::numeric_limits
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:222
ripple::ApplyContext::tx
STTx const & tx
Definition: ApplyContext.h:48
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:528