From 37f28fe66391d3227ca5692cb01f54aecec5cb13 Mon Sep 17 00:00:00 2001 From: r4bbit <445106+0x-r4bbit@users.noreply.github.com> Date: Mon, 10 Aug 2026 11:03:16 +0200 Subject: [PATCH] feat(modules/amm): add_liquidity_quote takes slippage, returns minimumLpRaw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The add-liquidity quote now takes slippageBps and returns minimumLpRaw = floor(delta_lp * (10000 - slippage) / 10000) — the LP floor the submit passes as min_amount_liquidity, mirroring the swap quotes' minReceivedRaw. Computing it in Rust keeps the u128 slippage math out of the UI. Adds invalid_slippage (>= 100%) and minimum_lp_zero (slippage leaves no floor) errors; the module's addLiquidityQuote forwards slippageBps. --- modules/amm/ffi/src/api/liquidity.rs | 54 +++++++++++++++++++++++----- modules/amm/ffi/src/api/request.rs | 4 +++ modules/amm/src/amm_module_impl.cpp | 16 ++++++++- 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/modules/amm/ffi/src/api/liquidity.rs b/modules/amm/ffi/src/api/liquidity.rs index dd66126..61010d0 100644 --- a/modules/amm/ffi/src/api/liquidity.rs +++ b/modules/amm/ffi/src/api/liquidity.rs @@ -12,7 +12,8 @@ //! guest's `assert pool uninitialized`. use amm_core::{ - isqrt_product, mul_div_floor, spot_price_q64_64, PoolDefinition, MINIMUM_LIQUIDITY, + isqrt_product, mul_div_floor, spot_price_q64_64, PoolDefinition, FEE_BPS_DENOMINATOR, + MINIMUM_LIQUIDITY, }; use nssa_core::account::AccountId; use serde_json::{json, Value}; @@ -202,13 +203,14 @@ pub(super) fn create_pool_plan(request: CreatePoolPlanRequest) -> Result Result { let token_a = account_id_from_hex(&request.token_a_id, "token A id")?; let token_b = account_id_from_hex(&request.token_b_id, "token B id")?; @@ -217,6 +219,9 @@ pub(super) fn add_liquidity_quote(request: AddLiquidityQuoteRequest) -> Result= FEE_BPS_DENOMINATOR { + return Err(String::from("invalid_slippage")); + } // Decode the pool; absent / undecodable / empty ⇒ nothing to add to. let pool = hex::decode(&request.pool_data) @@ -258,6 +263,14 @@ pub(super) fn add_liquidity_quote(request: AddLiquidityQuoteRequest) -> Result Result() on a number_float THROWS, terminating the module), while a string / + // bool would otherwise fall through to a silent 0. A missing field defaults to 0 (no + // slippage). A negative or >= 100% value is likewise invalid_slippage. + const json slippage_val = request.value("slippageBps", json(0)); + if (!slippage_val.is_number_integer()) + return error("invalid_slippage"); + const int64_t slippage_bps = slippage_val.get(); + if (slippage_bps < 0 || slippage_bps >= 10000) + return error("invalid_slippage"); + const FfiResult quoteResult = call(amm_add_liquidity_quote, json{ {"tokenAId", token_a}, {"tokenBId", token_b}, {"maxAmountARaw", max_a_decimal}, {"maxAmountBRaw", max_b_decimal}, + {"slippageBps", slippage_bps}, {"poolData", pool_data}, }); if (!quoteResult.ok) return error(quoteResult.error.empty() ? "backend_error" : quoteResult.error); - // Success: wrap { amountARaw, amountBRaw, expectedLpRaw, priceRaw } in the envelope. + // Success: wrap { amountARaw, amountBRaw, expectedLpRaw, minimumLpRaw, priceRaw }. LogosMap out = quoteResult.value; out["status"] = "ok"; out["error"] = "";