From 930989d334e2026de39bd0129628fa0fded9143d Mon Sep 17 00:00:00 2001 From: Richard Vade Date: Thu, 15 Sep 2022 14:26:28 -0400 Subject: [PATCH 1/3] prevent duplicate denoms --- src/contract.rs | 32 ++++++++++++ src/error.rs | 3 ++ src/integration_test.rs | 105 +++++++++++++++++++++++++++++++--------- 3 files changed, 118 insertions(+), 22 deletions(-) diff --git a/src/contract.rs b/src/contract.rs index f5eafcb..d19dfd1 100644 --- a/src/contract.rs +++ b/src/contract.rs @@ -51,6 +51,8 @@ pub fn instantiate( }; TOKEN2.save(deps.storage, &token2)?; + prevent_duplicate_denoms(&msg.token1_denom.clone(), &msg.token2_denom.clone())?; + let owner = msg.owner.map(|h| deps.api.addr_validate(&h)).transpose()?; OWNER.save(deps.storage, &owner)?; @@ -391,6 +393,36 @@ fn validate_input_amount( } } +fn prevent_duplicate_denoms( + token1:&Denom, + token2:&Denom +) -> Result<(), ContractError> { + match token1 { + Denom::Cw20(token1_address) => { + match token2 { + Denom::Cw20(token2_address) => { + if token1_address.to_string() == token2_address.to_string() { + return Err(ContractError::DuplicateDenom {}); + } + Ok(()) + }, + Denom::Native(_) => Ok(()) + } + }, + Denom::Native(token1_denom) => { + match token2 { + Denom::Cw20(_) => Ok(()), + Denom::Native(token2_denom) => { + if token1_denom == token2_denom { + return Err(ContractError::DuplicateDenom {}); + } + Ok(()) + } + } + } + } +} + fn get_cw20_transfer_from_msg( owner: &Addr, recipient: &Addr, diff --git a/src/error.rs b/src/error.rs index 92439bf..55eafc8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -69,4 +69,7 @@ pub enum ContractError { #[error("Failed to instantiate lp token")] InstantiateLpTokenError {}, + + #[error("Duplicate denom is not allowed")] + DuplicateDenom {}, } diff --git a/src/integration_test.rs b/src/integration_test.rs index a1cbd24..8c7fd28 100644 --- a/src/integration_test.rs +++ b/src/integration_test.rs @@ -46,8 +46,8 @@ fn get_info(router: &App, contract_addr: &Addr) -> InfoResponse { fn create_amm( router: &mut App, owner: &Addr, - cash: &Cw20Contract, - native_denom: String, + token1_denom:&Denom, + token2_denom:&Denom, lp_fee_percent: Decimal, protocol_fee_percent: Decimal, protocol_fee_recipient: String, @@ -56,8 +56,8 @@ fn create_amm( let cw20_id = router.store_code(contract_cw20()); let amm_id = router.store_code(contract_amm()); let msg = InstantiateMsg { - token1_denom: Denom::Native(native_denom), - token2_denom: Denom::Cw20(cash.addr()), + token1_denom: token1_denom.clone(), + token2_denom: token2_denom.clone(), lp_token_code_id: cw20_id, owner: Some(owner.to_string()), lp_fee_percent, @@ -129,8 +129,8 @@ fn test_instantiate() { let amm_addr = create_amm( &mut router, &owner, - &cw20_token, - NATIVE_TOKEN_DENOM.into(), + &Denom::Native(NATIVE_TOKEN_DENOM.into()), + &Denom::Cw20(cw20_token.addr()), lp_fee_percent, protocol_fee_percent, owner.to_string(), @@ -199,8 +199,8 @@ fn amm_add_and_remove_liquidity() { let amm_addr = create_amm( &mut router, &owner, - &cw20_token, - NATIVE_TOKEN_DENOM.into(), + &Denom::Native(NATIVE_TOKEN_DENOM.into()), + &Denom::Cw20(cw20_token.addr()), lp_fee_percent, protocol_fee_percent, owner.to_string(), @@ -584,8 +584,8 @@ fn swap_tokens_happy_path() { let amm_addr = create_amm( &mut router, &owner, - &cw20_token, - NATIVE_TOKEN_DENOM.to_string(), + &Denom::Native(NATIVE_TOKEN_DENOM.into()), + &Denom::Cw20(cw20_token.addr()), lp_fee_percent, protocol_fee_percent, owner.to_string(), @@ -791,8 +791,8 @@ fn swap_with_fee_split() { let amm_addr = create_amm( &mut router, &owner, - &cw20_token, - NATIVE_TOKEN_DENOM.to_string(), + &Denom::Native(NATIVE_TOKEN_DENOM.into()), + &Denom::Cw20(cw20_token.addr()), lp_fee_percent, protocol_fee_percent, protocol_fee_recipient.to_string(), @@ -1015,8 +1015,8 @@ fn update_config() { let amm_addr = create_amm( &mut router, &owner, - &cw20_token, - NATIVE_TOKEN_DENOM.to_string(), + &Denom::Native(NATIVE_TOKEN_DENOM.into()), + &Denom::Cw20(cw20_token.addr()), lp_fee_percent, protocol_fee_percent, owner.to_string(), @@ -1334,8 +1334,8 @@ fn token_to_token_swap_with_fee_split() { let amm1 = create_amm( &mut router, &owner, - &token1, - NATIVE_TOKEN_DENOM.to_string(), + &Denom::Native(NATIVE_TOKEN_DENOM.into()), + &Denom::Cw20(token1.addr()), lp_fee_percent, protocol_fee_percent, protocol_fee_recipient.to_string(), @@ -1343,8 +1343,8 @@ fn token_to_token_swap_with_fee_split() { let amm2 = create_amm( &mut router, &owner, - &token2, - NATIVE_TOKEN_DENOM.to_string(), + &Denom::Native(NATIVE_TOKEN_DENOM.into()), + &Denom::Cw20(token2.addr()), lp_fee_percent, protocol_fee_percent, protocol_fee_recipient.to_string(), @@ -1541,8 +1541,8 @@ fn token_to_token_swap() { let amm1 = create_amm( &mut router, &owner, - &token1, - NATIVE_TOKEN_DENOM.to_string(), + &Denom::Native(NATIVE_TOKEN_DENOM.into()), + &Denom::Cw20(token1.addr()), lp_fee_percent, protocol_fee_percent, owner.to_string(), @@ -1550,8 +1550,8 @@ fn token_to_token_swap() { let amm2 = create_amm( &mut router, &owner, - &token2, - NATIVE_TOKEN_DENOM.to_string(), + &Denom::Native(NATIVE_TOKEN_DENOM.into()), + &Denom::Cw20(token2.addr()), lp_fee_percent, protocol_fee_percent, owner.to_string(), @@ -1691,3 +1691,64 @@ fn token_to_token_swap() { assert_eq!(info_amm2.token2_reserve, token2_balance); assert_eq!(info_amm2.token1_reserve, amm2_native_balance.amount); } + +#[test] +#[should_panic(expected = "Duplicate denom is not allowed")] +fn cw20_token1_to_token1_swap() { + let mut router = mock_app(); + + const NATIVE_TOKEN_DENOM: &str = "juno"; + + let owner = Addr::unchecked("owner"); + let funds = coins(2000, NATIVE_TOKEN_DENOM); + router.borrow_mut().init_modules(|router, _, storage| { + router.bank.init_balance(storage, &owner, funds).unwrap() + }); + + let cw20_token = create_cw20( + &mut router, + &owner, + "token1".to_string(), + "TOKENONE".to_string(), + Uint128::new(5000), + ); + + let lp_fee_percent = Decimal::from_str("0.3").unwrap(); + let protocol_fee_percent = Decimal::zero(); + let _amm = create_amm( + &mut router, + &owner, + &Denom::Cw20(cw20_token.addr().clone()), + &Denom::Cw20(cw20_token.addr().clone()), + lp_fee_percent, + protocol_fee_percent, + owner.to_string(), + ); + +} + +#[test] +#[should_panic(expected = "Duplicate denom is not allowed")] +fn native_token1_to_token1_swap() { + let mut router = mock_app(); + + const NATIVE_TOKEN_DENOM: &str = "juno"; + + let owner = Addr::unchecked("owner"); + let funds = coins(2000, NATIVE_TOKEN_DENOM); + router.borrow_mut().init_modules(|router, _, storage| { + router.bank.init_balance(storage, &owner, funds).unwrap() + }); + + let lp_fee_percent = Decimal::from_str("0.3").unwrap(); + let protocol_fee_percent = Decimal::zero(); + let _amm = create_amm( + &mut router, + &owner, + &Denom::Native(NATIVE_TOKEN_DENOM.into()), + &Denom::Native(NATIVE_TOKEN_DENOM.into()), + lp_fee_percent, + protocol_fee_percent, + owner.to_string(), + ); +} From e6dbd6576eadc634fd37573f5f99674c38d3620b Mon Sep 17 00:00:00 2001 From: Richard Vade Date: Thu, 15 Sep 2022 14:44:38 -0400 Subject: [PATCH 2/3] forgot to run cargo fmt --- src/contract.rs | 37 +++++++++++++++---------------------- src/integration_test.rs | 5 ++--- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/contract.rs b/src/contract.rs index d19dfd1..b1a1025 100644 --- a/src/contract.rs +++ b/src/contract.rs @@ -393,33 +393,26 @@ fn validate_input_amount( } } -fn prevent_duplicate_denoms( - token1:&Denom, - token2:&Denom -) -> Result<(), ContractError> { +fn prevent_duplicate_denoms(token1: &Denom, token2: &Denom) -> Result<(), ContractError> { match token1 { - Denom::Cw20(token1_address) => { - match token2 { - Denom::Cw20(token2_address) => { - if token1_address.to_string() == token2_address.to_string() { - return Err(ContractError::DuplicateDenom {}); - } - Ok(()) - }, - Denom::Native(_) => Ok(()) + Denom::Cw20(token1_address) => match token2 { + Denom::Cw20(token2_address) => { + if token1_address.to_string() == token2_address.to_string() { + return Err(ContractError::DuplicateDenom {}); + } + Ok(()) } + Denom::Native(_) => Ok(()), }, - Denom::Native(token1_denom) => { - match token2 { - Denom::Cw20(_) => Ok(()), - Denom::Native(token2_denom) => { - if token1_denom == token2_denom { - return Err(ContractError::DuplicateDenom {}); - } - Ok(()) + Denom::Native(token1_denom) => match token2 { + Denom::Cw20(_) => Ok(()), + Denom::Native(token2_denom) => { + if token1_denom == token2_denom { + return Err(ContractError::DuplicateDenom {}); } + Ok(()) } - } + }, } } diff --git a/src/integration_test.rs b/src/integration_test.rs index 8c7fd28..873f8fd 100644 --- a/src/integration_test.rs +++ b/src/integration_test.rs @@ -46,8 +46,8 @@ fn get_info(router: &App, contract_addr: &Addr) -> InfoResponse { fn create_amm( router: &mut App, owner: &Addr, - token1_denom:&Denom, - token2_denom:&Denom, + token1_denom: &Denom, + token2_denom: &Denom, lp_fee_percent: Decimal, protocol_fee_percent: Decimal, protocol_fee_recipient: String, @@ -1724,7 +1724,6 @@ fn cw20_token1_to_token1_swap() { protocol_fee_percent, owner.to_string(), ); - } #[test] From 903c6d1ffde8b81959ff0d6ffd8ab7a96981bc7c Mon Sep 17 00:00:00 2001 From: Richard Vade Date: Thu, 15 Sep 2022 14:51:23 -0400 Subject: [PATCH 3/3] add 2 more tests --- src/contract.rs | 4 +-- src/integration_test.rs | 67 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/contract.rs b/src/contract.rs index b1a1025..43e30df 100644 --- a/src/contract.rs +++ b/src/contract.rs @@ -51,7 +51,7 @@ pub fn instantiate( }; TOKEN2.save(deps.storage, &token2)?; - prevent_duplicate_denoms(&msg.token1_denom.clone(), &msg.token2_denom.clone())?; + prevent_duplicate_denoms(&msg.token1_denom, &msg.token2_denom)?; let owner = msg.owner.map(|h| deps.api.addr_validate(&h)).transpose()?; OWNER.save(deps.storage, &owner)?; @@ -397,7 +397,7 @@ fn prevent_duplicate_denoms(token1: &Denom, token2: &Denom) -> Result<(), Contra match token1 { Denom::Cw20(token1_address) => match token2 { Denom::Cw20(token2_address) => { - if token1_address.to_string() == token2_address.to_string() { + if *token1_address == *token2_address { return Err(ContractError::DuplicateDenom {}); } Ok(()) diff --git a/src/integration_test.rs b/src/integration_test.rs index 873f8fd..107b816 100644 --- a/src/integration_test.rs +++ b/src/integration_test.rs @@ -1726,6 +1726,47 @@ fn cw20_token1_to_token1_swap() { ); } +#[test] +fn cw20_token1_token2_swap() { + let mut router = mock_app(); + + const NATIVE_TOKEN_DENOM: &str = "juno"; + + let owner = Addr::unchecked("owner"); + let funds = coins(2000, NATIVE_TOKEN_DENOM); + router.borrow_mut().init_modules(|router, _, storage| { + router.bank.init_balance(storage, &owner, funds).unwrap() + }); + + let token1 = create_cw20( + &mut router, + &owner, + "token1".to_string(), + "TOKENONE".to_string(), + Uint128::new(5000), + ); + + let token2 = create_cw20( + &mut router, + &owner, + "token2".to_string(), + "TOKENTWO".to_string(), + Uint128::new(5000), + ); + + let lp_fee_percent = Decimal::from_str("0.3").unwrap(); + let protocol_fee_percent = Decimal::zero(); + let _amm = create_amm( + &mut router, + &owner, + &Denom::Cw20(token1.addr().clone()), + &Denom::Cw20(token2.addr().clone()), + lp_fee_percent, + protocol_fee_percent, + owner.to_string(), + ); +} + #[test] #[should_panic(expected = "Duplicate denom is not allowed")] fn native_token1_to_token1_swap() { @@ -1751,3 +1792,29 @@ fn native_token1_to_token1_swap() { owner.to_string(), ); } + +#[test] +fn native_token1_to_token2_swap() { + let mut router = mock_app(); + + const NATIVE_TOKEN_DENOM: &str = "juno"; + const NATIVE_TOKEN_DENOM2: &str = "stars"; + + let owner = Addr::unchecked("owner"); + let funds = coins(2000, NATIVE_TOKEN_DENOM); + router.borrow_mut().init_modules(|router, _, storage| { + router.bank.init_balance(storage, &owner, funds).unwrap() + }); + + let lp_fee_percent = Decimal::from_str("0.3").unwrap(); + let protocol_fee_percent = Decimal::zero(); + let _amm = create_amm( + &mut router, + &owner, + &Denom::Native(NATIVE_TOKEN_DENOM.into()), + &Denom::Native(NATIVE_TOKEN_DENOM2.into()), + lp_fee_percent, + protocol_fee_percent, + owner.to_string(), + ); +}