From 3db69ce5e8c0841b5cd63be14a8348c0535c1eee Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Mon, 10 Aug 2026 11:43:52 -0300 Subject: [PATCH] fix(amm): avoid redundant output holding signatures --- modules/amm/ffi/src/api/request.rs | 6 ++ modules/amm/ffi/src/api/swap.rs | 109 +++++++++++++++++++++++++++- modules/amm/ffi/src/api/tests.rs | 3 + modules/amm/src/amm_module_impl.cpp | 4 + programs/amm/src/swap.rs | 4 +- 5 files changed, 121 insertions(+), 5 deletions(-) diff --git a/modules/amm/ffi/src/api/request.rs b/modules/amm/ffi/src/api/request.rs index 3d4c4d8..3f0f464 100644 --- a/modules/amm/ffi/src/api/request.rs +++ b/modules/amm/ffi/src/api/request.rs @@ -108,6 +108,9 @@ pub struct SwapExactInPlanRequest { pub config: AccountRead, pub user_input_holding_id: String, pub user_output_holding_id: String, + /// Current read of the output holding. The plan uses its owner to avoid + /// requesting a signature for an already initialized Token holding. + pub user_output_holding: AccountRead, pub amount_in: String, pub min_out: String, pub deadline_ms: String, @@ -126,6 +129,9 @@ pub struct SwapExactOutPlanRequest { pub config: AccountRead, pub user_input_holding_id: String, pub user_output_holding_id: String, + /// Current read of the output holding. The plan uses its owner to avoid + /// requesting a signature for an already initialized Token holding. + pub user_output_holding: AccountRead, pub amount_out: String, pub max_in: String, pub deadline_ms: String, diff --git a/modules/amm/ffi/src/api/swap.rs b/modules/amm/ffi/src/api/swap.rs index d2bbed8..52159dc 100644 --- a/modules/amm/ffi/src/api/swap.rs +++ b/modules/amm/ffi/src/api/swap.rs @@ -7,7 +7,7 @@ use amm_core::{ compute_pool_pda, mul_div_ceil, mul_div_floor, price_impact_bps, swap_exact_in_amounts, swap_exact_out_amounts, PoolDefinition, FEE_BPS_DENOMINATOR, }; -use nssa_core::account::AccountId; +use nssa_core::{account::AccountId, program::ProgramId}; use risc0_binfmt::ProgramBinary; use serde_json::{json, Value}; @@ -18,8 +18,20 @@ use super::{ }; use crate::account::{ account_id_from_hex, account_id_hex, decode_account, parse_program_id, program_id_bytes, + AccountRead, }; +fn output_holding_requires_signature( + read: &AccountRead, + expected_id: AccountId, + token_program_id: ProgramId, +) -> bool { + let Ok((account_id, account)) = decode_account(read) else { + return true; + }; + account_id != expected_id || account.program_owner != token_program_id +} + /// Orders `(token_in, token_out)` into the pool's canonical `(token_a, token_b)` /// so derived vault PDAs line up with the pool's stored `vault_a`/`vault_b`. fn canonical_pair(token_in: AccountId, token_out: AccountId) -> (AccountId, AccountId) { @@ -330,7 +342,21 @@ pub(super) fn swap_exact_in_plan(request: SwapExactInPlanRequest) -> Result Result