Skip to content

Commit 6a58194

Browse files
authored
Implement SmartSwapExactAssetIn queries (#113)
* implement SimulateSmartSwapExactAssetIn and SimulateSmartSwapExactAssetInWithMetadata for the hallswap and osmosis adapters * clippy * implement smart swap in simulations for all adapters
1 parent ce53425 commit 6a58194

File tree

7 files changed

+557
-31
lines changed

7 files changed

+557
-31
lines changed

contracts/adapters/swap/astroport/src/contract.rs

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ use cw_utils::one_coin;
1616
use skip::{
1717
asset::{get_current_asset_available, Asset},
1818
swap::{
19-
execute_transfer_funds_back, Cw20HookMsg, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg,
19+
execute_transfer_funds_back, get_ask_denom_for_routes, Cw20HookMsg, ExecuteMsg,
20+
InstantiateMsg, MigrateMsg, QueryMsg, Route, SimulateSmartSwapExactAssetInResponse,
2021
SimulateSwapExactAssetInResponse, SimulateSwapExactAssetOutResponse, SwapOperation,
2122
},
2223
};
@@ -277,6 +278,28 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> ContractResult<Binary> {
277278
swap_operations,
278279
include_spot_price,
279280
)?),
281+
QueryMsg::SimulateSmartSwapExactAssetIn { routes, .. } => {
282+
let ask_denom = get_ask_denom_for_routes(&routes)?;
283+
284+
to_json_binary(&query_simulate_smart_swap_exact_asset_in(
285+
deps, ask_denom, routes,
286+
)?)
287+
}
288+
QueryMsg::SimulateSmartSwapExactAssetInWithMetadata {
289+
asset_in,
290+
routes,
291+
include_spot_price,
292+
} => {
293+
let ask_denom = get_ask_denom_for_routes(&routes)?;
294+
295+
to_json_binary(&query_simulate_smart_swap_exact_asset_in_with_metadata(
296+
deps,
297+
asset_in,
298+
ask_denom,
299+
routes,
300+
include_spot_price,
301+
)?)
302+
}
280303
}
281304
.map_err(From::from)
282305
}
@@ -325,6 +348,16 @@ fn query_simulate_swap_exact_asset_out(
325348
Ok(asset_in)
326349
}
327350

351+
fn query_simulate_smart_swap_exact_asset_in(
352+
deps: Deps,
353+
ask_denom: String,
354+
routes: Vec<Route>,
355+
) -> ContractResult<Asset> {
356+
let (asset_out, _) = simulate_smart_swap_exact_asset_in(deps, ask_denom, routes, false)?;
357+
358+
Ok(asset_out)
359+
}
360+
328361
// Queries the astroport pool contracts to simulate a swap exact amount in with metadata
329362
fn query_simulate_swap_exact_asset_in_with_metadata(
330363
deps: Deps,
@@ -425,6 +458,33 @@ fn query_simulate_swap_exact_asset_out_with_metadata(
425458
Ok(response)
426459
}
427460

461+
fn query_simulate_smart_swap_exact_asset_in_with_metadata(
462+
deps: Deps,
463+
asset_in: Asset,
464+
ask_denom: String,
465+
routes: Vec<Route>,
466+
include_spot_price: bool,
467+
) -> ContractResult<SimulateSmartSwapExactAssetInResponse> {
468+
let (asset_out, simulation_responses) =
469+
simulate_smart_swap_exact_asset_in(deps, ask_denom, routes.clone(), include_spot_price)?;
470+
471+
let mut response = SimulateSmartSwapExactAssetInResponse {
472+
asset_out,
473+
spot_price: None,
474+
};
475+
476+
if include_spot_price {
477+
response.spot_price = Some(calculate_weighted_spot_price_from_simulation_responses(
478+
deps,
479+
asset_in,
480+
routes,
481+
simulation_responses,
482+
)?)
483+
}
484+
485+
Ok(response)
486+
}
487+
428488
fn assert_max_spread(return_amount: Uint128, spread_amount: Uint128) -> ContractResult<()> {
429489
let max_spread = MAX_ALLOWED_SLIPPAGE.parse::<Decimal>()?;
430490
if Decimal::from_ratio(spread_amount, return_amount + spread_amount) > max_spread {
@@ -515,6 +575,58 @@ fn simulate_swap_exact_asset_out(
515575
Ok((asset_in, responses))
516576
}
517577

578+
fn simulate_smart_swap_exact_asset_in(
579+
deps: Deps,
580+
ask_denom: String,
581+
routes: Vec<Route>,
582+
include_responses: bool,
583+
) -> ContractResult<(Asset, Vec<Vec<SimulationResponse>>)> {
584+
let mut asset_out = Asset::new(deps.api, &ask_denom, Uint128::zero());
585+
let mut simulation_responses = Vec::new();
586+
587+
for route in &routes {
588+
let (route_asset_out, route_simulation_responses) = simulate_swap_exact_asset_in(
589+
deps,
590+
route.offer_asset.clone(),
591+
route.operations.clone(),
592+
include_responses,
593+
)?;
594+
595+
asset_out.add(route_asset_out.amount())?;
596+
597+
if include_responses {
598+
simulation_responses.push(route_simulation_responses);
599+
}
600+
}
601+
602+
Ok((asset_out, simulation_responses))
603+
}
604+
605+
fn calculate_weighted_spot_price_from_simulation_responses(
606+
deps: Deps,
607+
asset_in: Asset,
608+
routes: Vec<Route>,
609+
simulation_responses: Vec<Vec<SimulationResponse>>,
610+
) -> ContractResult<Decimal> {
611+
let spot_price = routes.into_iter().zip(simulation_responses).try_fold(
612+
Decimal::zero(),
613+
|curr_spot_price, (route, res)| -> ContractResult<Decimal> {
614+
let route_spot_price = calculate_spot_price_from_simulation_responses(
615+
deps,
616+
asset_in.clone(),
617+
route.operations,
618+
res,
619+
)?;
620+
621+
let weight = Decimal::from_ratio(route.offer_asset.amount(), asset_in.amount());
622+
623+
Ok(curr_spot_price + (route_spot_price * weight))
624+
},
625+
)?;
626+
627+
Ok(spot_price)
628+
}
629+
518630
// Calculate the spot price using simulation responses
519631
fn calculate_spot_price_from_simulation_responses(
520632
deps: Deps,

contracts/adapters/swap/dexter/src/contract.rs

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ use dexter::{
1919
use skip::{
2020
asset::Asset,
2121
swap::{
22-
execute_transfer_funds_back, Cw20HookMsg, DexterAdapterInstantiateMsg, ExecuteMsg,
23-
MigrateMsg, QueryMsg, SimulateSwapExactAssetInResponse, SimulateSwapExactAssetOutResponse,
24-
SwapOperation,
22+
execute_transfer_funds_back, get_ask_denom_for_routes, Cw20HookMsg,
23+
DexterAdapterInstantiateMsg, ExecuteMsg, MigrateMsg, QueryMsg, Route,
24+
SimulateSmartSwapExactAssetInResponse, SimulateSwapExactAssetInResponse,
25+
SimulateSwapExactAssetOutResponse, SwapOperation,
2526
},
2627
};
2728

@@ -265,6 +266,28 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> ContractResult<Binary> {
265266
swap_operations,
266267
include_spot_price,
267268
)?),
269+
QueryMsg::SimulateSmartSwapExactAssetIn { routes, .. } => {
270+
let ask_denom = get_ask_denom_for_routes(&routes)?;
271+
272+
to_json_binary(&query_simulate_smart_swap_exact_asset_in(
273+
deps, ask_denom, routes,
274+
)?)
275+
}
276+
QueryMsg::SimulateSmartSwapExactAssetInWithMetadata {
277+
routes,
278+
asset_in,
279+
include_spot_price,
280+
} => {
281+
let ask_denom = get_ask_denom_for_routes(&routes)?;
282+
283+
to_json_binary(&query_simulate_smart_swap_exact_asset_in_with_metadata(
284+
deps,
285+
asset_in,
286+
ask_denom,
287+
routes,
288+
include_spot_price,
289+
)?)
290+
}
268291
}
269292
.map_err(From::from)
270293
}
@@ -313,6 +336,14 @@ fn query_simulate_swap_exact_asset_out(
313336
Ok(asset_in)
314337
}
315338

339+
fn query_simulate_smart_swap_exact_asset_in(
340+
deps: Deps,
341+
ask_denom: String,
342+
routes: Vec<Route>,
343+
) -> ContractResult<Asset> {
344+
simulate_smart_swap_exact_asset_in(deps, ask_denom, routes)
345+
}
346+
316347
// Queries the dexter pool contracts to simulate a swap exact amount in with metadata
317348
fn query_simulate_swap_exact_asset_in_with_metadata(
318349
deps: Deps,
@@ -383,6 +414,27 @@ fn query_simulate_swap_exact_asset_out_with_metadata(
383414
Ok(response)
384415
}
385416

417+
fn query_simulate_smart_swap_exact_asset_in_with_metadata(
418+
deps: Deps,
419+
asset_in: Asset,
420+
ask_denom: String,
421+
routes: Vec<Route>,
422+
include_spot_price: bool,
423+
) -> ContractResult<SimulateSmartSwapExactAssetInResponse> {
424+
let asset_out = simulate_smart_swap_exact_asset_in(deps, ask_denom, routes.clone())?;
425+
426+
let mut response = SimulateSmartSwapExactAssetInResponse {
427+
asset_out,
428+
spot_price: None,
429+
};
430+
431+
if include_spot_price {
432+
response.spot_price = Some(calculate_weighted_spot_price(deps, asset_in, routes)?)
433+
}
434+
435+
Ok(response)
436+
}
437+
386438
// Simulates a swap exact amount in request, returning the asset out and optionally the reverse simulation responses
387439
fn simulate_swap_exact_asset_in(
388440
deps: Deps,
@@ -475,6 +527,26 @@ fn simulate_swap_exact_asset_out(
475527
}
476528
}
477529

530+
fn simulate_smart_swap_exact_asset_in(
531+
deps: Deps,
532+
ask_denom: String,
533+
routes: Vec<Route>,
534+
) -> ContractResult<Asset> {
535+
let mut asset_out = Asset::new(deps.api, &ask_denom, Uint128::zero());
536+
537+
for route in &routes {
538+
let route_asset_out = simulate_swap_exact_asset_in(
539+
deps,
540+
route.offer_asset.clone(),
541+
route.operations.clone(),
542+
)?;
543+
544+
asset_out.add(route_asset_out.amount())?;
545+
}
546+
547+
Ok(asset_out)
548+
}
549+
478550
// find spot prices for all the pools in the swap operations
479551
fn calculate_spot_price(
480552
deps: Deps,
@@ -508,3 +580,22 @@ fn calculate_spot_price(
508580

509581
Ok(final_price)
510582
}
583+
584+
fn calculate_weighted_spot_price(
585+
deps: Deps,
586+
asset_in: Asset,
587+
routes: Vec<Route>,
588+
) -> ContractResult<Decimal> {
589+
let spot_price = routes.into_iter().try_fold(
590+
Decimal::zero(),
591+
|curr_spot_price, route| -> ContractResult<Decimal> {
592+
let route_spot_price = calculate_spot_price(deps, route.operations)?;
593+
594+
let weight = Decimal::from_ratio(route.offer_asset.amount(), asset_in.amount());
595+
596+
Ok(curr_spot_price + (route_spot_price * weight))
597+
},
598+
)?;
599+
600+
Ok(spot_price)
601+
}

0 commit comments

Comments
 (0)