@@ -16,7 +16,8 @@ use cw_utils::one_coin;
16
16
use skip:: {
17
17
asset:: { get_current_asset_available, Asset } ,
18
18
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 ,
20
21
SimulateSwapExactAssetInResponse , SimulateSwapExactAssetOutResponse , SwapOperation ,
21
22
} ,
22
23
} ;
@@ -277,6 +278,28 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> ContractResult<Binary> {
277
278
swap_operations,
278
279
include_spot_price,
279
280
) ?) ,
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
+ }
280
303
}
281
304
. map_err ( From :: from)
282
305
}
@@ -325,6 +348,16 @@ fn query_simulate_swap_exact_asset_out(
325
348
Ok ( asset_in)
326
349
}
327
350
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
+
328
361
// Queries the astroport pool contracts to simulate a swap exact amount in with metadata
329
362
fn query_simulate_swap_exact_asset_in_with_metadata (
330
363
deps : Deps ,
@@ -425,6 +458,33 @@ fn query_simulate_swap_exact_asset_out_with_metadata(
425
458
Ok ( response)
426
459
}
427
460
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
+
428
488
fn assert_max_spread ( return_amount : Uint128 , spread_amount : Uint128 ) -> ContractResult < ( ) > {
429
489
let max_spread = MAX_ALLOWED_SLIPPAGE . parse :: < Decimal > ( ) ?;
430
490
if Decimal :: from_ratio ( spread_amount, return_amount + spread_amount) > max_spread {
@@ -515,6 +575,58 @@ fn simulate_swap_exact_asset_out(
515
575
Ok ( ( asset_in, responses) )
516
576
}
517
577
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
+
518
630
// Calculate the spot price using simulation responses
519
631
fn calculate_spot_price_from_simulation_responses (
520
632
deps : Deps ,
0 commit comments