xrpld
Loading...
Searching...
No Matches
NFTOffersHelpers.h
1#pragma once
2
3#include <xrpld/rpc/Context.h>
4#include <xrpld/rpc/detail/RPCHelpers.h>
5#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
6#include <xrpld/rpc/detail/Tuning.h>
7
8#include <xrpl/basics/base_uint.h>
9#include <xrpl/core/ServiceRegistry.h>
10#include <xrpl/json/json_value.h>
11#include <xrpl/ledger/ReadView.h>
12#include <xrpl/ledger/helpers/DirectoryHelpers.h>
13#include <xrpl/protocol/AccountID.h>
14#include <xrpl/protocol/ErrorCodes.h>
15#include <xrpl/protocol/Indexes.h>
16#include <xrpl/protocol/Keylet.h>
17#include <xrpl/protocol/LedgerFormats.h>
18#include <xrpl/protocol/RPCErr.h>
19#include <xrpl/protocol/SField.h>
20#include <xrpl/protocol/jss.h>
21#include <xrpl/resource/Fees.h>
22
23#include <cstdint>
24#include <memory>
25#include <vector>
26
27namespace xrpl {
28
29inline void
31{
32 json::Value& obj(offers.append(json::ValueType::Object));
33
34 obj[jss::nft_offer_index] = to_string(offer->key());
35 obj[jss::flags] = (*offer)[sfFlags];
36 obj[jss::owner] = toBase58(offer->getAccountID(sfOwner));
37
38 if (offer->isFieldPresent(sfDestination))
39 obj[jss::destination] = toBase58(offer->getAccountID(sfDestination));
40
41 if (offer->isFieldPresent(sfExpiration))
42 obj[jss::expiration] = offer->getFieldU32(sfExpiration);
43
44 offer->getFieldAmount(sfAmount).setJson(obj[jss::amount]);
45}
46
47// {
48// nft_id: <token hash>
49// ledger_hash : <ledger>
50// ledger_index : <ledger_index>
51// limit: integer // optional
52// marker: opaque // optional, resume previous query
53// }
54inline json::Value
56{
57 unsigned int limit = 0;
58 if (auto err = readLimitField(limit, rpc::tuning::kNftOffers, context))
59 return *err;
60
62
63 if (auto result = rpc::lookupLedger(ledger, context); !ledger)
64 return result;
65
66 if (!ledger->exists(directory))
68
69 json::Value result;
70 result[jss::nft_id] = to_string(nftId);
71
72 json::Value& jsonOffers(result[jss::offers] = json::ValueType::Array);
73
75 unsigned int reserve(limit);
76 uint256 startAfter;
77 std::uint64_t startHint = 0;
78
79 if (context.params.isMember(jss::marker))
80 {
81 // We have a start point. Use limit - 1 from the result and use the
82 // very last one for the resume.
83 json::Value const& marker(context.params[jss::marker]);
84
85 if (!marker.isString())
86 return rpc::expectedFieldError(jss::marker, "string");
87
88 if (!startAfter.parseHex(marker.asString()))
90
91 auto const sle = ledger->read(keylet::nftokenOffer(startAfter));
92
93 if (!sle || nftId != sle->getFieldH256(sfNFTokenID))
95
96 // Reject a marker that references an offer on the opposite side
97 // (buy vs. sell) of the directory being enumerated. Without this
98 // check the marker's node hint points into the other directory, so
99 // forEachItemAfter never finds `startAfter` and instead scans every
100 // page of `directory` before returning invalidParams -- turning an
101 // O(1) rejection into an O(directory size) walk.
102 auto const offerDir =
103 sle->isFlag(lsfSellNFToken) ? keylet::nftSells(nftId) : keylet::nftBuys(nftId);
104 if (directory.key != offerDir.key)
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, directory, startAfter, startHint, reserve, [&offers](SLE::const_ref offer) {
119 if (offer->getType() == ltNFTOKEN_OFFER)
120 {
121 offers.emplace_back(offer);
122 return true;
123 }
124
125 return false;
126 }))
127 {
129 }
130
131 if (offers.size() == reserve)
132 {
133 result[jss::limit] = limit;
134 result[jss::marker] = to_string(offers.back()->key());
135 offers.pop_back();
136 }
137
138 for (auto const& offer : offers)
139 appendNftOfferJson(context.app, offer, jsonOffers);
140
142 return result;
143}
144
145} // namespace xrpl
Represents a JSON value.
Definition json_value.h:117
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:525
std::shared_ptr< STLedgerEntry const > const & const_ref
@ Array
array value (ordered list)
Definition json_value.h:28
@ Object
object value (collection of name/value pairs).
Definition json_value.h:29
Keylet nftokenOffer(AccountID const &owner, SeqProxy const &seq)
An offer from an account to buy or sell an NFT.
Definition Indexes.cpp:423
Keylet nftSells(uint256 const &id) noexcept
The directory of sell offers for the specified NFT.
Definition Indexes.cpp:435
Keylet nftBuys(uint256 const &id) noexcept
The directory of buy offers for the specified NFT.
Definition Indexes.cpp:429
Charge const kFeeMediumBurdenRpc
static constexpr LimitRange kNftOffers
Limits for the nft_buy_offers & nft_sell_offers commands.
json::Value expectedFieldError(std::string const &name, std::string const &type)
Definition ErrorCodes.h:309
Status lookupLedger(std::shared_ptr< ReadView const > &ledger, JsonContext const &context, json::Value &result)
Looks up a ledger from a request and fills a json::Value with ledger data.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
void appendNftOfferJson(Application const &app, SLE::const_ref offer, json::Value &offers)
@ RpcObjectNotFound
Definition ErrorCodes.h:126
@ RpcInvalidParams
Definition ErrorCodes.h:67
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:95
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:651
json::Value rpcError(ErrorCodeI iError)
Definition RPCErr.cpp:13
json::Value enumerateNFTOffers(rpc::JsonContext &context, uint256 const &nftId, Keylet const &directory)
BaseUInt< 256 > uint256
Definition base_uint.h:580
bool forEachItemAfter(ReadView const &view, Keylet const &root, uint256 const &after, std::uint64_t const hint, unsigned int limit, std::function< bool(SLE::const_ref)> const &f)
Iterate all items after an item in the given directory.
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:20
uint256 key
Definition Keylet.h:21
resource::Charge & loadType
Definition Context.h:30
Application & app
Definition Context.h:29
json::Value params
Definition Context.h:51