diff --git a/contracts/adapters/swap/astroport/src/contract.rs b/contracts/adapters/swap/astroport/src/contract.rs index c89f09a6..6e594a17 100644 --- a/contracts/adapters/swap/astroport/src/contract.rs +++ b/contracts/adapters/swap/astroport/src/contract.rs @@ -4,10 +4,11 @@ use crate::{ }; use astroport::{ asset::{Asset, AssetInfo}, - pair::{QueryMsg as PairQueryMsg, ReverseSimulationResponse, MAX_ALLOWED_SLIPPAGE}, - router::{ - ExecuteMsg as RouterExecuteMsg, QueryMsg as RouterQueryMsg, SimulateSwapOperationsResponse, + pair::{ + QueryMsg as PairQueryMsg, ReverseSimulationResponse, SimulationResponse, + MAX_ALLOWED_SLIPPAGE, }, + router::ExecuteMsg as RouterExecuteMsg, }; use cosmwasm_std::{ entry_point, to_binary, Addr, Binary, Coin, Decimal, Deps, DepsMut, Env, MessageInfo, Response, @@ -181,7 +182,7 @@ fn query_simulate_swap_exact_coin_in( swap_operations: Vec, ) -> ContractResult { // Error if swap operations is empty - let (Some(first_op), Some(last_op)) = (swap_operations.first(), swap_operations.last()) else { + let Some(first_op) = swap_operations.first() else { return Err(ContractError::SwapOperationsEmpty); }; @@ -190,29 +191,37 @@ fn query_simulate_swap_exact_coin_in( return Err(ContractError::CoinInDenomMismatch); } - // Get the router contract address - let router_contract_address = ROUTER_CONTRACT_ADDRESS.load(deps.storage)?; - - // Get denom out from last swap operation - let denom_out = last_op.denom_out.clone(); + // Iterate through the swap operations, querying the astroport pool contracts to get the coin out + // for each swap operation, and then updating the coin out for the next swap operation until the + // coin out for the last swap operation is found. + let coin_out = swap_operations.iter().try_fold( + coin_in, + |coin_out, operation| -> Result<_, ContractError> { + let res: SimulationResponse = deps.querier.query_wasm_smart( + &operation.pool, + &PairQueryMsg::Simulation { + offer_asset: Asset { + info: AssetInfo::NativeToken { + denom: coin_out.denom, + }, + amount: coin_out.amount, + }, + ask_asset_info: None, + }, + )?; - // Convert the swap operations to astroport swap operations - let astroport_swap_operations = swap_operations.into_iter().map(From::from).collect(); + // Assert the operation does not exceed the max spread limit + assert_max_spread(res.return_amount, res.spread_amount)?; - // Query the astroport router contract to simulate the swap operations - let res: SimulateSwapOperationsResponse = deps.querier.query_wasm_smart( - router_contract_address, - &RouterQueryMsg::SimulateSwapOperations { - offer_amount: coin_in.amount, - operations: astroport_swap_operations, + Ok(Coin { + denom: operation.denom_out.clone(), + amount: res.return_amount, + }) }, )?; // Return the coin out - Ok(Coin { - denom: denom_out, - amount: res.amount, - }) + Ok(coin_out) } // Queries the astroport pool contracts to simulate a multi-hop swap exact amount out