#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace xrpl { template AMMOffer::AMMOffer( AMMLiquidity const& ammLiquidity, TAmounts const& amounts, TAmounts const& balances, Quality const& quality) : ammLiquidity_(ammLiquidity), amounts_(amounts), balances_(balances), quality_(quality) { } template Asset const& AMMOffer::assetIn() const { return ammLiquidity_.assetIn(); } template Asset const& AMMOffer::assetOut() const { return ammLiquidity_.assetOut(); } template AccountID const& AMMOffer::owner() const { return ammLiquidity_.ammAccount(); } template TAmounts const& AMMOffer::amount() const { return amounts_; } template void AMMOffer::consume(ApplyView& view, TAmounts const& consumed) { // Consumed offer must be less or equal to the original if (consumed.in > amounts_.in || consumed.out > amounts_.out) Throw("Invalid consumed AMM offer."); // AMM pool is updated when the amounts are transferred // in BookStep::consumeOffer(). consumed_ = true; // Let the context know AMM offer is consumed ammLiquidity_.context().setAMMUsed(); } template TAmounts AMMOffer::limitOut( TAmounts const& offerAmount, TOut const& limit, bool roundUp) const { // Change the offer size proportionally to the original offer quality // to keep the strands quality order unchanged. The taker pays slightly // more for the offer in this case, which results in a slightly higher // pool product than the original pool product. I.e. if the original // pool is poolPays, poolGets and the offer is assetIn, assetOut then // poolPays * poolGets < (poolPays - assetOut) * (poolGets + assetIn) if (ammLiquidity_.multiPath()) { // It turns out that the ceil_out implementation has some slop in // it, which ceil_out_strict removes. return quality().ceilOutStrict(offerAmount, limit, roundUp); } // Change the offer size according to the conservation function. The offer // quality is increased in this case, but it doesn't matter since there is // only one path. return {swapAssetOut(balances_, limit, ammLiquidity_.tradingFee()), limit}; } template TAmounts AMMOffer::limitIn(TAmounts const& offerAmount, TIn const& limit, bool roundUp) const { // See the comments above in limitOut(). if (ammLiquidity_.multiPath()) { if (auto const& rules = getCurrentTransactionRules(); rules && rules->enabled(fixReducedOffersV2)) return quality().ceilInStrict(offerAmount, limit, roundUp); return quality().ceilIn(offerAmount, limit); } return {limit, swapAssetIn(balances_, limit, ammLiquidity_.tradingFee())}; } template QualityFunction AMMOffer::getQualityFunc() const { if (ammLiquidity_.multiPath()) return QualityFunction{quality(), QualityFunction::CLOBLikeTag{}}; return QualityFunction{balances_, ammLiquidity_.tradingFee(), QualityFunction::AMMTag{}}; } template bool AMMOffer::checkInvariant(TAmounts const& consumed, beast::Journal j) const { if (consumed.in > amounts_.in || consumed.out > amounts_.out) { JLOG(j.error()) << "AMMOffer::checkInvariant failed: consumed " << to_string(consumed.in) << " " << to_string(consumed.out) << " amounts " << to_string(amounts_.in) << " " << to_string(amounts_.out); return false; } Number const product = balances_.in * balances_.out; auto const newBalances = TAmounts{balances_.in + consumed.in, balances_.out - consumed.out}; Number const newProduct = newBalances.in * newBalances.out; if (newProduct >= product || withinRelativeDistance(product, newProduct, Number{1, -7})) return true; JLOG(j.error()) << "AMMOffer::checkInvariant failed: balances " << to_string(balances_.in) << " " << to_string(balances_.out) << " new balances " << to_string(newBalances.in) << " " << to_string(newBalances.out) << " product/newProduct " << product << " " << newProduct << " diff " << (product != Number{0} ? to_string((product - newProduct) / product) : "undefined"); return false; } template class AMMOffer; template class AMMOffer; template class AMMOffer; template class AMMOffer; template class AMMOffer; template class AMMOffer; template class AMMOffer; template class AMMOffer; } // namespace xrpl