xrpld
Toggle main menu visibility
Loading...
Searching...
No Matches
libxrpl
protocol
NFTokenID.cpp
1
#include <xrpl/protocol/NFTokenID.h>
2
3
#include <xrpl/basics/base_uint.h>
4
#include <xrpl/json/json_value.h>
5
#include <xrpl/protocol/LedgerFormats.h>
6
#include <xrpl/protocol/SField.h>
7
#include <xrpl/protocol/STArray.h>
8
#include <xrpl/protocol/STObject.h>
9
#include <xrpl/protocol/STTx.h>
10
#include <xrpl/protocol/TER.h>
11
#include <xrpl/protocol/TxFormats.h>
12
#include <xrpl/protocol/TxMeta.h>
13
#include <xrpl/protocol/jss.h>
14
15
#include <
algorithm
>
16
#include <
iterator
>
17
#include <
memory
>
18
#include <
optional
>
19
#include <
vector
>
20
21
namespace
xrpl
{
22
23
bool
24
canHaveNFTokenID
(
std::shared_ptr<STTx const>
const
& serializedTx,
TxMeta
const
& transactionMeta)
25
{
26
if
(!serializedTx)
27
return
false
;
28
29
TxType
const
tt = serializedTx->getTxnType();
30
if
(tt != ttNFTOKEN_MINT && tt != ttNFTOKEN_ACCEPT_OFFER && tt != ttNFTOKEN_CANCEL_OFFER)
31
return
false
;
32
33
// if the transaction failed nothing could have been delivered.
34
if
(!
isTesSuccess
(transactionMeta.
getResultTER
()))
35
return
false
;
36
37
return
true
;
38
}
39
40
std::optional<UInt256>
41
getNFTokenIDFromPage
(
TxMeta
const
& transactionMeta)
42
{
43
// The metadata does not make it obvious which NFT was added. To figure
44
// that out we gather up all of the previous NFT IDs and all of the final
45
// NFT IDs and compare them to find what changed.
46
std::vector<UInt256>
prevIDs;
47
std::vector<UInt256>
finalIDs;
48
49
for
(
STObject
const
& node : transactionMeta.
getNodes
())
50
{
51
if
(node.getFieldU16(sfLedgerEntryType) != ltNFTOKEN_PAGE)
52
continue
;
53
54
SField
const
& fName = node.getFName();
55
if
(fName == sfCreatedNode)
56
{
57
STArray
const
& toAddPrevNFTs =
58
node.peekAtField(sfNewFields).
downcast
<
STObject
>().getFieldArray(sfNFTokens);
59
std::ranges::transform
(
60
toAddPrevNFTs,
std::back_inserter
(finalIDs), [](
STObject
const
&
nft
) {
61
return
nft
.getFieldH256(sfNFTokenID);
62
});
63
}
64
else
if
(fName == sfModifiedNode)
65
{
66
// When a mint results in splitting an existing page,
67
// it results in a created page and a modified node. Sometimes,
68
// the created node needs to be linked to a third page, resulting
69
// in modifying that third page's PreviousPageMin or NextPageMin
70
// field changing, but no NFTs within that page changing. In this
71
// case, there will be no previous NFTs and we need to skip.
72
// However, there will always be NFTs listed in the final fields,
73
// as xrpld outputs all fields in final fields even if they were
74
// not changed.
75
auto
const
& previousFields = node.peekAtField(sfPreviousFields).downcast<
STObject
>();
76
if
(!previousFields.isFieldPresent(sfNFTokens))
77
continue
;
78
79
STArray
const
& toAddPrevNFTs = previousFields.getFieldArray(sfNFTokens);
80
std::ranges::transform
(
81
toAddPrevNFTs,
std::back_inserter
(prevIDs), [](
STObject
const
&
nft
) {
82
return
nft
.getFieldH256(sfNFTokenID);
83
});
84
85
STArray
const
& toAddFinalNFTs =
86
node.peekAtField(sfFinalFields).
downcast
<
STObject
>().getFieldArray(sfNFTokens);
87
std::ranges::transform
(
88
toAddFinalNFTs,
std::back_inserter
(finalIDs), [](
STObject
const
&
nft
) {
89
return
nft
.getFieldH256(sfNFTokenID);
90
});
91
}
92
}
93
94
// We expect NFTs to be added one at a time. So finalIDs should be one
95
// longer than prevIDs. If that's not the case something is messed up.
96
if
(finalIDs.
size
() != prevIDs.
size
() + 1)
97
return
std::nullopt;
98
99
// Find the first NFT ID that doesn't match. We're looking for an
100
// added NFT, so the one we want will be the mismatch in finalIDs.
101
auto
const
diff =
std::ranges::mismatch
(finalIDs, prevIDs);
102
103
// There should always be a difference so the returned finalIDs
104
// iterator should never be end(). But better safe than sorry.
105
if
(diff.in1 == finalIDs.
end
())
106
return
std::nullopt;
107
108
return
*diff.in1;
109
}
110
111
std::vector<UInt256>
112
getNFTokenIDFromDeletedOffer
(
TxMeta
const
& transactionMeta)
113
{
114
std::vector<UInt256>
tokenIDResult;
115
for
(
STObject
const
& node : transactionMeta.
getNodes
())
116
{
117
if
(node.getFieldU16(sfLedgerEntryType) != ltNFTOKEN_OFFER ||
118
node.getFName() != sfDeletedNode)
119
continue
;
120
121
auto
const
& toAddNFT =
122
node.peekAtField(sfFinalFields).downcast<
STObject
>().getFieldH256(sfNFTokenID);
123
tokenIDResult.
push_back
(toAddNFT);
124
}
125
126
// Deduplicate the NFT IDs because multiple offers could affect the same NFT
127
// and hence we would get duplicate NFT IDs
128
std::ranges::sort
(tokenIDResult);
129
auto
const
uniq =
std::ranges::unique
(tokenIDResult);
130
tokenIDResult.
erase
(uniq.begin(), uniq.end());
131
return
tokenIDResult;
132
}
133
134
void
135
insertNFTokenID
(
136
json::Value
& response,
137
std::shared_ptr<STTx const>
const
& transaction,
138
TxMeta
const
& transactionMeta)
139
{
140
if
(!
canHaveNFTokenID
(transaction, transactionMeta))
141
return
;
142
143
// We extract the NFTokenID from metadata by comparing affected nodes
144
if
(
auto
const
type = transaction->getTxnType(); type == ttNFTOKEN_MINT)
145
{
146
std::optional<UInt256>
result =
getNFTokenIDFromPage
(transactionMeta);
147
if
(result.
has_value
())
148
response[jss::nftoken_id] =
to_string
(result.
value
());
149
}
150
else
if
(type == ttNFTOKEN_ACCEPT_OFFER)
151
{
152
std::vector<UInt256>
result =
getNFTokenIDFromDeletedOffer
(transactionMeta);
153
154
if
(!result.
empty
())
155
response[jss::nftoken_id] =
to_string
(result.
front
());
156
}
157
else
if
(type == ttNFTOKEN_CANCEL_OFFER)
158
{
159
std::vector<UInt256>
const
result =
getNFTokenIDFromDeletedOffer
(transactionMeta);
160
161
response[jss::nftoken_ids] =
json::Value
(
json::ValueType::Array
);
162
for
(
auto
const
& nftID : result)
163
response[jss::nftoken_ids].
append
(
to_string
(nftID));
164
}
165
}
166
167
}
// namespace xrpl
algorithm
std::back_inserter
T back_inserter(T... args)
json::Value
Represents a JSON value.
Definition
json_value.h:117
json::Value::append
Value & append(Value const &value)
Append value to array at the end.
Definition
json_value.cpp:997
xrpl::SField
Identifies fields.
Definition
SField.h:132
xrpl::STArray
Definition
STArray.h:20
xrpl::STBase::downcast
D & downcast()
Definition
STBase.h:206
xrpl::STObject
Definition
STObject.h:49
xrpl::TxMeta
Definition
TxMeta.h:26
xrpl::TxMeta::getResultTER
TER getResultTER() const
Definition
TxMeta.h:48
xrpl::TxMeta::getNodes
STArray & getNodes()
Definition
TxMeta.h:82
std::vector::empty
T empty(T... args)
std::vector::end
T end(T... args)
std::vector::erase
T erase(T... args)
std::vector::front
T front(T... args)
iterator
memory
std::ranges::mismatch
T mismatch(T... args)
json::ValueType::Array
@ Array
array value (ordered list)
Definition
json_value.h:28
xrpl::nft
Definition
NFTokenHelpers.h:25
xrpl
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition
algorithm.h:5
xrpl::TxType
TxType
Transaction type identifiers.
Definition
TxFormats.h:45
xrpl::canHaveNFTokenID
bool canHaveNFTokenID(std::shared_ptr< STTx const > const &serializedTx, TxMeta const &transactionMeta)
Add a nftoken_ids field to the meta output parameter.
Definition
NFTokenID.cpp:24
xrpl::to_string
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition
base_uint.h:657
xrpl::insertNFTokenID
void insertNFTokenID(json::Value &response, std::shared_ptr< STTx const > const &transaction, TxMeta const &transactionMeta)
Definition
NFTokenID.cpp:135
xrpl::isTesSuccess
bool isTesSuccess(TER x) noexcept
Definition
TER.h:683
xrpl::getNFTokenIDFromDeletedOffer
std::vector< UInt256 > getNFTokenIDFromDeletedOffer(TxMeta const &transactionMeta)
Definition
NFTokenID.cpp:112
xrpl::getNFTokenIDFromPage
std::optional< UInt256 > getNFTokenIDFromPage(TxMeta const &transactionMeta)
Definition
NFTokenID.cpp:41
std::optional::has_value
T has_value(T... args)
optional
std::vector::push_back
T push_back(T... args)
std::shared_ptr
std::vector::size
T size(T... args)
std::ranges::sort
T sort(T... args)
std::ranges::transform
T transform(T... args)
std::ranges::unique
T unique(T... args)
std::optional::value
T value(T... args)
vector
Generated by
1.17.0