#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace xrpl { template static auto finishFlow(PaymentSandbox& sb, Asset const& srcAsset, Asset const& dstAsset, FlowResult&& f) { path::RippleCalc::Output result; if (isTesSuccess(f.ter)) { f.sandbox->apply(sb); // NOLINT(bugprone-unchecked-optional-access) sandbox set on success } else { result.removableOffers = std::move(f.removableOffers); } result.setResult(f.ter); result.actualAmountIn = toSTAmount(f.in, srcAsset); result.actualAmountOut = toSTAmount(f.out, dstAsset); return result; }; path::RippleCalc::Output flow( PaymentSandbox& sb, STAmount const& deliver, AccountID const& src, AccountID const& dst, STPathSet const& paths, bool defaultPaths, bool partialPayment, bool ownerPaysTransferFee, OfferCrossing offerCrossing, std::optional const& limitQuality, std::optional const& sendMax, std::optional const& domainID, beast::Journal j, path::detail::FlowDebugInfo* flowDebugInfo) { Asset const srcAsset = [&]() -> Asset { if (sendMax) return sendMax->asset(); return deliver.asset().visit( [&](Issue const& issue) -> Asset { if (isXRP(issue)) return xrpIssue(); return Issue(issue.currency, src); }, [&](MPTIssue const&) { return deliver.asset(); }); }(); Asset const dstAsset = deliver.asset(); std::optional sendMaxAsset; if (sendMax) sendMaxAsset = sendMax->asset(); AMMContext ammContext(src, false); // convert the paths to a collection of strands. Each strand is the // collection of account->account steps and book steps that may be used in // this payment. auto [toStrandsTer, strands] = toStrands( sb, src, dst, dstAsset, limitQuality, sendMaxAsset, paths, defaultPaths, ownerPaysTransferFee, offerCrossing, ammContext, domainID, j); if (!isTesSuccess(toStrandsTer)) { path::RippleCalc::Output result; result.setResult(toStrandsTer); return result; } ammContext.setMultiPath(strands.size() > 1); if (j.trace()) { j.trace() << "\nsrc: " << src << "\ndst: " << dst << "\nsrcAsset: " << srcAsset << "\ndstAsset: " << dstAsset; j.trace() << "\nNumStrands: " << strands.size(); for (auto const& curStrand : strands) { j.trace() << "NumSteps: " << curStrand.size(); for (auto const& step : curStrand) { j.trace() << '\n' << *step << '\n'; } } } // The src account may send either xrp,iou,or mpt. The dst account may // receive either xrp,iou, or mpt. Since XRP, IOU, and MPT amounts are // represented by different types, use templates to tell `flow` about the // amount types. return std::visit( [&, &strands = strands](TIn const&, TOut const&) { using TIn_ = typename TIn::amount_type; using TOut_ = typename TOut::amount_type; return finishFlow( sb, srcAsset, dstAsset, flow( sb, strands, get(deliver), partialPayment, offerCrossing, limitQuality, sendMax, j, ammContext, flowDebugInfo)); }, srcAsset.getAmountType(), dstAsset.getAmountType()); } } // namespace xrpl