From 2d8d3c7cfbf902624a95e99fe754b5aac20f467e Mon Sep 17 00:00:00 2001 From: Supanat Potiwarakorn Date: Mon, 7 Oct 2024 14:10:07 +0700 Subject: [PATCH] integration test for asset group limiter --- .../src/test/cases/units/swap/mod.rs | 17 +-- .../swap/swap_with_asset_group_limiters.rs | 100 ++++++++++++++++++ 2 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 contracts/transmuter/src/test/cases/units/swap/swap_with_asset_group_limiters.rs diff --git a/contracts/transmuter/src/test/cases/units/swap/mod.rs b/contracts/transmuter/src/test/cases/units/swap/mod.rs index ed93f62..bd954e7 100644 --- a/contracts/transmuter/src/test/cases/units/swap/mod.rs +++ b/contracts/transmuter/src/test/cases/units/swap/mod.rs @@ -27,14 +27,14 @@ macro_rules! test_swap { #[test] fn $test_name() { let app = osmosis_test_tube::OsmosisTestApp::new(); - test_swap_success_case($setup(&app), $msg, $received); + test_swap_success_case(&$setup(&app), $msg, $received); } }; ($test_name:ident [expect error] { setup = $setup:ident, msg = $msg:expr, err = $err:expr }) => { #[test] fn $test_name() { let app = osmosis_test_tube::OsmosisTestApp::new(); - test_swap_failed_case($setup(&app), $msg, $err); + test_swap_failed_case(&$setup(&app), $msg, $err); } }; ($test_name:ident [expect ok] { setup = $setup:expr, msgs = $msgs:expr, received = $received:expr }) => { @@ -42,7 +42,7 @@ macro_rules! test_swap { fn $test_name() { for msg in $msgs { let app = osmosis_test_tube::OsmosisTestApp::new(); - test_swap_success_case($setup(&app), msg, $received); + test_swap_success_case(&$setup(&app), msg, $received); } } }; @@ -51,7 +51,7 @@ macro_rules! test_swap { fn $test_name() { for msg in $msgs { let app = osmosis_test_tube::OsmosisTestApp::new(); - test_swap_failed_case($setup(&app), msg, $err); + test_swap_failed_case(&$setup(&app), msg, $err); } } }; @@ -71,7 +71,7 @@ pub enum SwapMsg { }, } -fn assert_invariants(t: TestEnv, act: impl FnOnce(&TestEnv) -> String) { +fn assert_invariants(t: &TestEnv, act: impl FnOnce(&TestEnv) -> String) { // store previous shares and pool assets let prev_shares = t .contract @@ -159,7 +159,7 @@ fn lcm_normalization_factor(configs: &[AssetConfig]) -> Uint128 { lcm_from_iter(norm_factors).unwrap() } -fn test_swap_success_case(t: TestEnv, msg: SwapMsg, received: Coin) { +fn test_swap_success_case(t: &TestEnv, msg: SwapMsg, received: Coin) { assert_invariants(t, move |t| { let cp = CosmwasmPool::new(t.app); let bank = Bank::new(t.app); @@ -422,7 +422,7 @@ pub fn test_swap_share_denom_success_case(t: &TestEnv, msg: SwapMsg, sent: Coin, ); } -fn test_swap_failed_case(t: TestEnv, msg: SwapMsg, err: ContractError) { +fn test_swap_failed_case(t: &TestEnv, msg: SwapMsg, err: ContractError) { assert_invariants(t, move |t| { let cp = CosmwasmPool::new(t.app); @@ -488,6 +488,7 @@ fn pool_with_single_lp( .collect::>(); let t = TestEnvBuilder::new() + .with_account("admin", non_zero_pool_assets.clone()) .with_account("provider", non_zero_pool_assets.clone()) .with_account( SWAPPER, @@ -531,3 +532,5 @@ fn pool_with_single_lp( mod client_error; mod non_empty_pool; mod swap_share_denom; + +mod swap_with_asset_group_limiters; diff --git a/contracts/transmuter/src/test/cases/units/swap/swap_with_asset_group_limiters.rs b/contracts/transmuter/src/test/cases/units/swap/swap_with_asset_group_limiters.rs new file mode 100644 index 0000000..1842b75 --- /dev/null +++ b/contracts/transmuter/src/test/cases/units/swap/swap_with_asset_group_limiters.rs @@ -0,0 +1,100 @@ +use cosmwasm_std::{Coin, Decimal, Uint128, Uint64}; + +use crate::{ + asset::AssetConfig, + contract::sv::ExecMsg, + limiter::{LimiterParams, WindowConfig}, + scope::Scope, + ContractError, +}; + +use super::{pool_with_single_lp, test_swap_failed_case, test_swap_success_case, SwapMsg}; + +const REMAINING_DENOM0: u128 = 1_000_000_000_000; +const REMAINING_DENOM1: u128 = 1_000_000_000_000; +const REMAINING_DENOM2: u128 = 1_000_000_000_000; + +#[test] +fn test_swap_with_asset_group_limiters() { + let app = osmosis_test_tube::OsmosisTestApp::new(); + let t = pool_with_single_lp( + &app, + vec![ + Coin::new(REMAINING_DENOM0, "denom0"), + Coin::new(REMAINING_DENOM1, "denom1"), + Coin::new(REMAINING_DENOM2, "denom2"), + ], + vec![ + AssetConfig { + denom: "denom0".to_string(), + normalization_factor: Uint128::one(), + }, + AssetConfig { + denom: "denom1".to_string(), + normalization_factor: Uint128::one(), + }, + AssetConfig { + denom: "denom2".to_string(), + normalization_factor: Uint128::one(), + }, + ], + ); + + // Add asset group and limiters + t.contract + .execute( + &ExecMsg::CreateAssetGroup { + label: "group1".to_string(), + denoms: vec!["denom0".to_string(), "denom1".to_string()], + }, + &[], + &t.accounts["admin"], + ) + .unwrap(); + + t.contract + .execute( + &ExecMsg::RegisterLimiter { + scope: Scope::asset_group("group1"), + label: "limiter1".to_string(), + limiter_params: LimiterParams::ChangeLimiter { + window_config: WindowConfig { + window_size: Uint64::from(1000u64), + division_count: Uint64::from(5u64), + }, + boundary_offset: Decimal::percent(10), + }, + }, + &[], + &t.accounts["admin"], + ) + .unwrap(); + + // swap within group, even an agressive one wouldn't effect anything + test_swap_success_case( + &t, + SwapMsg::SwapExactAmountOut { + token_in_denom: "denom0".to_string(), + token_in_max_amount: Uint128::from(REMAINING_DENOM1), + token_out: Coin::new(REMAINING_DENOM1, "denom1".to_string()), + }, + Coin::new(REMAINING_DENOM1, "denom1".to_string()), + ); + + app.increase_time(5); + + // swap denom0 to denom2 -> increase group1 weight by adding more denom0 + test_swap_failed_case( + &t, + SwapMsg::SwapExactAmountOut { + token_in_denom: "denom0".to_string(), + token_in_max_amount: Uint128::from(REMAINING_DENOM0), + token_out: Coin::new(REMAINING_DENOM0, "denom2".to_string()), + }, + ContractError::UpperLimitExceeded { + scope: Scope::asset_group("group1"), + upper_limit: "0.766666666666666666".parse().unwrap(), + value: Decimal::percent(100), + }, + ); +}