59 ripple::STAmount sideAVolume;
60 ripple::STAmount sideBVolume;
61 ripple::STAmount highRate;
62 ripple::STAmount lowRate;
63 ripple::STAmount openRate;
64 ripple::STAmount closeRate;
65 std::optional<ripple::uint256> domain;
81 [[nodiscard]]
static std::vector<BookChange>
82 compute(std::vector<data::TransactionAndMetadata>
const& transactions)
84 return HandlerImpl{}(transactions);
88 class HandlerImpl final {
89 std::map<std::string, BookChange> tally_;
90 std::optional<uint32_t> offerCancel_;
93 [[nodiscard]] std::vector<BookChange>
94 operator()(std::vector<data::TransactionAndMetadata>
const& transactions)
96 for (
auto const& tx : transactions)
100 std::vector<BookChange> changes;
102 std::make_move_iterator(std::begin(tally_)),
103 std::make_move_iterator(std::end(tally_)),
104 std::back_inserter(changes),
105 [](
auto obj) {
return obj.second; }
112 handleAffectedNode(ripple::STObject
const& node)
114 auto const& metaType = node.getFName();
115 auto const nodeType = node.getFieldU16(ripple::sfLedgerEntryType);
119 if (nodeType != ripple::ltOFFER || metaType == ripple::sfCreatedNode)
125 if (!node.isFieldPresent(ripple::sfFinalFields) || !node.isFieldPresent(ripple::sfPreviousFields))
128 auto const& finalFields = node.peekAtField(ripple::sfFinalFields).downcast<ripple::STObject>();
129 auto const& previousFields = node.peekAtField(ripple::sfPreviousFields).downcast<ripple::STObject>();
132 if (!finalFields.isFieldPresent(ripple::sfTakerGets) || !finalFields.isFieldPresent(ripple::sfTakerPays) ||
133 !previousFields.isFieldPresent(ripple::sfTakerGets) ||
134 !previousFields.isFieldPresent(ripple::sfTakerPays))
138 if (metaType == ripple::sfDeletedNode && offerCancel_ &&
139 finalFields.getFieldU32(ripple::sfSequence) == *offerCancel_)
144 auto const deltaGets =
145 finalFields.getFieldAmount(ripple::sfTakerGets) - previousFields.getFieldAmount(ripple::sfTakerGets);
146 auto const deltaPays =
147 finalFields.getFieldAmount(ripple::sfTakerPays) - previousFields.getFieldAmount(ripple::sfTakerPays);
149 transformAndStore(deltaGets, deltaPays, finalFields[~ripple::sfDomainID]);
154 ripple::STAmount
const& deltaGets,
155 ripple::STAmount
const& deltaPays,
156 std::optional<ripple::uint256>
const& domain
159 auto const g = to_string(deltaGets.issue());
160 auto const p = to_string(deltaPays.issue());
162 auto const noswap = [&]() {
163 if (isXRP(deltaGets))
165 return isXRP(deltaPays) ? false : (g < p);
168 auto first = noswap ? deltaGets : deltaPays;
169 auto second = noswap ? deltaPays : deltaGets;
172 if (second == beast::zero)
175 auto const rate = divide(first, second, ripple::noIssue());
177 if (first < beast::zero)
180 if (second < beast::zero)
183 auto const key = noswap ? (g +
'|' + p) : (p +
'|' + g);
184 if (tally_.contains(key)) {
185 auto& entry = tally_.at(key);
187 entry.sideAVolume += first;
188 entry.sideBVolume += second;
190 if (entry.highRate < rate)
191 entry.highRate = rate;
193 if (entry.lowRate > rate)
194 entry.lowRate = rate;
196 entry.closeRate = rate;
197 entry.domain = domain;
200 .sideAVolume = first,
201 .sideBVolume = second,
215 if (!tx || !meta || !tx->isFieldPresent(ripple::sfTransactionType))
218 offerCancel_ = shouldCancelOffer(tx);
219 for (
auto const& node : meta->getFieldArray(ripple::sfAffectedNodes))
220 handleAffectedNode(node);
223 static std::optional<uint32_t>
224 shouldCancelOffer(std::shared_ptr<ripple::STTx const>
const& tx)
226 switch (tx->getFieldU16(ripple::sfTransactionType)) {
229 case ripple::ttOFFER_CANCEL:
230 case ripple::ttOFFER_CREATE:
231 if (tx->isFieldPresent(ripple::sfOfferSequence))
232 return tx->getFieldU32(ripple::sfOfferSequence);
248tag_invoke(boost::json::value_from_tag, boost::json::value& jv,
BookChange const& change)
250 auto amountStr = [](ripple::STAmount
const& amount) -> std::string {
251 return isXRP(amount) ? to_string(amount.xrp()) : to_string(amount.iou());
254 auto currencyStr = [](ripple::STAmount
const& amount) -> std::string {
255 return isXRP(amount) ?
"XRP_drops" : to_string(amount.issue());
259 {JS(currency_a), currencyStr(change.sideAVolume)},
260 {JS(currency_b), currencyStr(change.sideBVolume)},
261 {JS(volume_a), amountStr(change.sideAVolume)},
262 {JS(volume_b), amountStr(change.sideBVolume)},
263 {JS(high), to_string(change.highRate.iou())},
264 {JS(low), to_string(change.lowRate.iou())},
265 {JS(open), to_string(change.openRate.iou())},
266 {JS(close), to_string(change.closeRate.iou())},
269 if (change.domain.has_value())
270 jv.as_object()[JS(domain)] = ripple::to_string(*change.domain);
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:209