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/ledger/ReadView.h>
21#include <xrpld/ledger/View.h>
22#include <xrpld/rpc/Context.h>
23#include <xrpld/rpc/detail/RPCHelpers.h>
24#include <xrpld/rpc/detail/Tuning.h>
25
26#include <xrpl/json/json_value.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:148
bool isString() const
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:475
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:949
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:43
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:44
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:315
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:339
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:622
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:273
Charge const feeMediumBurdenRPC
Keylet nft_buys(uint256 const &id) noexcept
The directory of buy offers for the specified NFT.
Definition: Indexes.cpp:425
Keylet nft_sells(uint256 const &id) noexcept
The directory of sell offers for the specified NFT.
Definition: Indexes.cpp:431
Keylet nftoffer(AccountID const &owner, std::uint32_t seq)
An offer from an account to buy or sell an NFT.
Definition: Indexes.cpp:418
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:114
static Json::Value enumerateNFTOffers(RPC::JsonContext &context, uint256 const &nftId, Keylet const &directory)
Definition: NFTOffers.cpp:63
Json::Value doNFTBuyOffers(RPC::JsonContext &)
Definition: NFTOffers.cpp:165
@ 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 &)
Definition: NFTOffers.cpp:151
static void appendNftOfferJson(Application const &app, std::shared_ptr< SLE const > const &offer, Json::Value &offers)
Definition: NFTOffers.cpp:35
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
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:572
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
Json::Value params
Definition: Context.h:63