52class BookChanges final {
54 BookChanges() =
delete;
62 [[nodiscard]]
static std::vector<BookChange>
63 compute(std::vector<data::TransactionAndMetadata>
const& transactions)
65 return HandlerImpl{}(transactions);
69 class HandlerImpl final {
70 std::map<std::string, BookChange> tally_;
71 std::optional<uint32_t> offerCancel_;
74 [[nodiscard]] std::vector<BookChange>
75 operator()(std::vector<data::TransactionAndMetadata>
const& transactions)
77 for (
auto const& tx : transactions)
81 std::vector<BookChange> changes;
83 std::make_move_iterator(std::begin(tally_)),
84 std::make_move_iterator(std::end(tally_)),
85 std::back_inserter(changes),
86 [](
auto obj) {
return obj.second; }
93 handleAffectedNode(xrpl::STObject
const& node)
95 auto const& metaType = node.getFName();
96 auto const nodeType = node.getFieldU16(xrpl::sfLedgerEntryType);
100 if (nodeType != xrpl::ltOFFER || metaType == xrpl::sfCreatedNode)
106 if (!node.isFieldPresent(xrpl::sfFinalFields) ||
107 !node.isFieldPresent(xrpl::sfPreviousFields))
110 auto const& finalFields =
111 node.peekAtField(xrpl::sfFinalFields).downcast<xrpl::STObject>();
112 auto const& previousFields =
113 node.peekAtField(xrpl::sfPreviousFields).downcast<xrpl::STObject>();
116 if (!finalFields.isFieldPresent(xrpl::sfTakerGets) ||
117 !finalFields.isFieldPresent(xrpl::sfTakerPays) ||
118 !previousFields.isFieldPresent(xrpl::sfTakerGets) ||
119 !previousFields.isFieldPresent(xrpl::sfTakerPays))
123 if (metaType == xrpl::sfDeletedNode && offerCancel_ &&
124 finalFields.getFieldU32(xrpl::sfSequence) == *offerCancel_)
129 auto const deltaGets = finalFields.getFieldAmount(xrpl::sfTakerGets) -
130 previousFields.getFieldAmount(xrpl::sfTakerGets);
131 auto const deltaPays = finalFields.getFieldAmount(xrpl::sfTakerPays) -
132 previousFields.getFieldAmount(xrpl::sfTakerPays);
134 transformAndStore(deltaGets, deltaPays, finalFields[~xrpl::sfDomainID]);
139 xrpl::STAmount
const& deltaGets,
140 xrpl::STAmount
const& deltaPays,
141 std::optional<xrpl::uint256>
const& domain
144 auto const g = to_string(deltaGets.get<xrpl::Issue>());
145 auto const p = to_string(deltaPays.get<xrpl::Issue>());
147 auto const noswap = [&]() {
148 if (isXRP(deltaGets))
150 return isXRP(deltaPays) ? false : (g < p);
153 auto first = noswap ? deltaGets : deltaPays;
154 auto second = noswap ? deltaPays : deltaGets;
157 if (second == beast::kZero)
160 auto const rate = divide(first, second, xrpl::noIssue());
162 if (first < beast::kZero)
165 if (second < beast::kZero)
168 auto const key = noswap ? (g +
'|' + p) : (p +
'|' + g);
169 if (tally_.contains(key)) {
170 auto& entry = tally_.at(key);
172 entry.sideAVolume += first;
173 entry.sideBVolume += second;
175 if (entry.highRate < rate)
176 entry.highRate = rate;
178 if (entry.lowRate > rate)
179 entry.lowRate = rate;
181 entry.closeRate = rate;
182 entry.domain = domain;
185 .sideAVolume = first,
186 .sideBVolume = second,
197 handleBookChange(data::TransactionAndMetadata
const& blob)
200 if (!tx || !meta || !tx->isFieldPresent(xrpl::sfTransactionType))
203 offerCancel_ = shouldCancelOffer(tx);
204 for (
auto const& node : meta->getFieldArray(xrpl::sfAffectedNodes))
205 handleAffectedNode(node);
208 static std::optional<uint32_t>
209 shouldCancelOffer(std::shared_ptr<xrpl::STTx const>
const& tx)
211 switch (tx->getFieldU16(xrpl::sfTransactionType)) {
214 case xrpl::ttOFFER_CANCEL:
215 case xrpl::ttOFFER_CREATE:
216 if (tx->isFieldPresent(xrpl::sfOfferSequence))
217 return tx->getFieldU32(xrpl::sfOfferSequence);
235 auto amountStr = [](xrpl::STAmount
const& amount) -> std::string {
236 return isXRP(amount) ? to_string(amount.xrp()) : to_string(amount.iou());
239 auto currencyStr = [](xrpl::STAmount
const& amount) -> std::string {
240 return isXRP(amount) ?
"XRP_drops" : to_string(amount.get<xrpl::Issue>());
244 {JS(currency_a), currencyStr(change.sideAVolume)},
245 {JS(currency_b), currencyStr(change.sideBVolume)},
246 {JS(volume_a), amountStr(change.sideAVolume)},
247 {JS(volume_b), amountStr(change.sideBVolume)},
248 {JS(high), to_string(change.highRate.iou())},
249 {JS(low), to_string(change.lowRate.iou())},
250 {JS(open), to_string(change.openRate.iou())},
251 {JS(close), to_string(change.closeRate.iou())},
254 if (change.domain.has_value())
255 jv.as_object()[JS(domain)] = xrpl::to_string(*change.domain);
void tag_invoke(boost::json::value_from_tag, boost::json::value &jv, BookChange const &change)
Implementation of value_from for BookChange type.
Definition BookChangesHelper.hpp:233