80 [[nodiscard]]
static std::vector<BookChange>
81 compute(std::vector<data::TransactionAndMetadata>
const& transactions)
83 return HandlerImpl{}(transactions);
87 class HandlerImpl final {
88 std::map<std::string, BookChange> tally_;
89 std::optional<uint32_t> offerCancel_;
92 [[nodiscard]] std::vector<BookChange>
93 operator()(std::vector<data::TransactionAndMetadata>
const& transactions)
95 for (
auto const& tx : transactions)
99 std::vector<BookChange> changes;
101 std::make_move_iterator(std::begin(tally_)),
102 std::make_move_iterator(std::end(tally_)),
103 std::back_inserter(changes),
104 [](
auto obj) {
return obj.second; }
111 handleAffectedNode(ripple::STObject
const& node)
113 auto const& metaType = node.getFName();
114 auto const nodeType = node.getFieldU16(ripple::sfLedgerEntryType);
118 if (nodeType != ripple::ltOFFER || metaType == ripple::sfCreatedNode)
124 if (!node.isFieldPresent(ripple::sfFinalFields) || !node.isFieldPresent(ripple::sfPreviousFields))
127 auto const& finalFields = node.peekAtField(ripple::sfFinalFields).downcast<ripple::STObject>();
128 auto const& previousFields = node.peekAtField(ripple::sfPreviousFields).downcast<ripple::STObject>();
131 if (!finalFields.isFieldPresent(ripple::sfTakerGets) || !finalFields.isFieldPresent(ripple::sfTakerPays) ||
132 !previousFields.isFieldPresent(ripple::sfTakerGets) ||
133 !previousFields.isFieldPresent(ripple::sfTakerPays))
137 if (metaType == ripple::sfDeletedNode && offerCancel_ &&
138 finalFields.getFieldU32(ripple::sfSequence) == *offerCancel_)
143 auto const deltaGets =
144 finalFields.getFieldAmount(ripple::sfTakerGets) - previousFields.getFieldAmount(ripple::sfTakerGets);
145 auto const deltaPays =
146 finalFields.getFieldAmount(ripple::sfTakerPays) - previousFields.getFieldAmount(ripple::sfTakerPays);
148 transformAndStore(deltaGets, deltaPays);
152 transformAndStore(ripple::STAmount
const& deltaGets, ripple::STAmount
const& deltaPays)
154 auto const g = to_string(deltaGets.issue());
155 auto const p = to_string(deltaPays.issue());
157 auto const noswap = [&]() {
158 if (isXRP(deltaGets))
160 return isXRP(deltaPays) ? false : (g < p);
163 auto first = noswap ? deltaGets : deltaPays;
164 auto second = noswap ? deltaPays : deltaGets;
167 if (second == beast::zero)
170 auto const rate = divide(first, second, ripple::noIssue());
172 if (first < beast::zero)
175 if (second < beast::zero)
178 auto const key = noswap ? (g +
'|' + p) : (p +
'|' + g);
179 if (tally_.contains(key)) {
180 auto& entry = tally_.at(key);
182 entry.sideAVolume += first;
183 entry.sideBVolume += second;
185 if (entry.highRate < rate)
186 entry.highRate = rate;
188 if (entry.lowRate > rate)
189 entry.lowRate = rate;
191 entry.closeRate = rate;
194 .sideAVolume = first,
195 .sideBVolume = second,
208 if (!tx || !meta || !tx->isFieldPresent(ripple::sfTransactionType))
211 offerCancel_ = shouldCancelOffer(tx);
212 for (
auto const& node : meta->getFieldArray(ripple::sfAffectedNodes))
213 handleAffectedNode(node);
216 static std::optional<uint32_t>
217 shouldCancelOffer(std::shared_ptr<ripple::STTx const>
const& tx)
219 switch (tx->getFieldU16(ripple::sfTransactionType)) {
222 case ripple::ttOFFER_CANCEL:
223 case ripple::ttOFFER_CREATE:
224 if (tx->isFieldPresent(ripple::sfOfferSequence))
225 return tx->getFieldU32(ripple::sfOfferSequence);
241tag_invoke(boost::json::value_from_tag, boost::json::value& jv,
BookChange const& change)
243 auto amountStr = [](ripple::STAmount
const& amount) -> std::string {
244 return isXRP(amount) ? to_string(amount.xrp()) : to_string(amount.iou());
247 auto currencyStr = [](ripple::STAmount
const& amount) -> std::string {
248 return isXRP(amount) ?
"XRP_drops" : to_string(amount.issue());
252 {JS(currency_a), currencyStr(change.sideAVolume)},
253 {JS(currency_b), currencyStr(change.sideBVolume)},
254 {JS(volume_a), amountStr(change.sideAVolume)},
255 {JS(volume_b), amountStr(change.sideBVolume)},
256 {JS(high), to_string(change.highRate.iou())},
257 {JS(low), to_string(change.lowRate.iou())},
258 {JS(open), to_string(change.openRate.iou())},
259 {JS(close), to_string(change.closeRate.iou())},
std::pair< std::shared_ptr< ripple::STTx const >, std::shared_ptr< ripple::STObject const > > deserializeTxPlusMeta(data::TransactionAndMetadata const &blobs)
Deserialize a TransactionAndMetadata into a pair of STTx and STObject.
Definition RPCHelpers.cpp:207