rippled
NFTOffers.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2022 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/main/Application.h>
21 #include <ripple/json/json_value.h>
22 #include <ripple/ledger/ReadView.h>
23 #include <ripple/ledger/View.h>
24 #include <ripple/net/RPCErr.h>
25 #include <ripple/protocol/ErrorCodes.h>
26 #include <ripple/protocol/jss.h>
27 #include <ripple/resource/Fees.h>
28 #include <ripple/rpc/Context.h>
29 #include <ripple/rpc/impl/RPCHelpers.h>
30 #include <ripple/rpc/impl/Tuning.h>
31 
32 namespace ripple {
33 
34 static void
36  Application const& app,
37  std::shared_ptr<SLE const> const& offer,
38  Json::Value& offers)
39 {
40  Json::Value& obj(offers.append(Json::objectValue));
41 
42  obj[jss::nft_offer_index] = to_string(offer->key());
43  obj[jss::flags] = (*offer)[sfFlags];
44  obj[jss::owner] =
45  app.accountIDCache().toBase58(offer->getAccountID(sfOwner));
46 
47  if (offer->isFieldPresent(sfDestination))
48  obj[jss::destination] =
49  app.accountIDCache().toBase58(offer->getAccountID(sfDestination));
50 
51  if (offer->isFieldPresent(sfExpiration))
52  obj[jss::expiration] = offer->getFieldU32(sfExpiration);
53 
54  offer->getFieldAmount(sfAmount).setJson(obj[jss::amount]);
55 }
56 
57 // {
58 // nft_id: <token hash>
59 // ledger_hash : <ledger>
60 // ledger_index : <ledger_index>
61 // limit: integer // optional
62 // marker: opaque // optional, resume previous query
63 // }
64 static Json::Value
66  RPC::JsonContext& context,
67  uint256 const& nftId,
68  Keylet const& directory)
69 {
70  unsigned int limit;
71  if (auto err = readLimitField(limit, RPC::Tuning::nftOffers, context))
72  return *err;
73 
75 
76  if (auto result = RPC::lookupLedger(ledger, context); !ledger)
77  return result;
78 
79  if (!ledger->exists(directory))
81 
82  Json::Value result;
83  result[jss::nft_id] = to_string(nftId);
84 
85  Json::Value& jsonOffers(result[jss::offers] = Json::arrayValue);
86 
88  unsigned int reserve(limit);
89  uint256 startAfter;
90  std::uint64_t startHint = 0;
91 
92  if (context.params.isMember(jss::marker))
93  {
94  // We have a start point. Use limit - 1 from the result and use the
95  // very last one for the resume.
96  Json::Value const& marker(context.params[jss::marker]);
97 
98  if (!marker.isString())
99  return RPC::expected_field_error(jss::marker, "string");
100 
101  if (!startAfter.parseHex(marker.asString()))
102  return rpcError(rpcINVALID_PARAMS);
103 
104  auto const sle = ledger->read(keylet::nftoffer(startAfter));
105 
106  if (!sle || nftId != sle->getFieldH256(sfNFTokenID))
107  return rpcError(rpcINVALID_PARAMS);
108 
109  startHint = sle->getFieldU64(sfNFTokenOfferNode);
110  appendNftOfferJson(context.app, sle, jsonOffers);
111  offers.reserve(reserve);
112  }
113  else
114  {
115  // We have no start point, limit should be one higher than requested.
116  offers.reserve(++reserve);
117  }
118 
119  if (!forEachItemAfter(
120  *ledger,
121  directory,
122  startAfter,
123  startHint,
124  reserve,
125  [&offers](std::shared_ptr<SLE const> const& offer) {
126  if (offer->getType() == ltNFTOKEN_OFFER)
127  {
128  offers.emplace_back(offer);
129  return true;
130  }
131 
132  return false;
133  }))
134  {
135  return rpcError(rpcINVALID_PARAMS);
136  }
137 
138  if (offers.size() == reserve)
139  {
140  result[jss::limit] = limit;
141  result[jss::marker] = to_string(offers.back()->key());
142  offers.pop_back();
143  }
144 
145  for (auto const& offer : offers)
146  appendNftOfferJson(context.app, offer, jsonOffers);
147 
149  return result;
150 }
151 
154 {
155  if (!context.params.isMember(jss::nft_id))
156  return RPC::missing_field_error(jss::nft_id);
157 
158  uint256 nftId;
159 
160  if (!nftId.parseHex(context.params[jss::nft_id].asString()))
161  return RPC::invalid_field_error(jss::nft_id);
162 
163  return enumerateNFTOffers(context, nftId, keylet::nft_sells(nftId));
164 }
165 
168 {
169  if (!context.params.isMember(jss::nft_id))
170  return RPC::missing_field_error(jss::nft_id);
171 
172  uint256 nftId;
173 
174  if (!nftId.parseHex(context.params[jss::nft_id].asString()))
175  return RPC::invalid_field_error(jss::nft_id);
176 
177  return enumerateNFTOffers(context, nftId, keylet::nft_buys(nftId));
178 }
179 
180 } // namespace ripple
ripple::enumerateNFTOffers
static Json::Value enumerateNFTOffers(RPC::JsonContext &context, uint256 const &nftId, Keylet const &directory)
Definition: NFTOffers.cpp:65
ripple::Application
Definition: Application.h:115
ripple::RPC::JsonContext
Definition: Context.h:53
ripple::Keylet
A pair of SHAMap key and LedgerEntryType.
Definition: Keylet.h:38
std::shared_ptr
STL class.
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
Json::Value::isString
bool isString() const
Definition: json_value.cpp:1009
ripple::rpcError
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:29
ripple::forEachItemAfter
bool forEachItemAfter(ReadView const &view, Keylet const &root, uint256 const &after, std::uint64_t const hint, unsigned int limit, std::function< bool(std::shared_ptr< SLE const > const &)> const &f)
Iterate all items after an item in the given directory.
Definition: View.cpp:394
ripple::sfDestination
const SF_ACCOUNT sfDestination
ripple::sfAmount
const SF_AMOUNT sfAmount
ripple::Resource::feeMediumBurdenRPC
const Charge feeMediumBurdenRPC
ripple::sfNFTokenID
const SF_UINT256 sfNFTokenID
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::sfOwner
const SF_ACCOUNT sfOwner
ripple::RPC::Context::loadType
Resource::Charge & loadType
Definition: Context.h:43
std::vector
STL class.
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:355
ripple::RPC::lookupLedger
Status lookupLedger(std::shared_ptr< ReadView const > &ledger, JsonContext &context, Json::Value &result)
Look up a ledger from a request and fill a Json::Result with the data representing a ledger.
Definition: RPCHelpers.cpp:582
ripple::sfNFTokenOfferNode
const SF_UINT64 sfNFTokenOfferNode
ripple::Application::accountIDCache
virtual AccountIDCache const & accountIDCache() const =0
ripple::rpcOBJECT_NOT_FOUND
@ rpcOBJECT_NOT_FOUND
Definition: ErrorCodes.h:143
ripple::RPC::expected_field_error
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:312
ripple::sfExpiration
const SF_UINT32 sfExpiration
ripple::RPC::missing_field_error
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:246
ripple::doNFTBuyOffers
Json::Value doNFTBuyOffers(RPC::JsonContext &)
Definition: NFTOffers.cpp:167
ripple::Keylet::key
uint256 key
Definition: Keylet.h:40
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:75
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::RPC::Tuning::nftOffers
static constexpr LimitRange nftOffers
Limits for the nft_buy_offers & nft_sell_offers commands.
Definition: rpc/impl/Tuning.h:58
ripple::doNFTSellOffers
Json::Value doNFTSellOffers(RPC::JsonContext &)
Definition: NFTOffers.cpp:153
ripple::appendNftOfferJson
static void appendNftOfferJson(Application const &app, std::shared_ptr< SLE const > const &offer, Json::Value &offers)
Definition: NFTOffers.cpp:35
ripple::ltNFTOKEN_OFFER
@ ltNFTOKEN_OFFER
A ledger object which identifies an offer to buy or sell an NFT.
Definition: LedgerFormats.h:162
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::RPC::Context::app
Application & app
Definition: Context.h:42
ripple::ReadView::exists
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
std::uint64_t
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
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::sfFlags
const SF_UINT32 sfFlags
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::base_uint::parseHex
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:489
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
ripple::RPC::invalid_field_error
Json::Value invalid_field_error(std::string const &name)
Definition: ErrorCodes.h:288
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::AccountIDCache::toBase58
std::string toBase58(AccountID const &) const
Return ripple::toBase58 for the AccountID.
Definition: AccountID.cpp:134
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469