rippled
Loading...
Searching...
No Matches
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 <xrpld/rpc/Context.h>
21#include <xrpld/rpc/detail/RPCHelpers.h>
22#include <xrpld/rpc/detail/Tuning.h>
23
24#include <xrpl/json/json_value.h>
25#include <xrpl/ledger/ReadView.h>
26#include <xrpl/ledger/View.h>
27#include <xrpl/protocol/ErrorCodes.h>
28#include <xrpl/protocol/RPCErr.h>
29#include <xrpl/protocol/jss.h>
30#include <xrpl/resource/Fees.h>
31
32namespace ripple {
33
34static 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] = toBase58(offer->getAccountID(sfOwner));
45
46 if (offer->isFieldPresent(sfDestination))
47 obj[jss::destination] = toBase58(offer->getAccountID(sfDestination));
48
49 if (offer->isFieldPresent(sfExpiration))
50 obj[jss::expiration] = offer->getFieldU32(sfExpiration);
51
52 offer->getFieldAmount(sfAmount).setJson(obj[jss::amount]);
53}
54
55// {
56// nft_id: <token hash>
57// ledger_hash : <ledger>
58// ledger_index : <ledger_index>
59// limit: integer // optional
60// marker: opaque // optional, resume previous query
61// }
62static Json::Value
64 RPC::JsonContext& context,
65 uint256 const& nftId,
66 Keylet const& directory)
67{
68 unsigned int limit;
69 if (auto err = readLimitField(limit, RPC::Tuning::nftOffers, context))
70 return *err;
71
73
74 if (auto result = RPC::lookupLedger(ledger, context); !ledger)
75 return result;
76
77 if (!ledger->exists(directory))
79
80 Json::Value result;
81 result[jss::nft_id] = to_string(nftId);
82
83 Json::Value& jsonOffers(result[jss::offers] = Json::arrayValue);
84
86 unsigned int reserve(limit);
87 uint256 startAfter;
88 std::uint64_t startHint = 0;
89
90 if (context.params.isMember(jss::marker))
91 {
92 // We have a start point. Use limit - 1 from the result and use the
93 // very last one for the resume.
94 Json::Value const& marker(context.params[jss::marker]);
95
96 if (!marker.isString())
97 return RPC::expected_field_error(jss::marker, "string");
98
99 if (!startAfter.parseHex(marker.asString()))
101
102 auto const sle = ledger->read(keylet::nftoffer(startAfter));
103
104 if (!sle || nftId != sle->getFieldH256(sfNFTokenID))
106
107 startHint = sle->getFieldU64(sfNFTokenOfferNode);
108 appendNftOfferJson(context.app, sle, jsonOffers);
109 offers.reserve(reserve);
110 }
111 else
112 {
113 // We have no start point, limit should be one higher than requested.
114 offers.reserve(++reserve);
115 }
116
117 if (!forEachItemAfter(
118 *ledger,
119 directory,
120 startAfter,
121 startHint,
122 reserve,
123 [&offers](std::shared_ptr<SLE const> const& offer) {
124 if (offer->getType() == ltNFTOKEN_OFFER)
125 {
126 offers.emplace_back(offer);
127 return true;
128 }
129
130 return false;
131 }))
132 {
134 }
135
136 if (offers.size() == reserve)
137 {
138 result[jss::limit] = limit;
139 result[jss::marker] = to_string(offers.back()->key());
140 offers.pop_back();
141 }
142
143 for (auto const& offer : offers)
144 appendNftOfferJson(context.app, offer, jsonOffers);
145
147 return result;
148}
149
152{
153 if (!context.params.isMember(jss::nft_id))
154 return RPC::missing_field_error(jss::nft_id);
155
156 uint256 nftId;
157
158 if (!nftId.parseHex(context.params[jss::nft_id].asString()))
159 return RPC::invalid_field_error(jss::nft_id);
160
161 return enumerateNFTOffers(context, nftId, keylet::nft_sells(nftId));
162}
163
166{
167 if (!context.params.isMember(jss::nft_id))
168 return RPC::missing_field_error(jss::nft_id);
169
170 uint256 nftId;
171
172 if (!nftId.parseHex(context.params[jss::nft_id].asString()))
173 return RPC::invalid_field_error(jss::nft_id);
174
175 return enumerateNFTOffers(context, nftId, keylet::nft_buys(nftId));
176}
177
178} // namespace ripple
Represents a JSON value.
Definition json_value.h:149
bool isString() const
std::string asString() const
Returns the unquoted string value.
bool isMember(char const *key) const
Return true if the object has a member named key.
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:503
@ arrayValue
array value (ordered list)
Definition json_value.h:44
@ objectValue
object value (collection of name/value pairs).
Definition json_value.h:45
static LimitRange constexpr nftOffers
Limits for the nft_buy_offers & nft_sell_offers commands.
Json::Value invalid_field_error(std::string const &name)
Definition ErrorCodes.h:325
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition ErrorCodes.h:349
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.
Json::Value missing_field_error(std::string const &name)
Definition ErrorCodes.h:283
Charge const feeMediumBurdenRPC
Keylet nft_buys(uint256 const &id) noexcept
The directory of buy offers for the specified NFT.
Definition Indexes.cpp:434
Keylet nft_sells(uint256 const &id) noexcept
The directory of sell offers for the specified NFT.
Definition Indexes.cpp:440
Keylet nftoffer(AccountID const &owner, std::uint32_t seq)
An offer from an account to buy or sell an NFT.
Definition Indexes.cpp:427
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
static Json::Value enumerateNFTOffers(RPC::JsonContext &context, uint256 const &nftId, Keylet const &directory)
Definition NFTOffers.cpp:63
Json::Value doNFTBuyOffers(RPC::JsonContext &)
@ rpcOBJECT_NOT_FOUND
Definition ErrorCodes.h:143
@ rpcINVALID_PARAMS
Definition ErrorCodes.h:84
Json::Value rpcError(int iError)
Definition RPCErr.cpp:31
Json::Value doNFTSellOffers(RPC::JsonContext &)
static void appendNftOfferJson(Application const &app, std::shared_ptr< SLE const > const &offer, Json::Value &offers)
Definition NFTOffers.cpp:35
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:684
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:630
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:39
uint256 key
Definition Keylet.h:40
Resource::Charge & loadType
Definition Context.h:42
Application & app
Definition Context.h:41