From 7c88dc3eb197aad84c0b3ded3ad1b5547866889c Mon Sep 17 00:00:00 2001 From: zielvna Date: Fri, 1 Dec 2023 20:49:48 +0100 Subject: [PATCH 1/6] put fee tier tests and some of integration tests in separate file --- src/lib.rs | 803 +---------------------- src/tests/entrypoints/add_fee_tier.rs | 103 +++ src/tests/entrypoints/mod.rs | 5 + src/tests/entrypoints/remove_fee_tier.rs | 65 ++ src/tests/integration/cross_both_side.rs | 459 +++++++++++++ src/tests/integration/liquidity_gap.rs | 243 +++++++ src/tests/integration/mod.rs | 5 + src/tests/mod.rs | 5 + 8 files changed, 887 insertions(+), 801 deletions(-) create mode 100644 src/tests/entrypoints/add_fee_tier.rs create mode 100644 src/tests/entrypoints/mod.rs create mode 100644 src/tests/entrypoints/remove_fee_tier.rs create mode 100644 src/tests/integration/cross_both_side.rs create mode 100644 src/tests/integration/liquidity_gap.rs create mode 100644 src/tests/integration/mod.rs create mode 100644 src/tests/mod.rs diff --git a/src/lib.rs b/src/lib.rs index e2fd120a..d6dff32f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ extern crate alloc; mod contracts; pub mod math; +pub mod tests; #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] #[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] @@ -1082,6 +1083,7 @@ pub mod contract { #[cfg(all(test, feature = "e2e-tests"))] pub mod e2e_tests { + use super::*; use crate::contracts::{get_liquidity, get_liquidity_by_x, get_liquidity_by_y}; use crate::math::fee_growth::FeeGrowth; use crate::math::get_delta_y; @@ -1091,7 +1093,6 @@ pub mod contract { use ink::prelude::vec; use ink::prelude::vec::Vec; use ink_e2e::build_message; - use test_helpers::{ add_fee_tier, address_of, approve, balance_of, big_deposit_and_swap, change_fee_receiver, claim_fee, create_3_tokens, create_dex, create_pool, @@ -1106,151 +1107,8 @@ pub mod contract { }; use token::TokenRef; - use super::*; - type E2EResult = Result>; - #[ink_e2e::test] - async fn add_multiple_fee_tiers(mut client: ink_e2e::Client) -> E2EResult<()> { - let admin = ink_e2e::alice(); - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - - let first_fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, first_fee_tier, admin); - - let second_fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap(); - add_fee_tier!(client, ContractRef, dex, second_fee_tier, admin); - - let third_fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 4).unwrap(); - add_fee_tier!(client, ContractRef, dex, third_fee_tier, admin); - - let exist = fee_tier_exist!( - client, - ContractRef, - dex, - FeeTier::new(Percentage::from_scale(2, 4), 1u16).unwrap() - ); - assert!(exist); - - let exist = fee_tier_exist!( - client, - ContractRef, - dex, - FeeTier::new(Percentage::from_scale(2, 4), 2u16).unwrap() - ); - assert!(exist); - - let exist = fee_tier_exist!( - client, - ContractRef, - dex, - FeeTier::new(Percentage::from_scale(2, 4), 4u16).unwrap() - ); - assert!(exist); - - let fee_tiers = get_fee_tiers!(client, ContractRef, dex); - assert_eq!(fee_tiers.len(), 3); - assert_eq!(fee_tiers[0], first_fee_tier); - assert_eq!(fee_tiers[1], second_fee_tier); - assert_eq!(fee_tiers[2], third_fee_tier); - - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn add_existing_fee_tier(mut client: ink_e2e::Client) -> () { - let admin = ink_e2e::alice(); - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); - } - - #[ink_e2e::test] - #[should_panic] - async fn add_fee_tier_not_admin(mut client: ink_e2e::Client) -> () { - let user = ink_e2e::bob(); - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, user).unwrap(); - } - - #[ink_e2e::test] - async fn add_fee_tier_zero_fee(mut client: ink_e2e::Client) -> E2EResult<()> { - let admin = ink_e2e::alice(); - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - - let fee_tier = FeeTier::new(Percentage::new(0), 10).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn add_fee_tier_tick_spacing_zero(mut client: ink_e2e::Client) -> () { - let admin = ink_e2e::alice(); - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 0).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); - } - #[ink_e2e::test] - async fn remove_fee_tier_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let admin = ink_e2e::alice(); - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - - remove_fee_tier!(client, ContractRef, dex, fee_tier, admin); - let exist = fee_tier_exist!( - client, - ContractRef, - dex, - FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap() - ); - assert!(!exist); - - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn remove_not_existing_fee_tier(mut client: ink_e2e::Client) -> () { - let admin = ink_e2e::alice(); - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap(); - remove_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); - } - - #[ink_e2e::test] - #[should_panic] - async fn remove_fee_tier_not_admin(mut client: ink_e2e::Client) -> () { - let admin = ink_e2e::alice(); - let user = ink_e2e::bob(); - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - - remove_fee_tier!(client, ContractRef, dex, fee_tier, user).unwrap(); - } - #[ink_e2e::test] #[should_panic] async fn remove_position_from_empty_list(mut client: ink_e2e::Client) -> () { @@ -4529,662 +4387,5 @@ pub mod contract { bob ); } - - #[ink_e2e::test] - async fn liquidity_gap_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - let alice = ink_e2e::alice(); - let bob = ink_e2e::bob(); - let init_tick = 0; - - let initial_mint = 10u128.pow(10); - - let dex = create_dex!(client, ContractRef, Percentage::from_scale(1, 2)); - let (token_x, token_y) = create_tokens!(client, TokenRef, initial_mint, initial_mint); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let lower_tick_index = -10; - let upper_tick_index = 10; - - let mint_amount = 10u128.pow(10); - mint!( - client, - TokenRef, - token_x, - address_of!(Alice), - mint_amount, - alice - ); - mint!( - client, - TokenRef, - token_y, - address_of!(Alice), - mint_amount, - alice - ); - - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); - - let liquidity_delta = Liquidity::from_integer(20_006_000); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - assert_eq!(pool_state.liquidity, liquidity_delta); - - let mint_amount = 10067; - mint!( - client, - TokenRef, - token_x, - address_of!(Bob), - mint_amount, - alice - ); - - approve!(client, TokenRef, token_x, dex, mint_amount, bob); - - let dex_x_before = balance_of!(client, TokenRef, token_x, dex); - let dex_y_before = balance_of!(client, TokenRef, token_y, dex); - - let swap_amount = TokenAmount::new(10067); - let target_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); - let quoted_target_sqrt_price = quote!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - target_sqrt_price - ) - .unwrap() - .target_sqrt_price; - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - quoted_target_sqrt_price, - bob - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let expected_price = calculate_sqrt_price(-10).unwrap(); - let expected_y_amount_out = 9999; - - assert_eq!(pool.liquidity, liquidity_delta); - assert_eq!(pool.current_tick_index, lower_tick_index); - assert_eq!(pool.sqrt_price, expected_price); - - let bob_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - let bob_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); - let dex_x_after = balance_of!(client, TokenRef, token_x, dex); - let dex_y_after = balance_of!(client, TokenRef, token_y, dex); - - let delta_dex_x = dex_x_after - dex_x_before; - let delta_dex_y = dex_y_before - dex_y_after; - - assert_eq!(bob_x, 0); - assert_eq!(bob_y, expected_y_amount_out); - assert_eq!(delta_dex_x, swap_amount.get()); - assert_eq!(delta_dex_y, expected_y_amount_out); - assert_eq!( - pool.fee_growth_global_x, - FeeGrowth::new(29991002699190242927121) - ); - assert_eq!(pool.fee_growth_global_y, FeeGrowth::new(0)); - assert_eq!(pool.fee_protocol_token_x, TokenAmount::new(1)); - assert_eq!(pool.fee_protocol_token_y, TokenAmount::new(0)); - - // Should skip gap and then swap - let lower_tick_after_swap = -90; - let upper_tick_after_swap = -50; - let liquidity_delta = Liquidity::from_integer(20008000); - - approve!(client, TokenRef, token_x, dex, liquidity_delta.get(), alice); - approve!(client, TokenRef, token_y, dex, liquidity_delta.get(), alice); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_after_swap, - upper_tick_after_swap, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - let swap_amount = TokenAmount::new(5000); - mint!( - client, - TokenRef, - token_x, - address_of!(Bob), - swap_amount.get(), - alice - ); - - approve!(client, TokenRef, token_x, dex, swap_amount.get(), bob); - - let dex_x_before = balance_of!(client, TokenRef, token_x, dex); - let dex_y_before = balance_of!(client, TokenRef, token_y, dex); - - let target_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); - let quoted_target_sqrt_price = quote!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - target_sqrt_price - ) - .unwrap() - .target_sqrt_price; - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - quoted_target_sqrt_price, - bob - ); - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - let bob_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - let bob_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); - let dex_x_after = balance_of!(client, TokenRef, token_x, dex); - let dex_y_after = balance_of!(client, TokenRef, token_y, dex); - - let delta_dex_x = dex_x_after - dex_x_before; - let delta_dex_y = dex_y_before - dex_y_after; - Ok(()) - } - - #[ink_e2e::test] - async fn cross_both_side_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - let alice = ink_e2e::alice(); - let bob = ink_e2e::bob(); - let init_tick = 0; - - let initial_mint = 10u128.pow(10); - - let dex = create_dex!(client, ContractRef, Percentage::from_scale(1, 2)); - let (token_x, token_y) = create_tokens!(client, TokenRef, initial_mint, initial_mint); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let lower_tick_index = -10; - let upper_tick_index = 10; - - let mint_amount = 10u128.pow(5); - mint!( - client, - TokenRef, - token_x, - address_of!(Bob), - mint_amount, - alice - ); - mint!( - client, - TokenRef, - token_y, - address_of!(Alice), - mint_amount, - alice - ); - - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); - - let liquidity_delta = Liquidity::new(20006000000000); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - create_position!( - client, - ContractRef, - dex, - pool_key, - -20, - lower_tick_index, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - assert_eq!(pool.liquidity, liquidity_delta); - - let limit_without_cross_tick_amount = TokenAmount(10_068); - let not_cross_amount = TokenAmount(1); - let min_amount_to_cross_from_tick_price = TokenAmount(3); - let crossing_amount_by_amount_out = TokenAmount(20136101434); - - let mint_amount = limit_without_cross_tick_amount.get() - + not_cross_amount.get() - + min_amount_to_cross_from_tick_price.get() - + crossing_amount_by_amount_out.get(); - - mint!( - client, - TokenRef, - token_x, - address_of!(Alice), - mint_amount, - alice - ); - mint!( - client, - TokenRef, - token_y, - address_of!(Alice), - mint_amount, - alice - ); - - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); - - let pool_before = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - let limit_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - limit_without_cross_tick_amount, - true, - limit_sqrt_price, - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let expected_tick = -10; - let expected_price = calculate_sqrt_price(expected_tick).unwrap(); - - assert_eq!(pool.current_tick_index, expected_tick); - assert_eq!(pool.liquidity, pool_before.liquidity); - assert_eq!(pool.sqrt_price, expected_price); - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - min_amount_to_cross_from_tick_price, - true, - limit_sqrt_price, - alice - ); - - swap!( - client, - ContractRef, - dex, - pool_key, - false, - min_amount_to_cross_from_tick_price, - true, - SqrtPrice::new(MAX_SQRT_PRICE), - alice - ); - - let massive_x = 10u128.pow(19); - let massive_y = 10u128.pow(19); - - mint!( - client, - TokenRef, - token_x, - address_of!(Alice), - massive_x, - alice - ); - mint!( - client, - TokenRef, - token_y, - address_of!(Alice), - massive_y, - alice - ); - approve!(client, TokenRef, token_x, dex, massive_x, alice); - approve!(client, TokenRef, token_y, dex, massive_y, alice); - - let massive_liquidity_delta = Liquidity::new(19996000399699881985603000000); - - create_position!( - client, - ContractRef, - dex, - pool_key, - -20, - 0, - massive_liquidity_delta, - SqrtPrice::new(MIN_SQRT_PRICE), - SqrtPrice::new(MAX_SQRT_PRICE), - alice - ); - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - TokenAmount(1), - false, - limit_sqrt_price, - alice - ); - - swap!( - client, - ContractRef, - dex, - pool_key, - false, - TokenAmount(2), - true, - SqrtPrice::new(MAX_SQRT_PRICE), - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - assert_eq!(pool.current_tick_index, -20); - assert_eq!( - pool.fee_growth_global_x, - FeeGrowth::new(29991002699190242927121) - ); - assert_eq!(pool.fee_growth_global_y, FeeGrowth::new(0)); - assert_eq!(pool.fee_protocol_token_x, TokenAmount(4)); - assert_eq!(pool.fee_protocol_token_y, TokenAmount(2)); - assert_eq!( - pool.liquidity, - Liquidity::new(19996000399699901991603000000) - ); - assert_eq!(pool.sqrt_price, SqrtPrice::new(999500149964999999999999)); - - let final_last_tick = get_tick!(client, ContractRef, dex, pool_key, -20).unwrap(); - assert_eq!(final_last_tick.fee_growth_outside_x, FeeGrowth::new(0)); - assert_eq!(final_last_tick.fee_growth_outside_y, FeeGrowth::new(0)); - assert_eq!( - final_last_tick.liquidity_change, - Liquidity::new(19996000399699901991603000000) - ); - - let final_lower_tick = get_tick!(client, ContractRef, dex, pool_key, -10).unwrap(); - assert_eq!( - final_lower_tick.fee_growth_outside_x, - FeeGrowth::new(29991002699190242927121) - ); - assert_eq!(final_lower_tick.fee_growth_outside_y, FeeGrowth::new(0)); - assert_eq!(final_lower_tick.liquidity_change, Liquidity::new(0)); - - let final_upper_tick = get_tick!(client, ContractRef, dex, pool_key, 10).unwrap(); - assert_eq!(final_upper_tick.fee_growth_outside_x, FeeGrowth::new(0)); - assert_eq!(final_upper_tick.fee_growth_outside_y, FeeGrowth::new(0)); - assert_eq!( - final_upper_tick.liquidity_change, - Liquidity::new(20006000000000) - ); - - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn cross_both_side_not_cross_case_test(mut client: ink_e2e::Client) -> () { - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - let alice = ink_e2e::alice(); - let bob = ink_e2e::bob(); - let init_tick = 0; - - let initial_mint = 10u128.pow(10); - - let dex = create_dex!(client, ContractRef, Percentage::from_scale(1, 2)); - let (token_x, token_y) = create_tokens!(client, TokenRef, initial_mint, initial_mint); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let lower_tick_index = -10; - let upper_tick_index = 10; - - let mint_amount = 10u128.pow(5); - mint!( - client, - TokenRef, - token_x, - address_of!(Alice), - mint_amount, - alice - ); - mint!( - client, - TokenRef, - token_y, - address_of!(Alice), - mint_amount, - alice - ); - - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); - - let liquidity_delta = Liquidity::new(20006000000000); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - create_position!( - client, - ContractRef, - dex, - pool_key, - -20, - lower_tick_index, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - assert_eq!(pool.liquidity, liquidity_delta); - - let limit_without_cross_tick_amount = TokenAmount(10_068); - let not_cross_amount = TokenAmount(1); - let min_amount_to_cross_from_tick_price = TokenAmount(3); - let crossing_amount_by_amount_out = TokenAmount(20136101434); - - let mint_amount = limit_without_cross_tick_amount.get() - + not_cross_amount.get() - + min_amount_to_cross_from_tick_price.get() - + crossing_amount_by_amount_out.get(); - - mint!( - client, - TokenRef, - token_x, - address_of!(Alice), - mint_amount, - alice - ); - mint!( - client, - TokenRef, - token_y, - address_of!(Alice), - mint_amount, - alice - ); - - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); - - let pool_before = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - let limit_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - limit_without_cross_tick_amount, - true, - limit_sqrt_price, - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let expected_tick = -10; - let expected_price = calculate_sqrt_price(expected_tick).unwrap(); - - assert_eq!(pool.current_tick_index, expected_tick); - assert_eq!(pool.liquidity, pool_before.liquidity); - assert_eq!(pool.sqrt_price, expected_price); - - let slippage = SqrtPrice::new(MIN_SQRT_PRICE); - let target_sqrt_price = quote!( - client, - ContractRef, - dex, - pool_key, - true, - not_cross_amount, - true, - slippage - ) - .unwrap() - .target_sqrt_price; - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - not_cross_amount, - true, - target_sqrt_price, - alice - ); - } } } diff --git a/src/tests/entrypoints/add_fee_tier.rs b/src/tests/entrypoints/add_fee_tier.rs new file mode 100644 index 00000000..b4171ddc --- /dev/null +++ b/src/tests/entrypoints/add_fee_tier.rs @@ -0,0 +1,103 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::math::types::percentage::Percentage; + use crate::{ + contract::ContractRef, + contracts::{entrypoints::Invariant, FeeTier}, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{add_fee_tier, create_dex, fee_tier_exist, get_fee_tiers}; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn add_multiple_fee_tiers(mut client: ink_e2e::Client) -> E2EResult<()> { + let admin = ink_e2e::alice(); + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + + let first_fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); + add_fee_tier!(client, ContractRef, dex, first_fee_tier, admin); + + let second_fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap(); + add_fee_tier!(client, ContractRef, dex, second_fee_tier, admin); + + let third_fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 4).unwrap(); + add_fee_tier!(client, ContractRef, dex, third_fee_tier, admin); + + let exist = fee_tier_exist!( + client, + ContractRef, + dex, + FeeTier::new(Percentage::from_scale(2, 4), 1u16).unwrap() + ); + assert!(exist); + + let exist = fee_tier_exist!( + client, + ContractRef, + dex, + FeeTier::new(Percentage::from_scale(2, 4), 2u16).unwrap() + ); + assert!(exist); + + let exist = fee_tier_exist!( + client, + ContractRef, + dex, + FeeTier::new(Percentage::from_scale(2, 4), 4u16).unwrap() + ); + assert!(exist); + + let fee_tiers = get_fee_tiers!(client, ContractRef, dex); + assert_eq!(fee_tiers.len(), 3); + assert_eq!(fee_tiers[0], first_fee_tier); + assert_eq!(fee_tiers[1], second_fee_tier); + assert_eq!(fee_tiers[2], third_fee_tier); + + Ok(()) + } + + #[ink_e2e::test] + #[should_panic] + async fn add_existing_fee_tier(mut client: ink_e2e::Client) -> () { + let admin = ink_e2e::alice(); + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); + } + + #[ink_e2e::test] + #[should_panic] + async fn add_fee_tier_not_admin(mut client: ink_e2e::Client) -> () { + let user = ink_e2e::bob(); + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); + add_fee_tier!(client, ContractRef, dex, fee_tier, user).unwrap(); + } + + #[ink_e2e::test] + async fn add_fee_tier_zero_fee(mut client: ink_e2e::Client) -> E2EResult<()> { + let admin = ink_e2e::alice(); + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + + let fee_tier = FeeTier::new(Percentage::new(0), 10).unwrap(); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + Ok(()) + } + + #[ink_e2e::test] + #[should_panic] + async fn add_fee_tier_tick_spacing_zero(mut client: ink_e2e::Client) -> () { + let admin = ink_e2e::alice(); + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 0).unwrap(); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); + } +} diff --git a/src/tests/entrypoints/mod.rs b/src/tests/entrypoints/mod.rs new file mode 100644 index 00000000..97d353e6 --- /dev/null +++ b/src/tests/entrypoints/mod.rs @@ -0,0 +1,5 @@ +pub mod add_fee_tier; +pub mod remove_fee_tier; + +pub use add_fee_tier::*; +pub use remove_fee_tier::*; diff --git a/src/tests/entrypoints/remove_fee_tier.rs b/src/tests/entrypoints/remove_fee_tier.rs new file mode 100644 index 00000000..7e3e9f94 --- /dev/null +++ b/src/tests/entrypoints/remove_fee_tier.rs @@ -0,0 +1,65 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::math::types::percentage::Percentage; + use crate::{ + contract::ContractRef, + contracts::{entrypoints::Invariant, FeeTier}, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{add_fee_tier, create_dex, fee_tier_exist, remove_fee_tier}; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn remove_fee_tier_test(mut client: ink_e2e::Client) -> E2EResult<()> { + let admin = ink_e2e::alice(); + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap(); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + + remove_fee_tier!(client, ContractRef, dex, fee_tier, admin); + let exist = fee_tier_exist!( + client, + ContractRef, + dex, + FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap() + ); + assert!(!exist); + + Ok(()) + } + + #[ink_e2e::test] + #[should_panic] + async fn remove_not_existing_fee_tier(mut client: ink_e2e::Client) -> () { + let admin = ink_e2e::alice(); + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap(); + remove_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); + } + + #[ink_e2e::test] + #[should_panic] + async fn remove_fee_tier_not_admin(mut client: ink_e2e::Client) -> () { + let admin = ink_e2e::alice(); + let user = ink_e2e::bob(); + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap(); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + + remove_fee_tier!(client, ContractRef, dex, fee_tier, user).unwrap(); + } +} diff --git a/src/tests/integration/cross_both_side.rs b/src/tests/integration/cross_both_side.rs new file mode 100644 index 00000000..4d8f572e --- /dev/null +++ b/src/tests/integration/cross_both_side.rs @@ -0,0 +1,459 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::ContractRef, + contracts::{entrypoints::Invariant, FeeTier, PoolKey}, + math::{ + types::{ + fee_growth::FeeGrowth, + liquidity::Liquidity, + percentage::Percentage, + sqrt_price::sqrt_price::{calculate_sqrt_price, SqrtPrice}, + token_amount::TokenAmount, + }, + MAX_SQRT_PRICE, MIN_SQRT_PRICE, + }, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{ + add_fee_tier, address_of, approve, create_dex, create_pool, create_position, create_tokens, + get_pool, get_tick, mint, quote, swap, + }; + use token::{TokenRef, PSP22}; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn cross_both_side_test(mut client: ink_e2e::Client) -> E2EResult<()> { + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); + let alice = ink_e2e::alice(); + let bob = ink_e2e::bob(); + let init_tick = 0; + + let initial_mint = 10u128.pow(10); + + let dex = create_dex!(client, ContractRef, Percentage::from_scale(1, 2)); + let (token_x, token_y) = create_tokens!(client, TokenRef, initial_mint, initial_mint); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + let pool = create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + let lower_tick_index = -10; + let upper_tick_index = 10; + + let mint_amount = 10u128.pow(5); + mint!( + client, + TokenRef, + token_x, + address_of!(Bob), + mint_amount, + alice + ); + mint!( + client, + TokenRef, + token_y, + address_of!(Alice), + mint_amount, + alice + ); + + approve!(client, TokenRef, token_x, dex, mint_amount, alice); + approve!(client, TokenRef, token_y, dex, mint_amount, alice); + + let liquidity_delta = Liquidity::new(20006000000000); + + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick_index, + upper_tick_index, + liquidity_delta, + pool_state.sqrt_price, + pool_state.sqrt_price, + alice + ); + + create_position!( + client, + ContractRef, + dex, + pool_key, + -20, + lower_tick_index, + liquidity_delta, + pool_state.sqrt_price, + pool_state.sqrt_price, + alice + ); + + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + assert_eq!(pool.liquidity, liquidity_delta); + + let limit_without_cross_tick_amount = TokenAmount(10_068); + let not_cross_amount = TokenAmount(1); + let min_amount_to_cross_from_tick_price = TokenAmount(3); + let crossing_amount_by_amount_out = TokenAmount(20136101434); + + let mint_amount = limit_without_cross_tick_amount.get() + + not_cross_amount.get() + + min_amount_to_cross_from_tick_price.get() + + crossing_amount_by_amount_out.get(); + + mint!( + client, + TokenRef, + token_x, + address_of!(Alice), + mint_amount, + alice + ); + mint!( + client, + TokenRef, + token_y, + address_of!(Alice), + mint_amount, + alice + ); + + approve!(client, TokenRef, token_x, dex, mint_amount, alice); + approve!(client, TokenRef, token_y, dex, mint_amount, alice); + + let pool_before = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + let limit_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); + + swap!( + client, + ContractRef, + dex, + pool_key, + true, + limit_without_cross_tick_amount, + true, + limit_sqrt_price, + alice + ); + + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + let expected_tick = -10; + let expected_price = calculate_sqrt_price(expected_tick).unwrap(); + + assert_eq!(pool.current_tick_index, expected_tick); + assert_eq!(pool.liquidity, pool_before.liquidity); + assert_eq!(pool.sqrt_price, expected_price); + + swap!( + client, + ContractRef, + dex, + pool_key, + true, + min_amount_to_cross_from_tick_price, + true, + limit_sqrt_price, + alice + ); + + swap!( + client, + ContractRef, + dex, + pool_key, + false, + min_amount_to_cross_from_tick_price, + true, + SqrtPrice::new(MAX_SQRT_PRICE), + alice + ); + + let massive_x = 10u128.pow(19); + let massive_y = 10u128.pow(19); + + mint!( + client, + TokenRef, + token_x, + address_of!(Alice), + massive_x, + alice + ); + mint!( + client, + TokenRef, + token_y, + address_of!(Alice), + massive_y, + alice + ); + approve!(client, TokenRef, token_x, dex, massive_x, alice); + approve!(client, TokenRef, token_y, dex, massive_y, alice); + + let massive_liquidity_delta = Liquidity::new(19996000399699881985603000000); + + create_position!( + client, + ContractRef, + dex, + pool_key, + -20, + 0, + massive_liquidity_delta, + SqrtPrice::new(MIN_SQRT_PRICE), + SqrtPrice::new(MAX_SQRT_PRICE), + alice + ); + + swap!( + client, + ContractRef, + dex, + pool_key, + true, + TokenAmount(1), + false, + limit_sqrt_price, + alice + ); + + swap!( + client, + ContractRef, + dex, + pool_key, + false, + TokenAmount(2), + true, + SqrtPrice::new(MAX_SQRT_PRICE), + alice + ); + + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + assert_eq!(pool.current_tick_index, -20); + assert_eq!( + pool.fee_growth_global_x, + FeeGrowth::new(29991002699190242927121) + ); + assert_eq!(pool.fee_growth_global_y, FeeGrowth::new(0)); + assert_eq!(pool.fee_protocol_token_x, TokenAmount(4)); + assert_eq!(pool.fee_protocol_token_y, TokenAmount(2)); + assert_eq!( + pool.liquidity, + Liquidity::new(19996000399699901991603000000) + ); + assert_eq!(pool.sqrt_price, SqrtPrice::new(999500149964999999999999)); + + let final_last_tick = get_tick!(client, ContractRef, dex, pool_key, -20).unwrap(); + assert_eq!(final_last_tick.fee_growth_outside_x, FeeGrowth::new(0)); + assert_eq!(final_last_tick.fee_growth_outside_y, FeeGrowth::new(0)); + assert_eq!( + final_last_tick.liquidity_change, + Liquidity::new(19996000399699901991603000000) + ); + + let final_lower_tick = get_tick!(client, ContractRef, dex, pool_key, -10).unwrap(); + assert_eq!( + final_lower_tick.fee_growth_outside_x, + FeeGrowth::new(29991002699190242927121) + ); + assert_eq!(final_lower_tick.fee_growth_outside_y, FeeGrowth::new(0)); + assert_eq!(final_lower_tick.liquidity_change, Liquidity::new(0)); + + let final_upper_tick = get_tick!(client, ContractRef, dex, pool_key, 10).unwrap(); + assert_eq!(final_upper_tick.fee_growth_outside_x, FeeGrowth::new(0)); + assert_eq!(final_upper_tick.fee_growth_outside_y, FeeGrowth::new(0)); + assert_eq!( + final_upper_tick.liquidity_change, + Liquidity::new(20006000000000) + ); + + Ok(()) + } + + #[ink_e2e::test] + #[should_panic] + async fn cross_both_side_not_cross_case_test(mut client: ink_e2e::Client) -> () { + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); + let alice = ink_e2e::alice(); + let bob = ink_e2e::bob(); + let init_tick = 0; + + let initial_mint = 10u128.pow(10); + + let dex = create_dex!(client, ContractRef, Percentage::from_scale(1, 2)); + let (token_x, token_y) = create_tokens!(client, TokenRef, initial_mint, initial_mint); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + let pool = create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + let lower_tick_index = -10; + let upper_tick_index = 10; + + let mint_amount = 10u128.pow(5); + mint!( + client, + TokenRef, + token_x, + address_of!(Alice), + mint_amount, + alice + ); + mint!( + client, + TokenRef, + token_y, + address_of!(Alice), + mint_amount, + alice + ); + + approve!(client, TokenRef, token_x, dex, mint_amount, alice); + approve!(client, TokenRef, token_y, dex, mint_amount, alice); + + let liquidity_delta = Liquidity::new(20006000000000); + + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick_index, + upper_tick_index, + liquidity_delta, + pool_state.sqrt_price, + pool_state.sqrt_price, + alice + ); + + create_position!( + client, + ContractRef, + dex, + pool_key, + -20, + lower_tick_index, + liquidity_delta, + pool_state.sqrt_price, + pool_state.sqrt_price, + alice + ); + + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + assert_eq!(pool.liquidity, liquidity_delta); + + let limit_without_cross_tick_amount = TokenAmount(10_068); + let not_cross_amount = TokenAmount(1); + let min_amount_to_cross_from_tick_price = TokenAmount(3); + let crossing_amount_by_amount_out = TokenAmount(20136101434); + + let mint_amount = limit_without_cross_tick_amount.get() + + not_cross_amount.get() + + min_amount_to_cross_from_tick_price.get() + + crossing_amount_by_amount_out.get(); + + mint!( + client, + TokenRef, + token_x, + address_of!(Alice), + mint_amount, + alice + ); + mint!( + client, + TokenRef, + token_y, + address_of!(Alice), + mint_amount, + alice + ); + + approve!(client, TokenRef, token_x, dex, mint_amount, alice); + approve!(client, TokenRef, token_y, dex, mint_amount, alice); + + let pool_before = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + let limit_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); + + swap!( + client, + ContractRef, + dex, + pool_key, + true, + limit_without_cross_tick_amount, + true, + limit_sqrt_price, + alice + ); + + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + let expected_tick = -10; + let expected_price = calculate_sqrt_price(expected_tick).unwrap(); + + assert_eq!(pool.current_tick_index, expected_tick); + assert_eq!(pool.liquidity, pool_before.liquidity); + assert_eq!(pool.sqrt_price, expected_price); + + let slippage = SqrtPrice::new(MIN_SQRT_PRICE); + let target_sqrt_price = quote!( + client, + ContractRef, + dex, + pool_key, + true, + not_cross_amount, + true, + slippage + ) + .unwrap() + .target_sqrt_price; + + swap!( + client, + ContractRef, + dex, + pool_key, + true, + not_cross_amount, + true, + target_sqrt_price, + alice + ); + } +} diff --git a/src/tests/integration/liquidity_gap.rs b/src/tests/integration/liquidity_gap.rs new file mode 100644 index 00000000..4df7b0ae --- /dev/null +++ b/src/tests/integration/liquidity_gap.rs @@ -0,0 +1,243 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::ContractRef, + contracts::{entrypoints::Invariant, FeeTier, PoolKey}, + math::{ + types::{ + fee_growth::FeeGrowth, + liquidity::Liquidity, + percentage::Percentage, + sqrt_price::sqrt_price::{calculate_sqrt_price, SqrtPrice}, + token_amount::TokenAmount, + }, + MIN_SQRT_PRICE, + }, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{ + add_fee_tier, address_of, approve, balance_of, create_dex, create_pool, create_position, + create_tokens, get_pool, mint, quote, swap, + }; + use token::{TokenRef, PSP22}; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn liquidity_gap_test(mut client: ink_e2e::Client) -> E2EResult<()> { + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); + let alice = ink_e2e::alice(); + let bob = ink_e2e::bob(); + let init_tick = 0; + + let initial_mint = 10u128.pow(10); + + let dex = create_dex!(client, ContractRef, Percentage::from_scale(1, 2)); + let (token_x, token_y) = create_tokens!(client, TokenRef, initial_mint, initial_mint); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + let pool = create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + let lower_tick_index = -10; + let upper_tick_index = 10; + + let mint_amount = 10u128.pow(10); + mint!( + client, + TokenRef, + token_x, + address_of!(Alice), + mint_amount, + alice + ); + mint!( + client, + TokenRef, + token_y, + address_of!(Alice), + mint_amount, + alice + ); + + approve!(client, TokenRef, token_x, dex, mint_amount, alice); + approve!(client, TokenRef, token_y, dex, mint_amount, alice); + + let liquidity_delta = Liquidity::from_integer(20_006_000); + + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick_index, + upper_tick_index, + liquidity_delta, + pool_state.sqrt_price, + pool_state.sqrt_price, + alice + ); + + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + assert_eq!(pool_state.liquidity, liquidity_delta); + + let mint_amount = 10067; + mint!( + client, + TokenRef, + token_x, + address_of!(Bob), + mint_amount, + alice + ); + + approve!(client, TokenRef, token_x, dex, mint_amount, bob); + + let dex_x_before = balance_of!(client, TokenRef, token_x, dex); + let dex_y_before = balance_of!(client, TokenRef, token_y, dex); + + let swap_amount = TokenAmount::new(10067); + let target_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); + let quoted_target_sqrt_price = quote!( + client, + ContractRef, + dex, + pool_key, + true, + swap_amount, + true, + target_sqrt_price + ) + .unwrap() + .target_sqrt_price; + + swap!( + client, + ContractRef, + dex, + pool_key, + true, + swap_amount, + true, + quoted_target_sqrt_price, + bob + ); + + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + let expected_price = calculate_sqrt_price(-10).unwrap(); + let expected_y_amount_out = 9999; + + assert_eq!(pool.liquidity, liquidity_delta); + assert_eq!(pool.current_tick_index, lower_tick_index); + assert_eq!(pool.sqrt_price, expected_price); + + let bob_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); + let bob_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); + let dex_x_after = balance_of!(client, TokenRef, token_x, dex); + let dex_y_after = balance_of!(client, TokenRef, token_y, dex); + + let delta_dex_x = dex_x_after - dex_x_before; + let delta_dex_y = dex_y_before - dex_y_after; + + assert_eq!(bob_x, 0); + assert_eq!(bob_y, expected_y_amount_out); + assert_eq!(delta_dex_x, swap_amount.get()); + assert_eq!(delta_dex_y, expected_y_amount_out); + assert_eq!( + pool.fee_growth_global_x, + FeeGrowth::new(29991002699190242927121) + ); + assert_eq!(pool.fee_growth_global_y, FeeGrowth::new(0)); + assert_eq!(pool.fee_protocol_token_x, TokenAmount::new(1)); + assert_eq!(pool.fee_protocol_token_y, TokenAmount::new(0)); + + // Should skip gap and then swap + let lower_tick_after_swap = -90; + let upper_tick_after_swap = -50; + let liquidity_delta = Liquidity::from_integer(20008000); + + approve!(client, TokenRef, token_x, dex, liquidity_delta.get(), alice); + approve!(client, TokenRef, token_y, dex, liquidity_delta.get(), alice); + + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick_after_swap, + upper_tick_after_swap, + liquidity_delta, + pool_state.sqrt_price, + pool_state.sqrt_price, + alice + ); + + let swap_amount = TokenAmount::new(5000); + mint!( + client, + TokenRef, + token_x, + address_of!(Bob), + swap_amount.get(), + alice + ); + + approve!(client, TokenRef, token_x, dex, swap_amount.get(), bob); + + let dex_x_before = balance_of!(client, TokenRef, token_x, dex); + let dex_y_before = balance_of!(client, TokenRef, token_y, dex); + + let target_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); + let quoted_target_sqrt_price = quote!( + client, + ContractRef, + dex, + pool_key, + true, + swap_amount, + true, + target_sqrt_price + ) + .unwrap() + .target_sqrt_price; + + swap!( + client, + ContractRef, + dex, + pool_key, + true, + swap_amount, + true, + quoted_target_sqrt_price, + bob + ); + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + let bob_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); + let bob_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); + let dex_x_after = balance_of!(client, TokenRef, token_x, dex); + let dex_y_after = balance_of!(client, TokenRef, token_y, dex); + + let delta_dex_x = dex_x_after - dex_x_before; + let delta_dex_y = dex_y_before - dex_y_after; + Ok(()) + } +} diff --git a/src/tests/integration/mod.rs b/src/tests/integration/mod.rs new file mode 100644 index 00000000..3b0f716a --- /dev/null +++ b/src/tests/integration/mod.rs @@ -0,0 +1,5 @@ +pub mod cross_both_side; +pub mod liquidity_gap; + +pub use cross_both_side::*; +pub use liquidity_gap::*; diff --git a/src/tests/mod.rs b/src/tests/mod.rs new file mode 100644 index 00000000..4c0a70b0 --- /dev/null +++ b/src/tests/mod.rs @@ -0,0 +1,5 @@ +pub mod entrypoints; +pub mod integration; + +pub use entrypoints::*; +pub use integration::*; From 015f4723be61a20d7f94cf03f8554e3f1c40ec54 Mon Sep 17 00:00:00 2001 From: zielvna Date: Mon, 4 Dec 2023 11:50:37 +0100 Subject: [PATCH 2/6] move tests --- src/tests/{entrypoints => }/add_fee_tier.rs | 0 src/tests/{integration => }/cross_both_side.rs | 0 src/tests/entrypoints/mod.rs | 5 ----- src/tests/integration/mod.rs | 5 ----- src/tests/{integration => }/liquidity_gap.rs | 0 src/tests/mod.rs | 12 ++++++++---- src/tests/{entrypoints => }/remove_fee_tier.rs | 0 7 files changed, 8 insertions(+), 14 deletions(-) rename src/tests/{entrypoints => }/add_fee_tier.rs (100%) rename src/tests/{integration => }/cross_both_side.rs (100%) delete mode 100644 src/tests/entrypoints/mod.rs delete mode 100644 src/tests/integration/mod.rs rename src/tests/{integration => }/liquidity_gap.rs (100%) rename src/tests/{entrypoints => }/remove_fee_tier.rs (100%) diff --git a/src/tests/entrypoints/add_fee_tier.rs b/src/tests/add_fee_tier.rs similarity index 100% rename from src/tests/entrypoints/add_fee_tier.rs rename to src/tests/add_fee_tier.rs diff --git a/src/tests/integration/cross_both_side.rs b/src/tests/cross_both_side.rs similarity index 100% rename from src/tests/integration/cross_both_side.rs rename to src/tests/cross_both_side.rs diff --git a/src/tests/entrypoints/mod.rs b/src/tests/entrypoints/mod.rs deleted file mode 100644 index 97d353e6..00000000 --- a/src/tests/entrypoints/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod add_fee_tier; -pub mod remove_fee_tier; - -pub use add_fee_tier::*; -pub use remove_fee_tier::*; diff --git a/src/tests/integration/mod.rs b/src/tests/integration/mod.rs deleted file mode 100644 index 3b0f716a..00000000 --- a/src/tests/integration/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod cross_both_side; -pub mod liquidity_gap; - -pub use cross_both_side::*; -pub use liquidity_gap::*; diff --git a/src/tests/integration/liquidity_gap.rs b/src/tests/liquidity_gap.rs similarity index 100% rename from src/tests/integration/liquidity_gap.rs rename to src/tests/liquidity_gap.rs diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 4c0a70b0..d1f03cd6 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,5 +1,9 @@ -pub mod entrypoints; -pub mod integration; +pub mod add_fee_tier; +pub mod cross_both_side; +pub mod liquidity_gap; +pub mod remove_fee_tier; -pub use entrypoints::*; -pub use integration::*; +pub use add_fee_tier::*; +pub use cross_both_side::*; +pub use liquidity_gap::*; +pub use remove_fee_tier::*; diff --git a/src/tests/entrypoints/remove_fee_tier.rs b/src/tests/remove_fee_tier.rs similarity index 100% rename from src/tests/entrypoints/remove_fee_tier.rs rename to src/tests/remove_fee_tier.rs From 02226fecf2e3de723a094d8b32220f2264332a96 Mon Sep 17 00:00:00 2001 From: zielvna Date: Mon, 4 Dec 2023 20:15:59 +0100 Subject: [PATCH 3/6] put all tests into separate files --- src/lib.rs | 3312 +----------------------------- src/tests/change_fee_receiver.rs | 82 + src/tests/change_protocol_fee.rs | 65 + src/tests/claim.rs | 58 + src/tests/constructor.rs | 28 + src/tests/create_pool.rs | 42 + src/tests/cross.rs | 66 + src/tests/cross_both_side.rs | 6 +- src/tests/fee_tier.rs | 73 + src/tests/limits.rs | 331 +++ src/tests/liquidity_gap.rs | 164 +- src/tests/max_tick_cross.rs | 142 ++ src/tests/mod.rs | 22 +- src/tests/multiple_swap.rs | 36 + src/tests/position.rs | 523 +++++ src/tests/position_list.rs | 1022 +++++++++ src/tests/position_slippage.rs | 173 ++ src/tests/protocol_fee.rs | 80 + src/tests/slippage.rs | 135 ++ src/tests/swap.rs | 336 +++ src/tests/swap_route.rs | 160 ++ 21 files changed, 3535 insertions(+), 3321 deletions(-) create mode 100644 src/tests/change_fee_receiver.rs create mode 100644 src/tests/change_protocol_fee.rs create mode 100644 src/tests/claim.rs create mode 100644 src/tests/constructor.rs create mode 100644 src/tests/create_pool.rs create mode 100644 src/tests/cross.rs create mode 100644 src/tests/fee_tier.rs create mode 100644 src/tests/limits.rs create mode 100644 src/tests/max_tick_cross.rs create mode 100644 src/tests/multiple_swap.rs create mode 100644 src/tests/position.rs create mode 100644 src/tests/position_list.rs create mode 100644 src/tests/position_slippage.rs create mode 100644 src/tests/protocol_fee.rs create mode 100644 src/tests/slippage.rs create mode 100644 src/tests/swap.rs create mode 100644 src/tests/swap_route.rs diff --git a/src/lib.rs b/src/lib.rs index cc60eba7..effce311 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -134,8 +134,8 @@ pub mod contract { derive(scale_info::TypeInfo, ink::storage::traits::StorageLayout,) )] pub struct Hop { - pool_key: PoolKey, - x_to_y: bool, + pub pool_key: PoolKey, + pub x_to_y: bool, } #[ink(storage)] @@ -1059,3312 +1059,4 @@ pub mod contract { assert_eq!(contract.fee_tiers.get_all().len(), 0); } } - - #[cfg(all(test, feature = "e2e-tests"))] - pub mod e2e_tests { - use super::*; - use crate::contracts::{get_liquidity, get_liquidity_by_x, get_liquidity_by_y}; - use crate::math::fee_growth::FeeGrowth; - use crate::math::get_delta_y; - use crate::math::sqrt_price::log::get_tick_at_sqrt_price; - use crate::math::sqrt_price::sqrt_price::{calculate_sqrt_price, get_max_tick}; - use crate::math::MAX_TICK; - use ink::prelude::vec; - use ink::prelude::vec::Vec; - use ink_e2e::build_message; - use test_helpers::{ - add_fee_tier, address_of, approve, balance_of, big_deposit_and_swap, - change_fee_receiver, claim_fee, create_3_tokens, create_dex, create_pool, - create_position, create_standard_fee_tiers, create_tokens, fee_tier_exist, - get_all_positions, get_fee_tiers, get_pool, get_position, get_tick, init_basic_pool, - init_basic_position, init_basic_swap, init_cross_position, init_cross_swap, - init_dex_and_3_tokens, init_dex_and_tokens, init_dex_and_tokens_max_mint_amount, - init_slippage_dex_and_tokens, init_slippage_pool_with_liquidity, is_tick_initialized, - mint, multiple_swap, positions_equals, quote, quote_route, remove_fee_tier, - remove_position, swap, swap_exact_limit, swap_route, transfer_position, - withdraw_protocol_fee, - }; - use token::TokenRef; - - type E2EResult = Result>; - - #[ink_e2e::test] - #[should_panic] - async fn remove_position_from_empty_list(mut client: ink_e2e::Client) -> () { - let dex = create_dex!(client, ContractRef, Percentage::from_scale(6, 3)); - let initial_amount = 10u128.pow(10); - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_amount, initial_amount); - - let alice = ink_e2e::alice(); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let init_tick = -23028; - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - remove_position!(client, ContractRef, dex, 0, alice).unwrap(); - } - - #[ink_e2e::test] - async fn add_multiple_positions(mut client: ink_e2e::Client) -> E2EResult<()> { - let alice = ink_e2e::alice(); - let init_tick = -23028; - - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let initial_balance = 10u128.pow(10); - - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_balance, initial_balance); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 3).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let tick_indexes = [-9780, -42, 0, 9, 276, 32343, -50001]; - let liquidity_delta = Liquidity::from_integer(1_000_000); - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - // Open three positions - { - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[2], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[1], - tick_indexes[4], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - } - - // Remove middle position - { - let position_index_to_remove = 2; - let positions_list_before = get_all_positions!(client, ContractRef, dex, alice); - let last_position = positions_list_before[positions_list_before.len() - 1]; - - remove_position!(client, ContractRef, dex, position_index_to_remove, alice); - - let positions_list_after = get_all_positions!(client, ContractRef, dex, alice); - let tested_position = positions_list_after[position_index_to_remove as usize]; - - // Last position should be at removed index - assert_eq!(last_position.pool_key, tested_position.pool_key); - assert_eq!(last_position.liquidity, tested_position.liquidity); - assert_eq!( - last_position.lower_tick_index, - tested_position.lower_tick_index - ); - assert_eq!( - last_position.upper_tick_index, - tested_position.upper_tick_index - ); - assert_eq!( - last_position.fee_growth_inside_x, - tested_position.fee_growth_inside_x - ); - assert_eq!( - last_position.fee_growth_inside_y, - tested_position.fee_growth_inside_y - ); - assert_eq!(last_position.tokens_owed_x, tested_position.tokens_owed_x); - assert_eq!(last_position.tokens_owed_y, tested_position.tokens_owed_y); - } - // Add position in place of the removed one - { - let positions_list_before = get_all_positions!(client, ContractRef, dex, alice); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[1], - tick_indexes[2], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - let positions_list_after = get_all_positions!(client, ContractRef, dex, alice); - assert_eq!(positions_list_before.len() + 1, positions_list_after.len()); - } - // Remove last position - { - let last_position_index_before = - get_all_positions!(client, ContractRef, dex, alice).len() - 1; - - remove_position!( - client, - ContractRef, - dex, - last_position_index_before as u32, - alice - ); - - let last_position_index_after = - get_all_positions!(client, ContractRef, dex, alice).len() - 1; - - assert_eq!(last_position_index_before - 1, last_position_index_after) - } - // Remove all positions - { - let last_position_index = get_all_positions!(client, ContractRef, dex, alice).len(); - - for i in (0..last_position_index).rev() { - remove_position!(client, ContractRef, dex, i as u32, alice); - } - - let list_length = get_all_positions!(client, ContractRef, dex, alice).len(); - assert_eq!(list_length, 0); - } - // Add position to cleared list - { - let list_length_before = get_all_positions!(client, ContractRef, dex, alice).len(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - let list_length_after = get_all_positions!(client, ContractRef, dex, alice).len(); - assert_eq!(list_length_after, list_length_before + 1); - } - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn test_only_owner_can_modify_position_list(mut client: ink_e2e::Client) -> () { - let alice = ink_e2e::alice(); - let init_tick = -23028; - - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let initial_balance = 10u128.pow(10); - - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_balance, initial_balance); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 3).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let tick_indexes = [-9780, -42, 0, 9, 276, 32343, -50001]; - let liquidity_delta = Liquidity::from_integer(1_000_000); - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - // Open three positions - { - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[2], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[1], - tick_indexes[4], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - } - - // Remove middle position - { - let position_index_to_remove = 2; - let positions_list_before = get_all_positions!(client, ContractRef, dex, alice); - let last_position = positions_list_before[positions_list_before.len() - 1]; - - remove_position!(client, ContractRef, dex, position_index_to_remove, alice); - - let positions_list_after = get_all_positions!(client, ContractRef, dex, alice); - let tested_position = positions_list_after[position_index_to_remove as usize]; - - // Last position should be at removed index - assert_eq!(last_position.pool_key, tested_position.pool_key); - assert_eq!(last_position.liquidity, tested_position.liquidity); - assert_eq!( - last_position.lower_tick_index, - tested_position.lower_tick_index - ); - assert_eq!( - last_position.upper_tick_index, - tested_position.upper_tick_index - ); - assert_eq!( - last_position.fee_growth_inside_x, - tested_position.fee_growth_inside_x - ); - assert_eq!( - last_position.fee_growth_inside_y, - tested_position.fee_growth_inside_y - ); - assert_eq!(last_position.tokens_owed_x, tested_position.tokens_owed_x); - assert_eq!(last_position.tokens_owed_y, tested_position.tokens_owed_y); - } - // Add position in place of the removed one - { - let positions_list_before = get_all_positions!(client, ContractRef, dex, alice); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[1], - tick_indexes[2], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - let positions_list_after = get_all_positions!(client, ContractRef, dex, alice); - assert_eq!(positions_list_before.len() + 1, positions_list_after.len()); - } - // Remove last position - { - let last_position_index_before = - get_all_positions!(client, ContractRef, dex, alice).len() - 1; - - let unauthorized_user = ink_e2e::bob(); - remove_position!( - client, - ContractRef, - dex, - last_position_index_before as u32, - unauthorized_user - ) - .unwrap(); - } - } - - #[ink_e2e::test] - async fn test_transfer_position_ownership( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - let alice = ink_e2e::alice(); - let init_tick = -23028; - - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let initial_balance = 10u128.pow(10); - - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_balance, initial_balance); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 3).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let tick_indexes = [-9780, -42, 0, 9, 276, 32343, -50001]; - let liquidity_delta = Liquidity::from_integer(1_000_000); - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - { - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - let list_length = get_all_positions!(client, ContractRef, dex, alice).len(); - - assert_eq!(list_length, 1) - } - - let bob_address = address_of!(Bob); - let bob = ink_e2e::bob(); - // Open additional positions - { - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[1], - tick_indexes[2], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[1], - tick_indexes[3], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - } - // Transfer first position - { - let transferred_index = 0; - let owner_list_before = get_all_positions!(client, ContractRef, dex, alice); - let recipient_list_before = get_all_positions!(client, ContractRef, dex, bob); - let removed_position = - get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); - let last_position_before = owner_list_before[owner_list_before.len() - 1]; - - transfer_position!( - client, - ContractRef, - dex, - transferred_index, - bob_address, - alice - ); - - let recipient_position = - get_position!(client, ContractRef, dex, transferred_index, bob).unwrap(); - let owner_list_after = get_all_positions!(client, ContractRef, dex, alice); - let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); - let owner_first_position_after = - get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); - - assert_eq!(recipient_list_after.len(), recipient_list_before.len() + 1); - assert_eq!(owner_list_before.len() - 1, owner_list_after.len()); - - // move last position - positions_equals!(owner_first_position_after, last_position_before); - - // Equals fields od transferred position - positions_equals!(recipient_position, removed_position); - } - - // Transfer middle position - { - let transferred_index = 1; - let owner_list_before = get_all_positions!(client, ContractRef, dex, alice); - let recipient_list_before = get_all_positions!(client, ContractRef, dex, bob); - let removed_position = - get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); - let last_position_before = owner_list_before[owner_list_before.len() - 1]; - - transfer_position!( - client, - ContractRef, - dex, - transferred_index, - bob_address, - alice - ); - - let recipient_position = - get_position!(client, ContractRef, dex, transferred_index, bob).unwrap(); - let owner_list_after = get_all_positions!(client, ContractRef, dex, alice); - let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); - let owner_first_position_after = - get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); - - assert_eq!(recipient_list_after.len(), recipient_list_before.len() + 1); - assert_eq!(owner_list_before.len() - 1, owner_list_after.len()); - - // move last position - positions_equals!(owner_first_position_after, last_position_before); - } - // Transfer last position - { - let owner_list_before = get_all_positions!(client, ContractRef, dex, alice); - let transferred_index = (owner_list_before.len() - 1) as u32; - let recipient_list_before = get_all_positions!(client, ContractRef, dex, bob); - let removed_position = - get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); - - transfer_position!( - client, - ContractRef, - dex, - transferred_index, - bob_address, - alice - ); - - let owner_list_after = get_all_positions!(client, ContractRef, dex, alice); - let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); - let recipient_position_index = (recipient_list_after.len() - 1) as u32; - let recipient_position = - get_position!(client, ContractRef, dex, recipient_position_index, bob).unwrap(); - - positions_equals!(removed_position, recipient_position); - } - - // Clear position - { - let transferred_index = 0; - let owner_list_before = get_all_positions!(client, ContractRef, dex, alice); - let recipient_list_before = get_all_positions!(client, ContractRef, dex, bob); - let removed_position = - get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); - let last_position_before = owner_list_before[owner_list_before.len() - 1]; - - transfer_position!( - client, - ContractRef, - dex, - transferred_index, - bob_address, - alice - ); - - let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); - let recipient_position_index = (recipient_list_after.len() - 1) as u32; - let recipient_position = - get_position!(client, ContractRef, dex, recipient_position_index, bob).unwrap(); - let owner_list_after = get_all_positions!(client, ContractRef, dex, alice); - - assert_eq!(recipient_list_after.len(), recipient_list_before.len() + 1); - assert_eq!(0, owner_list_after.len()); - - // Equals fields od transferred position - positions_equals!(recipient_position, removed_position); - } - - // Get back position - { - let transferred_index = 0; - let owner_list_before = get_all_positions!(client, ContractRef, dex, alice); - let recipient_list_before = get_all_positions!(client, ContractRef, dex, bob); - let removed_position = - get_position!(client, ContractRef, dex, transferred_index, bob).unwrap(); - let last_position_before = recipient_list_before[recipient_list_before.len() - 1]; - - transfer_position!( - client, - ContractRef, - dex, - transferred_index, - address_of!(Alice), - bob - ); - - let owner_list_after = get_all_positions!(client, ContractRef, dex, alice); - let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); - let recipient_first_position_after = - get_position!(client, ContractRef, dex, transferred_index, bob).unwrap(); - - let owner_new_position = - get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); - - assert_eq!(recipient_list_after.len(), recipient_list_before.len() - 1); - assert_eq!(owner_list_before.len() + 1, owner_list_after.len()); - - // move last position - positions_equals!(last_position_before, recipient_first_position_after); - - // Equals fields od transferred position - positions_equals!(owner_new_position, removed_position); - } - - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn test_only_owner_can_transfer_position(mut client: ink_e2e::Client) -> () { - let alice = ink_e2e::alice(); - let init_tick = -23028; - - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let initial_balance = 10u128.pow(10); - - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_balance, initial_balance); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 3).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let tick_indexes = [-9780, -42, 0, 9, 276, 32343, -50001]; - let liquidity_delta = Liquidity::from_integer(1_000_000); - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - { - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - let list_length = get_all_positions!(client, ContractRef, dex, alice).len(); - - assert_eq!(list_length, 1) - } - - let bob_address = address_of!(Bob); - let bob = ink_e2e::bob(); - // Open additional positions - { - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[1], - tick_indexes[2], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[1], - tick_indexes[3], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - } - // Transfer first position - { - let transferred_index = 0; - - transfer_position!( - client, - ContractRef, - dex, - transferred_index, - address_of!(Alice), - bob - ) - .unwrap(); - } - } - - #[ink_e2e::test] - async fn test_swap_x_to_y(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::from_scale(6, 3)); - let initial_amount = 10u128.pow(10); - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_amount, initial_amount); - - let alice = ink_e2e::alice(); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - 0, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_amount, alice); - approve!(client, TokenRef, token_y, dex, initial_amount, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - let lower_tick_index = -20; - let middle_tick_index = -10; - let upper_tick_index = 10; - - let liquidity_delta = Liquidity::from_integer(1000000); - - let position = create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - SqrtPrice::new(0), - SqrtPrice::max_instance(), - alice - ); - - let position = create_position!( - client, - ContractRef, - dex, - pool_key, - middle_tick_index, - upper_tick_index - 20, - liquidity_delta, - SqrtPrice::new(0), - SqrtPrice::max_instance(), - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - assert_eq!(pool.liquidity, liquidity_delta); - - let amount = 1000; - let swap_amount = TokenAmount(amount); - let bob = ink_e2e::bob(); - mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); - approve!(client, TokenRef, token_x, dex, amount, bob); - - let slippage = SqrtPrice::new(MIN_SQRT_PRICE); - let target_sqrt_price = quote!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - slippage - ) - .unwrap() - .target_sqrt_price; - - let before_dex_x = balance_of!(client, TokenRef, token_x, dex); - let before_dex_y = balance_of!(client, TokenRef, token_y, dex); - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - target_sqrt_price, - bob - ); - - // Load states - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let lower_tick = - get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); - let middle_tick = - get_tick!(client, ContractRef, dex, pool_key, middle_tick_index).unwrap(); - let upper_tick = - get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); - let lower_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, lower_tick_index); - let middle_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, middle_tick_index); - let upper_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, upper_tick_index); - let bob_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - let bob_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); - let dex_x = balance_of!(client, TokenRef, token_x, dex); - let dex_y = balance_of!(client, TokenRef, token_y, dex); - let delta_dex_y = before_dex_y - dex_y; - let delta_dex_x = dex_x - before_dex_x; - let expected_y = amount - 10; - let expected_x = 0; - - // Check balances - assert_eq!(bob_x, expected_x); - assert_eq!(bob_y, expected_y); - assert_eq!(delta_dex_x, amount); - assert_eq!(delta_dex_y, expected_y); - - // Check Pool - assert_eq!(pool.fee_growth_global_y, FeeGrowth::new(0)); - assert_eq!( - pool.fee_growth_global_x, - FeeGrowth::new(40000000000000000000000) - ); - assert_eq!(pool.fee_protocol_token_y, TokenAmount(0)); - assert_eq!(pool.fee_protocol_token_x, TokenAmount(2)); - - // Check Ticks - assert_eq!(lower_tick.liquidity_change, liquidity_delta); - assert_eq!(middle_tick.liquidity_change, liquidity_delta); - assert_eq!(upper_tick.liquidity_change, liquidity_delta); - assert_eq!(upper_tick.fee_growth_outside_x, FeeGrowth::new(0)); - assert_eq!( - middle_tick.fee_growth_outside_x, - FeeGrowth::new(30000000000000000000000) - ); - assert_eq!(lower_tick.fee_growth_outside_x, FeeGrowth::new(0)); - assert!(lower_tick_bit); - assert!(middle_tick_bit); - assert!(upper_tick_bit); - - Ok(()) - } - - #[ink_e2e::test] - async fn test_swap_y_to_x(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::from_scale(6, 3)); - let initial_amount = 10u128.pow(10); - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_amount, initial_amount); - - let alice = ink_e2e::alice(); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - 0, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_amount, alice); - approve!(client, TokenRef, token_y, dex, initial_amount, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - let lower_tick_index = -10; - let middle_tick_index = 10; - let upper_tick_index = 20; - - let liquidity_delta = Liquidity::from_integer(1000000); - - let position = create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - SqrtPrice::new(0), - SqrtPrice::max_instance(), - alice - ); - - let position = create_position!( - client, - ContractRef, - dex, - pool_key, - middle_tick_index, - upper_tick_index + 20, - liquidity_delta, - SqrtPrice::new(0), - SqrtPrice::max_instance(), - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - assert_eq!(pool.liquidity, liquidity_delta); - - let amount = 1000; - let swap_amount = TokenAmount(amount); - let bob = ink_e2e::bob(); - mint!(client, TokenRef, token_y, address_of!(Bob), amount, alice); - approve!(client, TokenRef, token_y, dex, amount, bob); - - let target_sqrt_price = SqrtPrice::new(MAX_SQRT_PRICE); - - let target_sqrt_price = quote!( - client, - ContractRef, - dex, - pool_key, - false, - swap_amount, - true, - target_sqrt_price - ) - .unwrap() - .target_sqrt_price; - - let before_dex_x = balance_of!(client, TokenRef, token_x, dex); - let before_dex_y = balance_of!(client, TokenRef, token_y, dex); - - swap!( - client, - ContractRef, - dex, - pool_key, - false, - swap_amount, - true, - target_sqrt_price, - bob - ); - - // Load states - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let lower_tick = - get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); - let middle_tick = - get_tick!(client, ContractRef, dex, pool_key, middle_tick_index).unwrap(); - let upper_tick = - get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); - let lower_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, lower_tick_index); - let middle_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, middle_tick_index); - let upper_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, upper_tick_index); - let bob_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - let bob_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); - let dex_x = balance_of!(client, TokenRef, token_x, dex); - let dex_y = balance_of!(client, TokenRef, token_y, dex); - let delta_dex_x = before_dex_x - dex_x; - let delta_dex_y = dex_y - before_dex_y; - let expected_x = amount - 10; - let expected_y = 0; - - // Check balances - assert_eq!(bob_x, expected_x); - assert_eq!(bob_y, expected_y); - assert_eq!(delta_dex_x, expected_x); - assert_eq!(delta_dex_y, amount); - - // Check Pool - assert_eq!(pool.fee_growth_global_x, FeeGrowth::new(0)); - assert_eq!( - pool.fee_growth_global_y, - FeeGrowth::new(40000000000000000000000) - ); - assert_eq!(pool.fee_protocol_token_x, TokenAmount(0)); - assert_eq!(pool.fee_protocol_token_y, TokenAmount(2)); - - // Check Ticks - assert_eq!(lower_tick.liquidity_change, liquidity_delta); - assert_eq!(middle_tick.liquidity_change, liquidity_delta); - assert_eq!(upper_tick.liquidity_change, liquidity_delta); - assert_eq!(upper_tick.fee_growth_outside_y, FeeGrowth::new(0)); - assert_eq!( - middle_tick.fee_growth_outside_y, - FeeGrowth::new(30000000000000000000000) - ); - assert_eq!(lower_tick.fee_growth_outside_y, FeeGrowth::new(0)); - assert!(lower_tick_bit); - assert!(middle_tick_bit); - assert!(upper_tick_bit); - - Ok(()) - } - - #[ink_e2e::test] - async fn swap_route(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y, token_z) = - init_dex_and_3_tokens!(client, ContractRef, TokenRef); - - let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, u64::MAX as u128, alice); - approve!(client, TokenRef, token_y, dex, u64::MAX as u128, alice); - approve!(client, TokenRef, token_z, dex, u64::MAX as u128, alice); - - let amount = 1000; - let bob = ink_e2e::bob(); - mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); - approve!(client, TokenRef, token_x, dex, amount, bob); - approve!(client, TokenRef, token_y, dex, u64::MAX as u128, bob); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let init_tick = 0; - create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let init_tick = 0; - create_pool!( - client, - ContractRef, - dex, - token_y, - token_z, - fee_tier, - init_tick, - alice - ); - - let pool_key_1 = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let pool_key_2 = PoolKey::new(token_y, token_z, fee_tier).unwrap(); - - let liquidity_delta = Liquidity::new(2u128.pow(63) - 1); - - let pool_1 = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let slippage_limit_lower = pool_1.sqrt_price; - let slippage_limit_upper = pool_1.sqrt_price; - create_position!( - client, - ContractRef, - dex, - pool_key_1, - -1, - 1, - liquidity_delta, - slippage_limit_lower, - slippage_limit_upper, - alice - ); - - let pool_2 = get_pool!(client, ContractRef, dex, token_y, token_z, fee_tier).unwrap(); - let slippage_limit_lower = pool_2.sqrt_price; - let slippage_limit_upper = pool_2.sqrt_price; - create_position!( - client, - ContractRef, - dex, - pool_key_2, - -1, - 1, - liquidity_delta, - slippage_limit_lower, - slippage_limit_upper, - alice - ); - - let amount_in = TokenAmount(1000); - let expected_amount_out = TokenAmount(1000); - let slippage = Percentage::new(0); - let swaps = vec![ - Hop { - pool_key: pool_key_1, - x_to_y: true, - }, - Hop { - pool_key: pool_key_2, - x_to_y: true, - }, - ]; - - let expected_token_amount = - quote_route!(client, ContractRef, dex, amount_in, swaps.clone()).unwrap(); - - swap_route!( - client, - ContractRef, - dex, - amount_in, - expected_token_amount, - slippage, - swaps.clone(), - bob - ); - - let bob_amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - let bob_amount_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); - let bob_amount_z = balance_of!(client, TokenRef, token_z, address_of!(Bob)); - - assert_eq!(bob_amount_x, 0); - assert_eq!(bob_amount_y, 0); - assert_eq!(bob_amount_z, 986); - - let pool_1_after = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - assert_eq!(pool_1_after.fee_protocol_token_x, TokenAmount(1)); - assert_eq!(pool_1_after.fee_protocol_token_y, TokenAmount(0)); - - let pool_2_after = - get_pool!(client, ContractRef, dex, token_y, token_z, fee_tier).unwrap(); - assert_eq!(pool_2_after.fee_protocol_token_x, TokenAmount(1)); - assert_eq!(pool_2_after.fee_protocol_token_y, TokenAmount(0)); - - let alice_amount_x_before = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let alice_amount_y_before = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - let alice_amount_z_before = balance_of!(client, TokenRef, token_z, address_of!(Alice)); - - claim_fee!(client, ContractRef, dex, 0, alice); - claim_fee!(client, ContractRef, dex, 1, alice); - - let alice_amount_x_after = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let alice_amount_y_after = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - let alice_amount_z_after = balance_of!(client, TokenRef, token_z, address_of!(Alice)); - - assert_eq!(alice_amount_x_after - alice_amount_x_before, 4); - assert_eq!(alice_amount_y_after - alice_amount_y_before, 4); - assert_eq!(alice_amount_z_after - alice_amount_z_before, 0); - - Ok(()) - } - - #[ink_e2e::test] - async fn limits_full_range_with_max_liquidity(mut client: ink_e2e::Client) -> () { - let (dex, token_x, token_y) = - init_dex_and_tokens_max_mint_amount!(client, ContractRef, TokenRef); - - let mint_amount = u128::MAX; - let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, u128::MAX, alice); - approve!(client, TokenRef, token_y, dex, u128::MAX, alice); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let init_tick = get_max_tick(1); - create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let current_sqrt_price = pool.sqrt_price; - assert_eq!(pool.current_tick_index, init_tick); - assert_eq!(pool.sqrt_price, calculate_sqrt_price(init_tick).unwrap()); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let liquidity_delta = Liquidity::new(2u128.pow(109) - 1); - let slippage_limit_lower = pool.sqrt_price; - let slippage_limit_upper = pool.sqrt_price; - create_position!( - client, - ContractRef, - dex, - pool_key, - -MAX_TICK, - MAX_TICK, - liquidity_delta, - slippage_limit_lower, - slippage_limit_upper, - alice - ); - - let contract_amount_x = balance_of!(client, TokenRef, token_x, dex); - let contract_amount_y = balance_of!(client, TokenRef, token_y, dex); - - let expected_x = 0; - let expected_y = 42534896005851865508212194815854; // < 2^106 - assert_eq!(contract_amount_x, expected_x); - assert_eq!(contract_amount_y, expected_y); - } - - #[ink_e2e::test] - async fn deposit_limits_at_upper_limit(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y) = - init_dex_and_tokens_max_mint_amount!(client, ContractRef, TokenRef); - - let mint_amount = 2u128.pow(105) - 1; - let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, u128::MAX, alice); - approve!(client, TokenRef, token_y, dex, u128::MAX, alice); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let init_tick = get_max_tick(1); - create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let current_sqrt_price = pool.sqrt_price; - assert_eq!(pool.current_tick_index, init_tick); - assert_eq!(pool.sqrt_price, calculate_sqrt_price(init_tick).unwrap()); - - let position_amount = mint_amount - 1; - - let liquidity_delta = get_liquidity_by_y( - TokenAmount(position_amount), - 0, - MAX_TICK, - pool.sqrt_price, - false, - ) - .unwrap() - .l; - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let slippage_limit_lower = pool.sqrt_price; - let slippage_limit_upper = pool.sqrt_price; - create_position!( - client, - ContractRef, - dex, - pool_key, - 0, - MAX_TICK, - liquidity_delta, - slippage_limit_lower, - slippage_limit_upper, - alice - ); - - Ok(()) - } - - #[ink_e2e::test] - async fn limits_big_deposit_and_swaps(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y) = - init_dex_and_tokens_max_mint_amount!(client, ContractRef, TokenRef); - - let mint_amount = 2u128.pow(76) - 1; - let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, u128::MAX, alice); - approve!(client, TokenRef, token_y, dex, u128::MAX, alice); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let init_tick = 0; - create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let pos_amount = mint_amount / 2; - let lower_tick = -(fee_tier.tick_spacing as i32); - let upper_tick = fee_tier.tick_spacing as i32; - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - let liquidity_delta = get_liquidity_by_x( - TokenAmount(pos_amount), - lower_tick, - upper_tick, - pool.sqrt_price, - false, - ) - .unwrap() - .l; - - let y = get_delta_y( - calculate_sqrt_price(lower_tick).unwrap(), - pool.sqrt_price, - liquidity_delta, - true, - ) - .unwrap(); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let slippage_limit_lower = pool.sqrt_price; - let slippage_limit_upper = pool.sqrt_price; - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick, - upper_tick, - liquidity_delta, - slippage_limit_lower, - slippage_limit_upper, - alice - ); - - let user_amount_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let user_amount_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - assert_eq!(user_amount_x, u128::MAX - pos_amount); - assert_eq!(user_amount_y, u128::MAX - y.get()); - - let contract_amount_x = balance_of!(client, TokenRef, token_x, dex); - let contract_amount_y = balance_of!(client, TokenRef, token_y, dex); - assert_eq!(contract_amount_x, pos_amount); - assert_eq!(contract_amount_y, y.get()); - - let swap_amount = TokenAmount(mint_amount / 8); - - for i in 1..=4 { - let (x_to_y, sqrt_price_limit) = if i % 2 == 0 { - (true, SqrtPrice::new(MIN_SQRT_PRICE)) - } else { - (false, SqrtPrice::new(MAX_SQRT_PRICE)) - }; - - swap!( - client, - ContractRef, - dex, - pool_key, - i % 2 == 0, - swap_amount, - true, - sqrt_price_limit, - alice - ); - } - - Ok(()) - } - - #[ink_e2e::test] - async fn multiple_swap_x_to_y(mut client: ink_e2e::Client) -> E2EResult<()> { - multiple_swap!(client, ContractRef, TokenRef, true); - Ok(()) - } - - #[ink_e2e::test] - async fn limits_big_deposit_x_and_swap_y( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - big_deposit_and_swap!(client, ContractRef, TokenRef, true); - - Ok(()) - } - - #[ink_e2e::test] - async fn multiple_swap_y_to_x(mut client: ink_e2e::Client) -> E2EResult<()> { - multiple_swap!(client, ContractRef, TokenRef, false); - Ok(()) - } - - #[ink_e2e::test] - async fn limits_big_deposit_y_and_swap_x( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - big_deposit_and_swap!(client, ContractRef, TokenRef, false); - - Ok(()) - } - - #[ink_e2e::test] - async fn limits_big_deposit_both_tokens( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - let (dex, token_x, token_y) = - init_dex_and_tokens_max_mint_amount!(client, ContractRef, TokenRef); - - let mint_amount = 2u128.pow(75) - 1; - let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, u128::MAX, alice); - approve!(client, TokenRef, token_y, dex, u128::MAX, alice); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let init_tick = 0; - create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let lower_tick = -(fee_tier.tick_spacing as i32); - let upper_tick = fee_tier.tick_spacing as i32; - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let liquidity_delta = get_liquidity_by_x( - TokenAmount(mint_amount), - lower_tick, - upper_tick, - pool.sqrt_price, - false, - ) - .unwrap() - .l; - let y = get_delta_y( - calculate_sqrt_price(lower_tick).unwrap(), - pool.sqrt_price, - liquidity_delta, - true, - ) - .unwrap(); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let slippage_limit_lower = pool.sqrt_price; - let slippage_limit_upper = pool.sqrt_price; - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick, - upper_tick, - liquidity_delta, - slippage_limit_lower, - slippage_limit_upper, - alice - ); - - let user_amount_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let user_amount_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - assert_eq!(user_amount_x, u128::MAX - mint_amount); - assert_eq!(user_amount_y, u128::MAX - y.get()); - - let contract_amount_x = balance_of!(client, TokenRef, token_x, dex); - let contract_amount_y = balance_of!(client, TokenRef, token_y, dex); - assert_eq!(contract_amount_x, mint_amount); - assert_eq!(contract_amount_y, y.get()); - - Ok(()) - } - - #[ink_e2e::test] - async fn max_tick_cross(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); - init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); - - let mint_amount = u128::MAX; - let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); - - let liquidity = Liquidity::from_integer(10000000); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - for i in (-2560..20).step_by(10) { - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - let slippage_limit_lower = pool.sqrt_price; - let slippage_limit_upper = pool.sqrt_price; - - create_position!( - client, - ContractRef, - dex, - pool_key, - i, - i + 10, - liquidity, - slippage_limit_lower, - slippage_limit_upper, - alice - ); - } - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - assert_eq!(pool.liquidity, liquidity); - - let amount = 760_000; - let bob = ink_e2e::bob(); - mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); - let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - assert_eq!(amount_x, amount); - approve!(client, TokenRef, token_x, dex, amount, bob); - - let pool_before = get_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - pool_key.fee_tier - ) - .unwrap(); - - let swap_amount = TokenAmount::new(amount); - let slippage = SqrtPrice::new(MIN_SQRT_PRICE); - let quote_result = quote!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - slippage - ) - .unwrap(); - - let pool_after_quote = get_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - pool_key.fee_tier - ) - .unwrap(); - - let crosses_after_quote = - ((pool_after_quote.current_tick_index - pool_before.current_tick_index) / 10).abs(); - assert_eq!(crosses_after_quote, 0); - assert_eq!(quote_result.ticks.len() - 1, 145); - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - slippage, - bob - ); - - let pool_after = get_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - pool_key.fee_tier - ) - .unwrap(); - - let crosses = - ((pool_after.current_tick_index - pool_before.current_tick_index) / 10).abs(); - assert_eq!(crosses, 146); - assert_eq!( - pool_after.current_tick_index, - get_tick_at_sqrt_price(quote_result.target_sqrt_price, 10).unwrap() - ); - - Ok(()) - } - - #[ink_e2e::test] - async fn swap_exact_limit(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); - init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - let amount = 1000; - let bob = ink_e2e::bob(); - let alice = ink_e2e::alice(); - mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); - let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - assert_eq!(amount_x, amount); - approve!(client, TokenRef, token_x, dex, amount, bob); - - let swap_amount = TokenAmount::new(amount); - swap_exact_limit!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - bob - ); - - Ok(()) - } - - #[ink_e2e::test] - async fn claim(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); - init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_swap!(client, ContractRef, TokenRef, dex, token_x, token_y); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let alice = ink_e2e::alice(); - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let user_amount_before_claim = - balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let dex_amount_before_claim = balance_of!(client, TokenRef, token_x, dex); - - claim_fee!(client, ContractRef, dex, 0, alice); - - let user_amount_after_claim = - balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let dex_amount_after_claim = balance_of!(client, TokenRef, token_x, dex); - let position = get_position!(client, ContractRef, dex, 0, alice).unwrap(); - let expected_tokens_claimed = 5; - - assert_eq!( - user_amount_after_claim - expected_tokens_claimed, - user_amount_before_claim - ); - assert_eq!( - dex_amount_after_claim + expected_tokens_claimed, - dex_amount_before_claim - ); - assert_eq!(position.fee_growth_inside_x, pool.fee_growth_global_x); - assert_eq!(position.tokens_owed_x, TokenAmount(0)); - - Ok(()) - } - - #[ink_e2e::test] - async fn basic_slippage_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let alice = ink_e2e::alice(); - let (dex, token_x, token_y) = - init_slippage_dex_and_tokens!(client, ContractRef, TokenRef); - let pool_key = init_slippage_pool_with_liquidity!( - client, - ContractRef, - TokenRef, - dex, - token_x, - token_y - ); - let amount = 10u128.pow(8); - let swap_amount = TokenAmount::new(amount); - approve!(client, TokenRef, token_x, dex, amount, alice); - - let target_sqrt_price = SqrtPrice::new(1009940000000000000000001); - swap!( - client, - ContractRef, - dex, - pool_key, - false, - swap_amount, - true, - target_sqrt_price, - alice - ); - let expected_sqrt_price = SqrtPrice::new(1009940000000000000000000); - let pool = get_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - pool_key.fee_tier - ) - .unwrap(); - - assert_eq!(expected_sqrt_price, pool.sqrt_price); - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn swap_close_to_limit_test(mut client: ink_e2e::Client) -> () { - let alice = ink_e2e::alice(); - let (dex, token_x, token_y) = - init_slippage_dex_and_tokens!(client, ContractRef, TokenRef); - let pool_key = init_slippage_pool_with_liquidity!( - client, - ContractRef, - TokenRef, - dex, - token_x, - token_y - ); - let amount = 10u128.pow(8); - let swap_amount = TokenAmount::new(amount); - approve!(client, TokenRef, token_x, dex, amount, alice); - - let target_sqrt_price = calculate_sqrt_price(-98).unwrap(); - swap!( - client, - ContractRef, - dex, - pool_key, - false, - swap_amount, - true, - target_sqrt_price, - alice - ) - .unwrap(); - } - - #[ink_e2e::test] - async fn cross(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); - init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_cross_position!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_cross_swap!(client, ContractRef, TokenRef, dex, token_x, token_y); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let alice = ink_e2e::alice(); - - let upper_tick_index = 10; - let middle_tick_index = -10; - let lower_tick_index = -20; - - let upper_tick = - get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); - let middle_tick = - get_tick!(client, ContractRef, dex, pool_key, middle_tick_index).unwrap(); - let lower_tick = - get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); - - assert_eq!( - upper_tick.liquidity_change, - Liquidity::from_integer(1000000) - ); - assert_eq!( - middle_tick.liquidity_change, - Liquidity::from_integer(1000000) - ); - assert_eq!( - lower_tick.liquidity_change, - Liquidity::from_integer(1000000) - ); - - assert_eq!(upper_tick.fee_growth_outside_x, FeeGrowth::new(0)); - assert_eq!( - middle_tick.fee_growth_outside_x, - FeeGrowth::new(30000000000000000000000) - ); - assert_eq!(lower_tick.fee_growth_outside_x, FeeGrowth::new(0)); - - Ok(()) - } - - #[ink_e2e::test] - async fn swap(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); - init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_swap!(client, ContractRef, TokenRef, dex, token_x, token_y); - Ok(()) - } - - #[ink_e2e::test] - async fn protocol_fee(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); - init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_swap!(client, ContractRef, TokenRef, dex, token_x, token_y); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let alice = ink_e2e::alice(); - withdraw_protocol_fee!(client, ContractRef, dex, pool_key, alice); - - let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let amount_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - assert_eq!(amount_x, 9999999501); - assert_eq!(amount_y, 9999999000); - - let amount_x = balance_of!(client, TokenRef, token_x, dex); - let amount_y = balance_of!(client, TokenRef, token_y, dex); - assert_eq!(amount_x, 1499); - assert_eq!(amount_y, 7); - - let pool_after_withdraw = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - assert_eq!( - pool_after_withdraw.fee_protocol_token_x, - TokenAmount::new(0) - ); - assert_eq!( - pool_after_withdraw.fee_protocol_token_y, - TokenAmount::new(0) - ); - - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn protocol_fee_should_panic(mut client: ink_e2e::Client) -> () { - let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); - init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_swap!(client, ContractRef, TokenRef, dex, token_x, token_y); - - let pool_key = PoolKey::new( - token_x, - token_y, - FeeTier { - fee: Percentage::from_scale(6, 3), - tick_spacing: 10, - }, - ) - .unwrap(); - let bob = ink_e2e::bob(); - withdraw_protocol_fee!(client, ContractRef, dex, pool_key, bob); - } - - #[ink_e2e::test] - async fn constructor_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let constructor = TokenRef::new(500, None, None, 0); - let _token: AccountId = client - .instantiate("token", &ink_e2e::alice(), constructor, 0, None) - .await - .expect("Instantiate failed") - .account_id; - - let constructor = ContractRef::new(Percentage::new(0)); - - let _contract: AccountId = client - .instantiate("contract", &ink_e2e::alice(), constructor, 0, None) - .await - .expect("Instantiate failed") - .account_id; - Ok(()) - } - - #[ink_e2e::test] - async fn change_protocol_fee(mut client: ink_e2e::Client) -> E2EResult<()> { - let contract = create_dex!(client, ContractRef, Percentage::new(0)); - - let protocol_fee = { - let _msg = build_message::(contract.clone()) - .call(|contract| contract.get_protocol_fee()); - client - .call(&ink_e2e::alice(), _msg, 0, None) - .await - .expect("getting protocol fee failed") - } - .return_value(); - - assert_eq!(protocol_fee, Percentage::new(0)); - - let _result = { - let _msg = build_message::(contract.clone()) - .call(|contract| contract.change_protocol_fee(Percentage::new(1))); - client - .call(&ink_e2e::alice(), _msg, 0, None) - .await - .expect("changing protocol fee failed") - }; - - let protocol_fee = { - let _msg = build_message::(contract.clone()) - .call(|contract| contract.get_protocol_fee()); - client - .call(&ink_e2e::alice(), _msg, 0, None) - .await - .expect("getting protocol fee failed") - } - .return_value(); - - assert_eq!(protocol_fee, Percentage::new(1)); - - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn change_protocol_fee_should_panic(mut client: ink_e2e::Client) -> () { - let contract = create_dex!(client, ContractRef, Percentage::new(0)); - - let result = { - let _msg = build_message::(contract.clone()) - .call(|contract| contract.change_protocol_fee(Percentage::new(1))); - client - .call(&ink_e2e::bob(), _msg, 0, None) - .await - .expect("changing protocol fee failed") - }; - } - - #[ink_e2e::test] - async fn create_position(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let (token_x, token_y) = create_tokens!(client, TokenRef, 500, 500); - - let alice = ink_e2e::alice(); - - let fee_tier = FeeTier::new(Percentage::new(0), 1).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - 10, - alice - ); - - approve!(client, TokenRef, token_x, dex, 500, alice); - approve!(client, TokenRef, token_y, dex, 500, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - let position = create_position!( - client, - ContractRef, - dex, - pool_key, - -10, - 10, - Liquidity::new(10), - SqrtPrice::new(0), - SqrtPrice::max_instance(), - alice - ); - - Ok(()) - } - - #[ink_e2e::test] - async fn add_fee_tier_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let fee_tier = FeeTier::new(Percentage::new(0), 10u16).unwrap(); - let alice = ink_e2e::alice(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - let fee_tier = fee_tier_exist!( - client, - ContractRef, - dex, - FeeTier::new(Percentage::new(0), 10).unwrap() - ); - assert!(fee_tier); - Ok(()) - } - - #[ink_e2e::test] - async fn create_standard_fee_tier_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - create_standard_fee_tiers!(client, ContractRef, dex); - let alice = ink_e2e::alice(); - let fee_tier = fee_tier_exist!( - client, - ContractRef, - dex, - FeeTier::new(Percentage::from_scale(5, 2), 100).unwrap() - ); - assert!(fee_tier); - Ok(()) - } - - #[ink_e2e::test] - async fn create_pool_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let (token_x, token_y) = create_tokens!(client, TokenRef, 500, 500); - - let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 100).unwrap(); - let init_tick = 0; - - let alice = ink_e2e::alice(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let result = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - assert!(result.is_ok()); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - Ok(()) - } - - #[ink_e2e::test] - async fn fee_tier_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let admin = ink_e2e::alice(); - let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 100).unwrap(); - let result = add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - assert!(result.is_ok()); - Ok(()) - } - #[ink_e2e::test] - #[should_panic] - async fn invalid_spacing_fee_tier_test(mut client: ink_e2e::Client) -> () { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let admin = ink_e2e::alice(); - // 0 tick spacing | should fail - let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 0).unwrap(); - let result = add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - } - - #[ink_e2e::test] - #[should_panic] - async fn non_admin_fee_tier_caller_test(mut client: ink_e2e::Client) -> () { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let user = ink_e2e::bob(); - // not-admin - let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 10).unwrap(); - let result = add_fee_tier!(client, ContractRef, dex, fee_tier, user).unwrap(); - } - - #[ink_e2e::test] - async fn position_above_current_tick_test( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - let alice = ink_e2e::alice(); - let init_tick = -23028; - - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let initial_balance = 10_000_000_000; - - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_balance, initial_balance); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 4).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let lower_tick_index = -22980; - let upper_tick_index = 0; - let liquidity_delta = Liquidity::new(initial_balance); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - // Load states - let position_state = get_position!(client, ContractRef, dex, 0, alice).unwrap(); - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let lower_tick = - get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); - let upper_tick = - get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); - let lower_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, lower_tick_index); - let upper_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, upper_tick_index); - let alice_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let alice_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - let dex_x = balance_of!(client, TokenRef, token_x, dex); - let dex_y = balance_of!(client, TokenRef, token_y, dex); - - let zero_fee = FeeGrowth::new(0); - let expected_x_increase = 21549; - let expected_y_increase = 0; - - // Check ticks - assert!(lower_tick.index == lower_tick_index); - assert!(upper_tick.index == upper_tick_index); - assert_eq!(lower_tick.liquidity_gross, liquidity_delta); - assert_eq!(upper_tick.liquidity_gross, liquidity_delta); - assert_eq!(lower_tick.liquidity_change, liquidity_delta); - assert_eq!(upper_tick.liquidity_change, liquidity_delta); - assert!(lower_tick.sign); - assert!(!upper_tick.sign); - - // Check pool - assert!(pool_state.liquidity == Liquidity::new(0)); - assert!(pool_state.current_tick_index == init_tick); - - // Check position - assert!(position_state.pool_key == pool_key); - assert!(position_state.liquidity == liquidity_delta); - assert!(position_state.lower_tick_index == lower_tick_index); - assert!(position_state.upper_tick_index == upper_tick_index); - assert!(position_state.fee_growth_inside_x == zero_fee); - assert!(position_state.fee_growth_inside_y == zero_fee); - - // Check balances - assert_eq!(alice_x, initial_balance.checked_sub(dex_x).unwrap()); - assert_eq!(alice_y, initial_balance.checked_sub(dex_y).unwrap()); - - assert_eq!(dex_x, expected_x_increase); - assert_eq!(dex_y, expected_y_increase); - - Ok(()) - } - - #[ink_e2e::test] - async fn multiple_positions_on_same_tick( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - let alice = ink_e2e::alice(); - let init_tick = 0; - - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let initial_balance = 100_000_000; - - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_balance, initial_balance); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 10).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - // Three position on same lower and upper tick - { - let lower_tick_index = -10; - let upper_tick_index = 10; - - let liquidity_delta = Liquidity::new(100); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - let first_position = get_position!(client, ContractRef, dex, 0, alice).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - let second_position = get_position!(client, ContractRef, dex, 1, alice).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - let third_position = get_position!(client, ContractRef, dex, 2, alice).unwrap(); - - assert!(first_position.lower_tick_index == second_position.lower_tick_index); - assert!(first_position.upper_tick_index == second_position.upper_tick_index); - assert!(first_position.lower_tick_index == third_position.lower_tick_index); - assert!(first_position.upper_tick_index == third_position.upper_tick_index); - - // Load states - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let lower_tick = - get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); - let upper_tick = - get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); - let lower_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, lower_tick_index); - let upper_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, upper_tick_index); - let expected_liquidity = Liquidity::new(liquidity_delta.get() * 3); - let zero_fee = FeeGrowth::new(0); - - // Check ticks - assert!(lower_tick.index == lower_tick_index); - assert!(upper_tick.index == upper_tick_index); - assert_eq!(lower_tick.liquidity_gross, expected_liquidity); - assert_eq!(upper_tick.liquidity_gross, expected_liquidity); - assert_eq!(lower_tick.liquidity_change, expected_liquidity); - assert_eq!(upper_tick.liquidity_change, expected_liquidity); - assert!(lower_tick.sign); - assert!(!upper_tick.sign); - - // Check pool - assert_eq!(pool_state.liquidity, expected_liquidity); - assert!(pool_state.current_tick_index == init_tick); - - // Check first position - assert!(first_position.pool_key == pool_key); - assert!(first_position.liquidity == liquidity_delta); - assert!(first_position.lower_tick_index == lower_tick_index); - assert!(first_position.upper_tick_index == upper_tick_index); - assert!(first_position.fee_growth_inside_x == zero_fee); - assert!(first_position.fee_growth_inside_y == zero_fee); - - // Check second position - assert!(second_position.pool_key == pool_key); - assert!(second_position.liquidity == liquidity_delta); - assert!(second_position.lower_tick_index == lower_tick_index); - assert!(second_position.upper_tick_index == upper_tick_index); - assert!(second_position.fee_growth_inside_x == zero_fee); - assert!(second_position.fee_growth_inside_y == zero_fee); - - // Check third position - assert!(third_position.pool_key == pool_key); - assert!(third_position.liquidity == liquidity_delta); - assert!(third_position.lower_tick_index == lower_tick_index); - assert!(third_position.upper_tick_index == upper_tick_index); - assert!(third_position.fee_growth_inside_x == zero_fee); - assert!(third_position.fee_growth_inside_y == zero_fee); - } - { - let lower_tick_index = -10; - let upper_tick_index = 10; - let zero_fee = FeeGrowth::new(0); - - let liquidity_delta = Liquidity::new(100); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - let first_position = get_position!(client, ContractRef, dex, 3, alice).unwrap(); - - // Check first position - assert!(first_position.pool_key == pool_key); - assert!(first_position.liquidity == liquidity_delta); - assert!(first_position.lower_tick_index == lower_tick_index); - assert!(first_position.upper_tick_index == upper_tick_index); - assert!(first_position.fee_growth_inside_x == zero_fee); - assert!(first_position.fee_growth_inside_y == zero_fee); - - let lower_tick_index = -20; - let upper_tick_index = -10; - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - let second_position = get_position!(client, ContractRef, dex, 4, alice).unwrap(); - - // Check second position - assert!(second_position.pool_key == pool_key); - assert!(second_position.liquidity == liquidity_delta); - assert!(second_position.lower_tick_index == lower_tick_index); - assert!(second_position.upper_tick_index == upper_tick_index); - assert!(second_position.fee_growth_inside_x == zero_fee); - assert!(second_position.fee_growth_inside_y == zero_fee); - - let lower_tick_index = 10; - let upper_tick_index = 20; - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - let third_position = get_position!(client, ContractRef, dex, 5, alice).unwrap(); - - // Check third position - assert!(third_position.pool_key == pool_key); - assert!(third_position.liquidity == liquidity_delta); - assert!(third_position.lower_tick_index == lower_tick_index); - assert!(third_position.upper_tick_index == upper_tick_index); - assert!(third_position.fee_growth_inside_x == zero_fee); - assert!(third_position.fee_growth_inside_y == zero_fee); - - // Load states - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let tick_n20 = get_tick!(client, ContractRef, dex, pool_key, -20).unwrap(); - let tick_n10 = get_tick!(client, ContractRef, dex, pool_key, -10).unwrap(); - let tick_10 = get_tick!(client, ContractRef, dex, pool_key, 10).unwrap(); - let tick_20 = get_tick!(client, ContractRef, dex, pool_key, 20).unwrap(); - let tick_n20_bit = is_tick_initialized!(client, ContractRef, dex, pool_key, -20); - let tick_n10_bit = is_tick_initialized!(client, ContractRef, dex, pool_key, -10); - let tick_10_bit = is_tick_initialized!(client, ContractRef, dex, pool_key, 10); - let tick_20_bit = is_tick_initialized!(client, ContractRef, dex, pool_key, 20); - - let expected_active_liquidity = Liquidity::new(400); - - // Check tick -20 - assert_eq!(tick_n20.index, -20); - assert_eq!(tick_n20.liquidity_gross, Liquidity::new(100)); - assert_eq!(tick_n20.liquidity_change, Liquidity::new(100)); - assert!(tick_n20.sign); - assert!(tick_n20_bit); - - // Check tick -10 - assert_eq!(tick_n10.index, -10); - assert_eq!(tick_n10.liquidity_gross, Liquidity::new(500)); - assert_eq!(tick_n10.liquidity_change, Liquidity::new(300)); - assert!(tick_n10.sign); - assert!(tick_n10_bit); - - // Check tick 10 - assert_eq!(tick_10.index, 10); - assert_eq!(tick_10.liquidity_gross, Liquidity::new(500)); - assert_eq!(tick_10.liquidity_change, Liquidity::new(300)); - assert!(!tick_10.sign); - assert!(tick_20_bit); - - // Check tick 20 - assert_eq!(tick_20.index, 20); - assert_eq!(tick_20.liquidity_gross, Liquidity::new(100)); - assert_eq!(tick_20.liquidity_change, Liquidity::new(100)); - assert!(!tick_20.sign); - assert!(tick_20_bit); - - // Check pool - assert_eq!(pool_state.liquidity, expected_active_liquidity); - assert!(pool_state.current_tick_index == init_tick); - } - Ok(()) - } - - #[ink_e2e::test] - async fn position_within_current_tick_test( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - let MAX_TICK_TEST = 177_450; // for tickSpacing 4 - let MIN_TICK_TEST = -MAX_TICK_TEST; - let alice = ink_e2e::alice(); - let init_tick = -23028; - - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let initial_balance = 100_000_000; - - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_balance, initial_balance); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 4).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let lower_tick_index = MIN_TICK_TEST + 10; - let upper_tick_index = MAX_TICK_TEST - 10; - - let liquidity_delta = Liquidity::new(initial_balance); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - // Load states - let position_state = get_position!(client, ContractRef, dex, 0, alice).unwrap(); - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let lower_tick = - get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); - let upper_tick = - get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); - let lower_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, lower_tick_index); - let upper_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, upper_tick_index); - let alice_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let alice_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - let dex_x = balance_of!(client, TokenRef, token_x, dex); - let dex_y = balance_of!(client, TokenRef, token_y, dex); - - let zero_fee = FeeGrowth::new(0); - let expected_x_increase = 317; - let expected_y_increase = 32; - - // Check ticks - assert!(lower_tick.index == lower_tick_index); - assert!(upper_tick.index == upper_tick_index); - assert_eq!(lower_tick.liquidity_gross, liquidity_delta); - assert_eq!(upper_tick.liquidity_gross, liquidity_delta); - assert_eq!(lower_tick.liquidity_change, liquidity_delta); - assert_eq!(upper_tick.liquidity_change, liquidity_delta); - assert!(lower_tick.sign); - assert!(!upper_tick.sign); - - // Check pool - assert!(pool_state.liquidity == liquidity_delta); - assert!(pool_state.current_tick_index == init_tick); - - // Check position - assert!(position_state.pool_key == pool_key); - assert!(position_state.liquidity == liquidity_delta); - assert!(position_state.lower_tick_index == lower_tick_index); - assert!(position_state.upper_tick_index == upper_tick_index); - assert!(position_state.fee_growth_inside_x == zero_fee); - assert!(position_state.fee_growth_inside_y == zero_fee); - - // Check balances - assert_eq!(alice_x, initial_balance.checked_sub(dex_x).unwrap()); - assert_eq!(alice_y, initial_balance.checked_sub(dex_y).unwrap()); - assert_eq!(dex_x, expected_x_increase); - assert_eq!(dex_y, expected_y_increase); - - Ok(()) - } - - #[ink_e2e::test] - async fn position_below_current_tick_test( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - let alice = ink_e2e::alice(); - let init_tick = -23028; - - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let initial_balance = 100_000_000_00; - - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_balance, initial_balance); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 4).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let lower_tick_index = -46080; - let upper_tick_index = -23040; - - let liquidity_delta = Liquidity::new(initial_balance); - - let pool_state_before = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state_before.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - // Load states - let position_state = get_position!(client, ContractRef, dex, 0, alice).unwrap(); - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let lower_tick = - get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); - let upper_tick = - get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); - let lower_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, lower_tick_index); - let upper_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, upper_tick_index); - let alice_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let alice_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - let dex_x = balance_of!(client, TokenRef, token_x, dex); - let dex_y = balance_of!(client, TokenRef, token_y, dex); - - let zero_fee = FeeGrowth::new(0); - let expected_x_increase = 0; - let expected_y_increase = 2162; - - // Check ticks - assert!(lower_tick.index == lower_tick_index); - assert!(upper_tick.index == upper_tick_index); - assert_eq!(lower_tick.liquidity_gross, liquidity_delta); - assert_eq!(upper_tick.liquidity_gross, liquidity_delta); - assert_eq!(lower_tick.liquidity_change, liquidity_delta); - assert_eq!(upper_tick.liquidity_change, liquidity_delta); - assert!(lower_tick.sign); - assert!(!upper_tick.sign); - - // Check pool - assert!(pool_state.liquidity == pool_state_before.liquidity); - assert!(pool_state.current_tick_index == init_tick); - - // Check position - assert!(position_state.pool_key == pool_key); - assert!(position_state.liquidity == liquidity_delta); - assert!(position_state.lower_tick_index == lower_tick_index); - assert!(position_state.upper_tick_index == upper_tick_index); - assert!(position_state.fee_growth_inside_x == zero_fee); - assert!(position_state.fee_growth_inside_y == zero_fee); - - // Check balances - assert_eq!(alice_x, initial_balance.checked_sub(dex_x).unwrap()); - assert_eq!(alice_y, initial_balance.checked_sub(dex_y).unwrap()); - - assert_eq!(dex_x, expected_x_increase); - assert_eq!(dex_y, expected_y_increase); - - Ok(()) - } - - #[ink_e2e::test] - async fn change_fee_reciever_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let (token_x, token_y) = create_tokens!(client, TokenRef, 500, 500); - - let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 1).unwrap(); - let init_tick = 0; - - let alice = ink_e2e::alice(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let result = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - assert!(result.is_ok()); - - let admin = ink_e2e::alice(); - let alice = address_of!(Alice); - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - change_fee_receiver!(client, ContractRef, dex, pool_key, alice, admin); - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - assert_eq!(pool.fee_receiver, alice); - - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn not_admin_change_fee_reciever_test(mut client: ink_e2e::Client) -> () { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let (token_x, token_y) = create_tokens!(client, TokenRef, 500, 500); - - let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 100).unwrap(); - let init_tick = 0; - - let admin = ink_e2e::alice(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - - let result = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - admin - ); - assert!(result.is_ok()); - - let user = ink_e2e::bob(); - let bob = address_of!(Bob); - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - change_fee_receiver!(client, ContractRef, dex, pool_key, bob, user).unwrap(); - } - - #[ink_e2e::test] - async fn remove_position_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - let alice = ink_e2e::alice(); - let bob = ink_e2e::bob(); - let init_tick = 0; - let remove_position_index = 0; - - let initial_mint = 10u128.pow(10); - - let dex = create_dex!(client, ContractRef, Percentage::from_scale(1, 2)); - let (token_x, token_y) = create_tokens!(client, TokenRef, initial_mint, initial_mint); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let lower_tick_index = -20; - let upper_tick_index = 10; - let liquidity_delta = Liquidity::from_integer(1_000_000); - - approve!(client, TokenRef, token_x, dex, initial_mint, alice); - approve!(client, TokenRef, token_y, dex, initial_mint, alice); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - assert_eq!(pool_state.liquidity, liquidity_delta); - - let liquidity_delta = Liquidity::new(liquidity_delta.get() * 1_000_000); - { - let incorrect_lower_tick_index = lower_tick_index - 50; - let incorrect_upper_tick_index = upper_tick_index + 50; - - approve!(client, TokenRef, token_x, dex, liquidity_delta.get(), alice); - approve!(client, TokenRef, token_y, dex, liquidity_delta.get(), alice); - - create_position!( - client, - ContractRef, - dex, - pool_key, - incorrect_lower_tick_index, - incorrect_upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - let position_state = get_position!(client, ContractRef, dex, 1, alice).unwrap(); - // Check position - assert!(position_state.lower_tick_index == incorrect_lower_tick_index); - assert!(position_state.upper_tick_index == incorrect_upper_tick_index); - } - - let amount = 1000; - mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); - let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - assert_eq!(amount_x, amount); - - approve!(client, TokenRef, token_x, dex, amount, bob); - - let pool_state_before = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - let swap_amount = TokenAmount::new(amount); - let slippage = SqrtPrice::new(MIN_SQRT_PRICE); - swap!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - slippage, - bob - ); - - let pool_state_after = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - assert_eq!( - pool_state_after.fee_growth_global_x, - FeeGrowth::new(49999950000049999) - ); - assert_eq!(pool_state_after.fee_protocol_token_x, TokenAmount(1)); - assert_eq!(pool_state_after.fee_protocol_token_y, TokenAmount(0)); - - assert!(pool_state_after - .sqrt_price - .lt(&pool_state_before.sqrt_price)); - - assert_eq!(pool_state_after.liquidity, pool_state_before.liquidity); - assert_eq!(pool_state_after.current_tick_index, -10); - assert_ne!(pool_state_after.sqrt_price, pool_state_before.sqrt_price); - - let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - let amount_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); - assert_eq!(amount_x, 0); - assert_eq!(amount_y, 993); - - // pre load dex balances - let dex_x_before_remove = balance_of!(client, TokenRef, token_x, dex); - let dex_y_before_remove = balance_of!(client, TokenRef, token_y, dex); - - // Remove position - let remove_result = - remove_position!(client, ContractRef, dex, remove_position_index, alice); - - // Load states - let position_state = - get_position!(client, ContractRef, dex, remove_position_index, alice); - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let lower_tick = get_tick!(client, ContractRef, dex, pool_key, lower_tick_index); - let upper_tick = get_tick!(client, ContractRef, dex, pool_key, upper_tick_index); - let lower_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, lower_tick_index); - let upper_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, upper_tick_index); - let alice_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let alice_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - let dex_x = balance_of!(client, TokenRef, token_x, dex); - let dex_y = balance_of!(client, TokenRef, token_y, dex); - let expected_withdrawn_x = 499; - let expected_withdrawn_y = 999; - let expected_fee_x = 0; - - assert_eq!( - dex_x_before_remove - dex_x, - expected_withdrawn_x + expected_fee_x - ); - assert_eq!(dex_y_before_remove - dex_y, expected_withdrawn_y); - - // Check ticks - assert_eq!(lower_tick, Err(InvariantError::TickNotFound)); - assert_eq!(upper_tick, Err(InvariantError::TickNotFound)); - - // Check tickmap - assert!(!lower_tick_bit); - assert!(!upper_tick_bit); - - // Check pool - assert!(pool_state.liquidity == liquidity_delta); - assert!(pool_state.current_tick_index == -10); - - Ok(()) - } - - #[ink_e2e::test] - async fn position_slippage_zero_slippage_and_inside_range( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - let alice = ink_e2e::alice(); - let (dex, token_x, token_y) = - init_slippage_dex_and_tokens!(client, ContractRef, TokenRef); - let pool_key = init_slippage_pool_with_liquidity!( - client, - ContractRef, - TokenRef, - dex, - token_x, - token_y - ); - - let pool = get_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - pool_key.fee_tier - ) - .unwrap(); - - // zero slippage - { - let liquidity_delta = Liquidity::from_integer(1_000_000); - let known_price = pool.sqrt_price; - let tick = pool_key.fee_tier.tick_spacing as i32; - create_position!( - client, - ContractRef, - dex, - pool_key, - -tick, - tick, - liquidity_delta, - known_price, - known_price, - alice - ); - } - // inside range - { - let liquidity_delta = Liquidity::from_integer(1_000_000); - let known_price = SqrtPrice::new(1010000000000000000000000); - let limit_lower = SqrtPrice::new(994734637981406576896367); - let limit_upper = SqrtPrice::new(1025038048074314166333500); - - let tick = pool_key.fee_tier.tick_spacing as i32; - - create_position!( - client, - ContractRef, - dex, - pool_key, - -tick, - tick, - liquidity_delta, - limit_lower, - limit_upper, - alice - ); - } - - Ok(()) - } - #[ink_e2e::test] - #[should_panic] - async fn position_slippage_below_range(mut client: ink_e2e::Client) -> () { - let alice = ink_e2e::alice(); - let (dex, token_x, token_y) = - init_slippage_dex_and_tokens!(client, ContractRef, TokenRef); - let pool_key = init_slippage_pool_with_liquidity!( - client, - ContractRef, - TokenRef, - dex, - token_x, - token_y - ); - - let pool = get_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - pool_key.fee_tier - ) - .unwrap(); - - let liquidity_delta = Liquidity::from_integer(1_000_000); - let known_price = SqrtPrice::new(1030000000000000000000000); - let limit_lower = SqrtPrice::new(1014432353584998786339859); - let limit_upper = SqrtPrice::new(1045335831204498605270797); - let tick = pool_key.fee_tier.tick_spacing as i32; - create_position!( - client, - ContractRef, - dex, - pool_key, - -tick, - tick, - liquidity_delta, - limit_lower, - limit_upper, - alice - ) - .unwrap(); - } - #[ink_e2e::test] - #[should_panic] - async fn position_slippage_above_range(mut client: ink_e2e::Client) -> () { - let alice = ink_e2e::alice(); - let (dex, token_x, token_y) = - init_slippage_dex_and_tokens!(client, ContractRef, TokenRef); - let pool_key = init_slippage_pool_with_liquidity!( - client, - ContractRef, - TokenRef, - dex, - token_x, - token_y - ); - - let pool = get_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - pool_key.fee_tier - ) - .unwrap(); - - let liquidity_delta = Liquidity::from_integer(1_000_000); - let known_price = pool.sqrt_price; - let limit_lower = SqrtPrice::new(955339206774222158009382); - let limit_upper = SqrtPrice::new(984442481813945288458906); - let tick = pool_key.fee_tier.tick_spacing as i32; - create_position!( - client, - ContractRef, - dex, - pool_key, - -tick, - tick, - liquidity_delta, - limit_lower, - limit_upper, - alice - ) - .unwrap(); - } - - #[ink_e2e::test] - #[should_panic] - async fn no_liquidity_swap(mut client: ink_e2e::Client) -> () { - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - let alice = ink_e2e::alice(); - let bob = ink_e2e::bob(); - let init_tick = 0; - - let initial_mint = 10u128.pow(10); - - let dex = create_dex!(client, ContractRef, Percentage::from_scale(1, 2)); - let (token_x, token_y) = create_tokens!(client, TokenRef, initial_mint, initial_mint); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let lower_tick_index = -10; - let upper_tick_index = 10; - - let mint_amount = 10u128.pow(10); - mint!( - client, - TokenRef, - token_x, - address_of!(Alice), - mint_amount, - alice - ); - mint!( - client, - TokenRef, - token_y, - address_of!(Alice), - mint_amount, - alice - ); - - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); - - let liquidity_delta = Liquidity::from_integer(20_006_000); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - assert_eq!(pool_state.liquidity, liquidity_delta); - - let mint_amount = 10067; - mint!( - client, - TokenRef, - token_x, - address_of!(Bob), - mint_amount, - alice - ); - - approve!(client, TokenRef, token_x, dex, mint_amount, bob); - - let dex_x_before = balance_of!(client, TokenRef, token_x, dex); - let dex_y_before = balance_of!(client, TokenRef, token_y, dex); - - let swap_amount = TokenAmount::new(10067); - let target_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); - let quoted_target_sqrt_price = quote!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - target_sqrt_price - ) - .unwrap() - .target_sqrt_price; - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - quoted_target_sqrt_price, - bob - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let expected_price = calculate_sqrt_price(-10).unwrap(); - let expected_y_amount_out = 9999; - - assert_eq!(pool.liquidity, liquidity_delta); - assert_eq!(pool.current_tick_index, lower_tick_index); - assert_eq!(pool.sqrt_price, expected_price); - - let bob_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - let bob_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); - let dex_x_after = balance_of!(client, TokenRef, token_x, dex); - let dex_y_after = balance_of!(client, TokenRef, token_y, dex); - - let delta_dex_x = dex_x_after - dex_x_before; - let delta_dex_y = dex_y_before - dex_y_after; - - assert_eq!(bob_x, 0); - assert_eq!(bob_y, expected_y_amount_out); - assert_eq!(delta_dex_x, swap_amount.get()); - assert_eq!(delta_dex_y, expected_y_amount_out); - assert_eq!( - pool.fee_growth_global_x, - FeeGrowth::new(29991002699190242927121) - ); - assert_eq!(pool.fee_growth_global_y, FeeGrowth::new(0)); - assert_eq!(pool.fee_protocol_token_x, TokenAmount::new(1)); - assert_eq!(pool.fee_protocol_token_y, TokenAmount::new(0)); - - let swap_amount = TokenAmount(1); - let target_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); - let quoted_target_sqrt_price = quote!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - target_sqrt_price - ) - .unwrap() - .target_sqrt_price; - swap!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - quoted_target_sqrt_price, - bob - ); - } - } } diff --git a/src/tests/change_fee_receiver.rs b/src/tests/change_fee_receiver.rs new file mode 100644 index 00000000..5a1dc092 --- /dev/null +++ b/src/tests/change_fee_receiver.rs @@ -0,0 +1,82 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::ContractRef, + contracts::{entrypoints::Invariant, FeeTier, PoolKey}, + math::types::percentage::Percentage, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{ + add_fee_tier, address_of, change_fee_receiver, create_dex, create_pool, create_tokens, + get_pool, + }; + use token::TokenRef; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn change_fee_reciever_test(mut client: ink_e2e::Client) -> E2EResult<()> { + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + let (token_x, token_y) = create_tokens!(client, TokenRef, 500, 500); + + let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 1).unwrap(); + let init_tick = 0; + + let alice = ink_e2e::alice(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + let result = create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + assert!(result.is_ok()); + + let admin = ink_e2e::alice(); + let alice = address_of!(Alice); + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + change_fee_receiver!(client, ContractRef, dex, pool_key, alice, admin); + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + assert_eq!(pool.fee_receiver, alice); + + Ok(()) + } + + #[ink_e2e::test] + #[should_panic] + async fn not_admin_change_fee_reciever_test(mut client: ink_e2e::Client) -> () { + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + let (token_x, token_y) = create_tokens!(client, TokenRef, 500, 500); + + let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 100).unwrap(); + let init_tick = 0; + + let admin = ink_e2e::alice(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + + let result = create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + admin + ); + assert!(result.is_ok()); + + let user = ink_e2e::bob(); + let bob = address_of!(Bob); + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + change_fee_receiver!(client, ContractRef, dex, pool_key, bob, user).unwrap(); + } +} diff --git a/src/tests/change_protocol_fee.rs b/src/tests/change_protocol_fee.rs new file mode 100644 index 00000000..1f295aff --- /dev/null +++ b/src/tests/change_protocol_fee.rs @@ -0,0 +1,65 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::ContractRef, contracts::entrypoints::Invariant, + math::types::percentage::Percentage, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::create_dex; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn change_protocol_fee(mut client: ink_e2e::Client) -> E2EResult<()> { + let contract = create_dex!(client, ContractRef, Percentage::new(0)); + + let protocol_fee = { + let _msg = build_message::(contract.clone()) + .call(|contract| contract.get_protocol_fee()); + client + .call(&ink_e2e::alice(), _msg, 0, None) + .await + .expect("getting protocol fee failed") + } + .return_value(); + + assert_eq!(protocol_fee, Percentage::new(0)); + + let _result = { + let _msg = build_message::(contract.clone()) + .call(|contract| contract.change_protocol_fee(Percentage::new(1))); + client + .call(&ink_e2e::alice(), _msg, 0, None) + .await + .expect("changing protocol fee failed") + }; + + let protocol_fee = { + let _msg = build_message::(contract.clone()) + .call(|contract| contract.get_protocol_fee()); + client + .call(&ink_e2e::alice(), _msg, 0, None) + .await + .expect("getting protocol fee failed") + } + .return_value(); + + assert_eq!(protocol_fee, Percentage::new(1)); + + Ok(()) + } + + #[ink_e2e::test] + #[should_panic] + async fn change_protocol_fee_should_panic(mut client: ink_e2e::Client) -> () { + let contract = create_dex!(client, ContractRef, Percentage::new(0)); + + let _msg = build_message::(contract.clone()) + .call(|contract| contract.change_protocol_fee(Percentage::new(1))); + client + .call(&ink_e2e::bob(), _msg, 0, None) + .await + .expect("changing protocol fee failed"); + } +} diff --git a/src/tests/claim.rs b/src/tests/claim.rs new file mode 100644 index 00000000..c7e1f0f1 --- /dev/null +++ b/src/tests/claim.rs @@ -0,0 +1,58 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::ContractRef, + contracts::{entrypoints::Invariant, FeeTier, PoolKey}, + math::{ + types::{ + fee_growth::FeeGrowth, liquidity::Liquidity, percentage::Percentage, + sqrt_price::sqrt_price::SqrtPrice, token_amount::TokenAmount, + }, + MIN_SQRT_PRICE, + }, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{ + add_fee_tier, address_of, approve, balance_of, claim_fee, create_dex, create_pool, + create_position, create_tokens, get_pool, get_position, init_basic_pool, + init_basic_position, init_basic_swap, init_dex_and_tokens, mint, swap, + }; + use token::{TokenRef, PSP22}; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn claim(mut client: ink_e2e::Client) -> E2EResult<()> { + let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); + init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); + init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); + init_basic_swap!(client, ContractRef, TokenRef, dex, token_x, token_y); + + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); + let alice = ink_e2e::alice(); + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + let user_amount_before_claim = balance_of!(client, TokenRef, token_x, address_of!(Alice)); + let dex_amount_before_claim = balance_of!(client, TokenRef, token_x, dex); + + claim_fee!(client, ContractRef, dex, 0, alice); + + let user_amount_after_claim = balance_of!(client, TokenRef, token_x, address_of!(Alice)); + let dex_amount_after_claim = balance_of!(client, TokenRef, token_x, dex); + let position = get_position!(client, ContractRef, dex, 0, alice).unwrap(); + let expected_tokens_claimed = 5; + + assert_eq!( + user_amount_after_claim - expected_tokens_claimed, + user_amount_before_claim + ); + assert_eq!( + dex_amount_after_claim + expected_tokens_claimed, + dex_amount_before_claim + ); + assert_eq!(position.fee_growth_inside_x, pool.fee_growth_global_x); + assert_eq!(position.tokens_owed_x, TokenAmount(0)); + + Ok(()) + } +} diff --git a/src/tests/constructor.rs b/src/tests/constructor.rs new file mode 100644 index 00000000..5bedc259 --- /dev/null +++ b/src/tests/constructor.rs @@ -0,0 +1,28 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{contract::ContractRef, math::types::percentage::Percentage}; + use decimal::*; + use ink::primitives::AccountId; + use token::TokenRef; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn constructor_test(mut client: ink_e2e::Client) -> E2EResult<()> { + let constructor = TokenRef::new(500, None, None, 0); + let _token: AccountId = client + .instantiate("token", &ink_e2e::alice(), constructor, 0, None) + .await + .expect("Instantiate failed") + .account_id; + + let constructor = ContractRef::new(Percentage::new(0)); + + let _contract: AccountId = client + .instantiate("contract", &ink_e2e::alice(), constructor, 0, None) + .await + .expect("Instantiate failed") + .account_id; + Ok(()) + } +} diff --git a/src/tests/create_pool.rs b/src/tests/create_pool.rs new file mode 100644 index 00000000..1ea755d4 --- /dev/null +++ b/src/tests/create_pool.rs @@ -0,0 +1,42 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::ContractRef, + contracts::{entrypoints::Invariant, FeeTier}, + math::types::percentage::Percentage, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{add_fee_tier, create_dex, create_pool, create_tokens, get_pool}; + use token::TokenRef; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn create_pool_test(mut client: ink_e2e::Client) -> E2EResult<()> { + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + let (token_x, token_y) = create_tokens!(client, TokenRef, 500, 500); + + let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 100).unwrap(); + let init_tick = 0; + + let alice = ink_e2e::alice(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + let result = create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + assert!(result.is_ok()); + + get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + Ok(()) + } +} diff --git a/src/tests/cross.rs b/src/tests/cross.rs new file mode 100644 index 00000000..7afcbe6f --- /dev/null +++ b/src/tests/cross.rs @@ -0,0 +1,66 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::ContractRef, + contracts::{entrypoints::Invariant, FeeTier, PoolKey}, + math::{ + types::{ + fee_growth::FeeGrowth, liquidity::Liquidity, percentage::Percentage, + sqrt_price::sqrt_price::SqrtPrice, token_amount::TokenAmount, + }, + MIN_SQRT_PRICE, + }, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{ + add_fee_tier, address_of, approve, balance_of, create_dex, create_pool, create_position, + create_tokens, get_pool, get_tick, init_basic_pool, init_basic_position, + init_cross_position, init_cross_swap, init_dex_and_tokens, mint, swap, + }; + use token::{TokenRef, PSP22}; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn cross(mut client: ink_e2e::Client) -> E2EResult<()> { + let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); + init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); + init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); + init_cross_position!(client, ContractRef, TokenRef, dex, token_x, token_y); + init_cross_swap!(client, ContractRef, TokenRef, dex, token_x, token_y); + + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + + let upper_tick_index = 10; + let middle_tick_index = -10; + let lower_tick_index = -20; + + let upper_tick = get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); + let middle_tick = get_tick!(client, ContractRef, dex, pool_key, middle_tick_index).unwrap(); + let lower_tick = get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); + + assert_eq!( + upper_tick.liquidity_change, + Liquidity::from_integer(1000000) + ); + assert_eq!( + middle_tick.liquidity_change, + Liquidity::from_integer(1000000) + ); + assert_eq!( + lower_tick.liquidity_change, + Liquidity::from_integer(1000000) + ); + + assert_eq!(upper_tick.fee_growth_outside_x, FeeGrowth::new(0)); + assert_eq!( + middle_tick.fee_growth_outside_x, + FeeGrowth::new(30000000000000000000000) + ); + assert_eq!(lower_tick.fee_growth_outside_x, FeeGrowth::new(0)); + + Ok(()) + } +} diff --git a/src/tests/cross_both_side.rs b/src/tests/cross_both_side.rs index 4d8f572e..10bb5e9e 100644 --- a/src/tests/cross_both_side.rs +++ b/src/tests/cross_both_side.rs @@ -28,7 +28,6 @@ pub mod e2e_tests { async fn cross_both_side_test(mut client: ink_e2e::Client) -> E2EResult<()> { let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); let alice = ink_e2e::alice(); - let bob = ink_e2e::bob(); let init_tick = 0; let initial_mint = 10u128.pow(10); @@ -40,7 +39,7 @@ pub mod e2e_tests { add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - let pool = create_pool!( + create_pool!( client, ContractRef, dex, @@ -295,7 +294,6 @@ pub mod e2e_tests { async fn cross_both_side_not_cross_case_test(mut client: ink_e2e::Client) -> () { let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); let alice = ink_e2e::alice(); - let bob = ink_e2e::bob(); let init_tick = 0; let initial_mint = 10u128.pow(10); @@ -307,7 +305,7 @@ pub mod e2e_tests { add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - let pool = create_pool!( + create_pool!( client, ContractRef, dex, diff --git a/src/tests/fee_tier.rs b/src/tests/fee_tier.rs new file mode 100644 index 00000000..e2d7290e --- /dev/null +++ b/src/tests/fee_tier.rs @@ -0,0 +1,73 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::ContractRef, + contracts::{entrypoints::Invariant, FeeTier}, + math::types::percentage::Percentage, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{add_fee_tier, create_dex, create_standard_fee_tiers, fee_tier_exist}; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn add_fee_tier_test(mut client: ink_e2e::Client) -> E2EResult<()> { + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + let fee_tier = FeeTier::new(Percentage::new(0), 10u16).unwrap(); + let alice = ink_e2e::alice(); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + let fee_tier = fee_tier_exist!( + client, + ContractRef, + dex, + FeeTier::new(Percentage::new(0), 10).unwrap() + ); + assert!(fee_tier); + Ok(()) + } + + #[ink_e2e::test] + async fn fee_tier_test(mut client: ink_e2e::Client) -> E2EResult<()> { + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + let admin = ink_e2e::alice(); + let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 100).unwrap(); + let result = add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + assert!(result.is_ok()); + Ok(()) + } + + #[ink_e2e::test] + #[should_panic] + async fn invalid_spacing_fee_tier_test(mut client: ink_e2e::Client) -> () { + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + let admin = ink_e2e::alice(); + // 0 tick spacing | should fail + let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 0).unwrap(); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + } + + #[ink_e2e::test] + #[should_panic] + async fn non_admin_fee_tier_caller_test(mut client: ink_e2e::Client) -> () { + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + let user = ink_e2e::bob(); + // not-admin + let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 10).unwrap(); + add_fee_tier!(client, ContractRef, dex, fee_tier, user).unwrap(); + } + + #[ink_e2e::test] + async fn create_standard_fee_tier_test(mut client: ink_e2e::Client) -> E2EResult<()> { + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + create_standard_fee_tiers!(client, ContractRef, dex); + let fee_tier = fee_tier_exist!( + client, + ContractRef, + dex, + FeeTier::new(Percentage::from_scale(5, 2), 100).unwrap() + ); + assert!(fee_tier); + Ok(()) + } +} diff --git a/src/tests/limits.rs b/src/tests/limits.rs new file mode 100644 index 00000000..f0900336 --- /dev/null +++ b/src/tests/limits.rs @@ -0,0 +1,331 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::ContractRef, + contracts::{ + entrypoints::Invariant, get_liquidity_by_x, get_liquidity_by_y, FeeTier, PoolKey, + }, + math::{ + liquidity::Liquidity, + math::get_delta_y, + types::{ + percentage::Percentage, + sqrt_price::sqrt_price::{calculate_sqrt_price, get_max_tick, SqrtPrice}, + token_amount::TokenAmount, + }, + MAX_SQRT_PRICE, MAX_TICK, MIN_SQRT_PRICE, + }, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{ + add_fee_tier, address_of, approve, balance_of, big_deposit_and_swap, create_dex, + create_pool, create_position, create_tokens, get_pool, init_dex_and_tokens_max_mint_amount, + swap, + }; + use token::{TokenRef, PSP22}; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn limits_big_deposit_x_and_swap_y(mut client: ink_e2e::Client) -> E2EResult<()> { + big_deposit_and_swap!(client, ContractRef, TokenRef, true); + + Ok(()) + } + + #[ink_e2e::test] + async fn limits_big_deposit_y_and_swap_x(mut client: ink_e2e::Client) -> E2EResult<()> { + big_deposit_and_swap!(client, ContractRef, TokenRef, false); + + Ok(()) + } + + #[ink_e2e::test] + async fn limits_big_deposit_both_tokens(mut client: ink_e2e::Client) -> E2EResult<()> { + let (dex, token_x, token_y) = + init_dex_and_tokens_max_mint_amount!(client, ContractRef, TokenRef); + + let mint_amount = 2u128.pow(75) - 1; + let alice = ink_e2e::alice(); + approve!(client, TokenRef, token_x, dex, u128::MAX, alice); + approve!(client, TokenRef, token_y, dex, u128::MAX, alice); + + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + let init_tick = 0; + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + let lower_tick = -(fee_tier.tick_spacing as i32); + let upper_tick = fee_tier.tick_spacing as i32; + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + let liquidity_delta = get_liquidity_by_x( + TokenAmount(mint_amount), + lower_tick, + upper_tick, + pool.sqrt_price, + false, + ) + .unwrap() + .l; + let y = get_delta_y( + calculate_sqrt_price(lower_tick).unwrap(), + pool.sqrt_price, + liquidity_delta, + true, + ) + .unwrap(); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + let slippage_limit_lower = pool.sqrt_price; + let slippage_limit_upper = pool.sqrt_price; + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick, + upper_tick, + liquidity_delta, + slippage_limit_lower, + slippage_limit_upper, + alice + ); + + let user_amount_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); + let user_amount_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); + assert_eq!(user_amount_x, u128::MAX - mint_amount); + assert_eq!(user_amount_y, u128::MAX - y.get()); + + let contract_amount_x = balance_of!(client, TokenRef, token_x, dex); + let contract_amount_y = balance_of!(client, TokenRef, token_y, dex); + assert_eq!(contract_amount_x, mint_amount); + assert_eq!(contract_amount_y, y.get()); + + Ok(()) + } + + #[ink_e2e::test] + async fn deposit_limits_at_upper_limit(mut client: ink_e2e::Client) -> E2EResult<()> { + let (dex, token_x, token_y) = + init_dex_and_tokens_max_mint_amount!(client, ContractRef, TokenRef); + + let mint_amount = 2u128.pow(105) - 1; + let alice = ink_e2e::alice(); + approve!(client, TokenRef, token_x, dex, u128::MAX, alice); + approve!(client, TokenRef, token_y, dex, u128::MAX, alice); + + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + let init_tick = get_max_tick(1); + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + assert_eq!(pool.current_tick_index, init_tick); + assert_eq!(pool.sqrt_price, calculate_sqrt_price(init_tick).unwrap()); + + let position_amount = mint_amount - 1; + + let liquidity_delta = get_liquidity_by_y( + TokenAmount(position_amount), + 0, + MAX_TICK, + pool.sqrt_price, + false, + ) + .unwrap() + .l; + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + let slippage_limit_lower = pool.sqrt_price; + let slippage_limit_upper = pool.sqrt_price; + create_position!( + client, + ContractRef, + dex, + pool_key, + 0, + MAX_TICK, + liquidity_delta, + slippage_limit_lower, + slippage_limit_upper, + alice + ); + + Ok(()) + } + + #[ink_e2e::test] + async fn limits_big_deposit_and_swaps(mut client: ink_e2e::Client) -> E2EResult<()> { + let (dex, token_x, token_y) = + init_dex_and_tokens_max_mint_amount!(client, ContractRef, TokenRef); + + let mint_amount = 2u128.pow(76) - 1; + let alice = ink_e2e::alice(); + approve!(client, TokenRef, token_x, dex, u128::MAX, alice); + approve!(client, TokenRef, token_y, dex, u128::MAX, alice); + + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + let init_tick = 0; + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + let pos_amount = mint_amount / 2; + let lower_tick = -(fee_tier.tick_spacing as i32); + let upper_tick = fee_tier.tick_spacing as i32; + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + let liquidity_delta = get_liquidity_by_x( + TokenAmount(pos_amount), + lower_tick, + upper_tick, + pool.sqrt_price, + false, + ) + .unwrap() + .l; + + let y = get_delta_y( + calculate_sqrt_price(lower_tick).unwrap(), + pool.sqrt_price, + liquidity_delta, + true, + ) + .unwrap(); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + let slippage_limit_lower = pool.sqrt_price; + let slippage_limit_upper = pool.sqrt_price; + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick, + upper_tick, + liquidity_delta, + slippage_limit_lower, + slippage_limit_upper, + alice + ); + + let user_amount_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); + let user_amount_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); + assert_eq!(user_amount_x, u128::MAX - pos_amount); + assert_eq!(user_amount_y, u128::MAX - y.get()); + + let contract_amount_x = balance_of!(client, TokenRef, token_x, dex); + let contract_amount_y = balance_of!(client, TokenRef, token_y, dex); + assert_eq!(contract_amount_x, pos_amount); + assert_eq!(contract_amount_y, y.get()); + + let swap_amount = TokenAmount(mint_amount / 8); + + for i in 1..=4 { + let (_, sqrt_price_limit) = if i % 2 == 0 { + (true, SqrtPrice::new(MIN_SQRT_PRICE)) + } else { + (false, SqrtPrice::new(MAX_SQRT_PRICE)) + }; + + swap!( + client, + ContractRef, + dex, + pool_key, + i % 2 == 0, + swap_amount, + true, + sqrt_price_limit, + alice + ); + } + + Ok(()) + } + + #[ink_e2e::test] + async fn limits_full_range_with_max_liquidity(mut client: ink_e2e::Client) -> () { + let (dex, token_x, token_y) = + init_dex_and_tokens_max_mint_amount!(client, ContractRef, TokenRef); + + let alice = ink_e2e::alice(); + approve!(client, TokenRef, token_x, dex, u128::MAX, alice); + approve!(client, TokenRef, token_y, dex, u128::MAX, alice); + + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + let init_tick = get_max_tick(1); + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + assert_eq!(pool.current_tick_index, init_tick); + assert_eq!(pool.sqrt_price, calculate_sqrt_price(init_tick).unwrap()); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + let liquidity_delta = Liquidity::new(2u128.pow(109) - 1); + let slippage_limit_lower = pool.sqrt_price; + let slippage_limit_upper = pool.sqrt_price; + create_position!( + client, + ContractRef, + dex, + pool_key, + -MAX_TICK, + MAX_TICK, + liquidity_delta, + slippage_limit_lower, + slippage_limit_upper, + alice + ); + + let contract_amount_x = balance_of!(client, TokenRef, token_x, dex); + let contract_amount_y = balance_of!(client, TokenRef, token_y, dex); + + let expected_x = 0; + let expected_y = 42534896005851865508212194815854; // < 2^106 + assert_eq!(contract_amount_x, expected_x); + assert_eq!(contract_amount_y, expected_y); + } +} diff --git a/src/tests/liquidity_gap.rs b/src/tests/liquidity_gap.rs index 4df7b0ae..a91081dd 100644 --- a/src/tests/liquidity_gap.rs +++ b/src/tests/liquidity_gap.rs @@ -40,7 +40,7 @@ pub mod e2e_tests { add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - let pool = create_pool!( + create_pool!( client, ContractRef, dex, @@ -201,9 +201,125 @@ pub mod e2e_tests { approve!(client, TokenRef, token_x, dex, swap_amount.get(), bob); + let target_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); + let quoted_target_sqrt_price = quote!( + client, + ContractRef, + dex, + pool_key, + true, + swap_amount, + true, + target_sqrt_price + ) + .unwrap() + .target_sqrt_price; + + swap!( + client, + ContractRef, + dex, + pool_key, + true, + swap_amount, + true, + quoted_target_sqrt_price, + bob + ); + get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + Ok(()) + } + + #[ink_e2e::test] + #[should_panic] + async fn no_liquidity_swap(mut client: ink_e2e::Client) -> () { + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); + let alice = ink_e2e::alice(); + let bob = ink_e2e::bob(); + let init_tick = 0; + + let initial_mint = 10u128.pow(10); + + let dex = create_dex!(client, ContractRef, Percentage::from_scale(1, 2)); + let (token_x, token_y) = create_tokens!(client, TokenRef, initial_mint, initial_mint); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + let lower_tick_index = -10; + let upper_tick_index = 10; + + let mint_amount = 10u128.pow(10); + mint!( + client, + TokenRef, + token_x, + address_of!(Alice), + mint_amount, + alice + ); + mint!( + client, + TokenRef, + token_y, + address_of!(Alice), + mint_amount, + alice + ); + + approve!(client, TokenRef, token_x, dex, mint_amount, alice); + approve!(client, TokenRef, token_y, dex, mint_amount, alice); + + let liquidity_delta = Liquidity::from_integer(20_006_000); + + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick_index, + upper_tick_index, + liquidity_delta, + pool_state.sqrt_price, + pool_state.sqrt_price, + alice + ); + + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + assert_eq!(pool_state.liquidity, liquidity_delta); + + let mint_amount = 10067; + mint!( + client, + TokenRef, + token_x, + address_of!(Bob), + mint_amount, + alice + ); + + approve!(client, TokenRef, token_x, dex, mint_amount, bob); + let dex_x_before = balance_of!(client, TokenRef, token_x, dex); let dex_y_before = balance_of!(client, TokenRef, token_y, dex); + let swap_amount = TokenAmount::new(10067); let target_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); let quoted_target_sqrt_price = quote!( client, @@ -229,7 +345,14 @@ pub mod e2e_tests { quoted_target_sqrt_price, bob ); + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + let expected_price = calculate_sqrt_price(-10).unwrap(); + let expected_y_amount_out = 9999; + + assert_eq!(pool.liquidity, liquidity_delta); + assert_eq!(pool.current_tick_index, lower_tick_index); + assert_eq!(pool.sqrt_price, expected_price); let bob_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); let bob_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); @@ -238,6 +361,43 @@ pub mod e2e_tests { let delta_dex_x = dex_x_after - dex_x_before; let delta_dex_y = dex_y_before - dex_y_after; - Ok(()) + + assert_eq!(bob_x, 0); + assert_eq!(bob_y, expected_y_amount_out); + assert_eq!(delta_dex_x, swap_amount.get()); + assert_eq!(delta_dex_y, expected_y_amount_out); + assert_eq!( + pool.fee_growth_global_x, + FeeGrowth::new(29991002699190242927121) + ); + assert_eq!(pool.fee_growth_global_y, FeeGrowth::new(0)); + assert_eq!(pool.fee_protocol_token_x, TokenAmount::new(1)); + assert_eq!(pool.fee_protocol_token_y, TokenAmount::new(0)); + + let swap_amount = TokenAmount(1); + let target_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); + let quoted_target_sqrt_price = quote!( + client, + ContractRef, + dex, + pool_key, + true, + swap_amount, + true, + target_sqrt_price + ) + .unwrap() + .target_sqrt_price; + swap!( + client, + ContractRef, + dex, + pool_key, + true, + swap_amount, + true, + quoted_target_sqrt_price, + bob + ); } } diff --git a/src/tests/max_tick_cross.rs b/src/tests/max_tick_cross.rs new file mode 100644 index 00000000..207875e7 --- /dev/null +++ b/src/tests/max_tick_cross.rs @@ -0,0 +1,142 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::ContractRef, + contracts::{entrypoints::Invariant, FeeTier, PoolKey}, + math::{ + types::{ + liquidity::Liquidity, + percentage::Percentage, + sqrt_price::{log::get_tick_at_sqrt_price, sqrt_price::SqrtPrice}, + token_amount::TokenAmount, + }, + MIN_SQRT_PRICE, + }, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{ + add_fee_tier, address_of, approve, balance_of, create_dex, create_pool, create_position, + create_tokens, get_pool, init_basic_pool, init_dex_and_tokens, mint, quote, swap, + }; + use token::{TokenRef, PSP22}; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn max_tick_cross(mut client: ink_e2e::Client) -> E2EResult<()> { + let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); + init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); + + let mint_amount = u128::MAX; + let alice = ink_e2e::alice(); + approve!(client, TokenRef, token_x, dex, mint_amount, alice); + approve!(client, TokenRef, token_y, dex, mint_amount, alice); + + let liquidity = Liquidity::from_integer(10000000); + + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + + for i in (-2560..20).step_by(10) { + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + let slippage_limit_lower = pool.sqrt_price; + let slippage_limit_upper = pool.sqrt_price; + + create_position!( + client, + ContractRef, + dex, + pool_key, + i, + i + 10, + liquidity, + slippage_limit_lower, + slippage_limit_upper, + alice + ); + } + + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + assert_eq!(pool.liquidity, liquidity); + + let amount = 760_000; + let bob = ink_e2e::bob(); + mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); + let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); + assert_eq!(amount_x, amount); + approve!(client, TokenRef, token_x, dex, amount, bob); + + let pool_before = get_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + pool_key.fee_tier + ) + .unwrap(); + + let swap_amount = TokenAmount::new(amount); + let slippage = SqrtPrice::new(MIN_SQRT_PRICE); + let quote_result = quote!( + client, + ContractRef, + dex, + pool_key, + true, + swap_amount, + true, + slippage + ) + .unwrap(); + + let pool_after_quote = get_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + pool_key.fee_tier + ) + .unwrap(); + + let crosses_after_quote = + ((pool_after_quote.current_tick_index - pool_before.current_tick_index) / 10).abs(); + assert_eq!(crosses_after_quote, 0); + assert_eq!(quote_result.ticks.len() - 1, 145); + + swap!( + client, + ContractRef, + dex, + pool_key, + true, + swap_amount, + true, + slippage, + bob + ); + + let pool_after = get_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + pool_key.fee_tier + ) + .unwrap(); + + let crosses = ((pool_after.current_tick_index - pool_before.current_tick_index) / 10).abs(); + assert_eq!(crosses, 146); + assert_eq!( + pool_after.current_tick_index, + get_tick_at_sqrt_price(quote_result.target_sqrt_price, 10).unwrap() + ); + + Ok(()) + } +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index d1f03cd6..b22b4ea1 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,9 +1,21 @@ pub mod add_fee_tier; +pub mod change_fee_receiver; +pub mod change_protocol_fee; +pub mod claim; +pub mod constructor; +pub mod create_pool; +pub mod cross; pub mod cross_both_side; +pub mod fee_tier; +pub mod limits; pub mod liquidity_gap; +pub mod max_tick_cross; +pub mod multiple_swap; +pub mod position; +pub mod position_list; +pub mod position_slippage; +pub mod protocol_fee; pub mod remove_fee_tier; - -pub use add_fee_tier::*; -pub use cross_both_side::*; -pub use liquidity_gap::*; -pub use remove_fee_tier::*; +pub mod slippage; +pub mod swap; +pub mod swap_route; diff --git a/src/tests/multiple_swap.rs b/src/tests/multiple_swap.rs new file mode 100644 index 00000000..3104487e --- /dev/null +++ b/src/tests/multiple_swap.rs @@ -0,0 +1,36 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::ContractRef, + contracts::{entrypoints::Invariant, get_liquidity, FeeTier, PoolKey}, + math::{ + types::{ + fee_growth::FeeGrowth, percentage::Percentage, sqrt_price::sqrt_price::SqrtPrice, + token_amount::TokenAmount, + }, + MAX_SQRT_PRICE, MIN_SQRT_PRICE, + }, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{ + add_fee_tier, address_of, approve, balance_of, create_dex, create_pool, create_position, + create_tokens, get_pool, init_dex_and_tokens, mint, multiple_swap, quote, swap, + swap_exact_limit, + }; + use token::{TokenRef, PSP22}; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn multiple_swap_x_to_y(mut client: ink_e2e::Client) -> E2EResult<()> { + multiple_swap!(client, ContractRef, TokenRef, true); + Ok(()) + } + + #[ink_e2e::test] + async fn multiple_swap_y_to_x(mut client: ink_e2e::Client) -> E2EResult<()> { + multiple_swap!(client, ContractRef, TokenRef, false); + Ok(()) + } +} diff --git a/src/tests/position.rs b/src/tests/position.rs new file mode 100644 index 00000000..92a5f6c1 --- /dev/null +++ b/src/tests/position.rs @@ -0,0 +1,523 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::ContractRef, + contracts::{entrypoints::Invariant, FeeTier, PoolKey}, + math::{ + types::{ + fee_growth::FeeGrowth, liquidity::Liquidity, percentage::Percentage, + sqrt_price::sqrt_price::SqrtPrice, token_amount::TokenAmount, + }, + MIN_SQRT_PRICE, + }, + InvariantError, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{ + add_fee_tier, address_of, approve, balance_of, create_dex, create_pool, create_position, + create_tokens, get_pool, get_position, get_tick, is_tick_initialized, mint, + remove_position, swap, + }; + use token::{TokenRef, PSP22}; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn create_position(mut client: ink_e2e::Client) -> E2EResult<()> { + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + let (token_x, token_y) = create_tokens!(client, TokenRef, 500, 500); + + let alice = ink_e2e::alice(); + + let fee_tier = FeeTier::new(Percentage::new(0), 1).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + 10, + alice + ); + + approve!(client, TokenRef, token_x, dex, 500, alice); + approve!(client, TokenRef, token_y, dex, 500, alice); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + + create_position!( + client, + ContractRef, + dex, + pool_key, + -10, + 10, + Liquidity::new(10), + SqrtPrice::new(0), + SqrtPrice::max_instance(), + alice + ); + + Ok(()) + } + + #[ink_e2e::test] + async fn remove_position_test(mut client: ink_e2e::Client) -> E2EResult<()> { + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); + let alice = ink_e2e::alice(); + let bob = ink_e2e::bob(); + let init_tick = 0; + let remove_position_index = 0; + + let initial_mint = 10u128.pow(10); + + let dex = create_dex!(client, ContractRef, Percentage::from_scale(1, 2)); + let (token_x, token_y) = create_tokens!(client, TokenRef, initial_mint, initial_mint); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + let lower_tick_index = -20; + let upper_tick_index = 10; + let liquidity_delta = Liquidity::from_integer(1_000_000); + + approve!(client, TokenRef, token_x, dex, initial_mint, alice); + approve!(client, TokenRef, token_y, dex, initial_mint, alice); + + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick_index, + upper_tick_index, + liquidity_delta, + pool_state.sqrt_price, + pool_state.sqrt_price, + alice + ); + + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + assert_eq!(pool_state.liquidity, liquidity_delta); + + let liquidity_delta = Liquidity::new(liquidity_delta.get() * 1_000_000); + { + let incorrect_lower_tick_index = lower_tick_index - 50; + let incorrect_upper_tick_index = upper_tick_index + 50; + + approve!(client, TokenRef, token_x, dex, liquidity_delta.get(), alice); + approve!(client, TokenRef, token_y, dex, liquidity_delta.get(), alice); + + create_position!( + client, + ContractRef, + dex, + pool_key, + incorrect_lower_tick_index, + incorrect_upper_tick_index, + liquidity_delta, + pool_state.sqrt_price, + pool_state.sqrt_price, + alice + ); + + let position_state = get_position!(client, ContractRef, dex, 1, alice).unwrap(); + // Check position + assert!(position_state.lower_tick_index == incorrect_lower_tick_index); + assert!(position_state.upper_tick_index == incorrect_upper_tick_index); + } + + let amount = 1000; + mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); + let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); + assert_eq!(amount_x, amount); + + approve!(client, TokenRef, token_x, dex, amount, bob); + + let pool_state_before = + get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + let swap_amount = TokenAmount::new(amount); + let slippage = SqrtPrice::new(MIN_SQRT_PRICE); + swap!( + client, + ContractRef, + dex, + pool_key, + true, + swap_amount, + true, + slippage, + bob + ); + + let pool_state_after = + get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + assert_eq!( + pool_state_after.fee_growth_global_x, + FeeGrowth::new(49999950000049999) + ); + assert_eq!(pool_state_after.fee_protocol_token_x, TokenAmount(1)); + assert_eq!(pool_state_after.fee_protocol_token_y, TokenAmount(0)); + + assert!(pool_state_after + .sqrt_price + .lt(&pool_state_before.sqrt_price)); + + assert_eq!(pool_state_after.liquidity, pool_state_before.liquidity); + assert_eq!(pool_state_after.current_tick_index, -10); + assert_ne!(pool_state_after.sqrt_price, pool_state_before.sqrt_price); + + let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); + let amount_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); + assert_eq!(amount_x, 0); + assert_eq!(amount_y, 993); + + // pre load dex balances + let dex_x_before_remove = balance_of!(client, TokenRef, token_x, dex); + let dex_y_before_remove = balance_of!(client, TokenRef, token_y, dex); + + // Remove position + remove_position!(client, ContractRef, dex, remove_position_index, alice); + + // Load states + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + let lower_tick = get_tick!(client, ContractRef, dex, pool_key, lower_tick_index); + let upper_tick = get_tick!(client, ContractRef, dex, pool_key, upper_tick_index); + let lower_tick_bit = + is_tick_initialized!(client, ContractRef, dex, pool_key, lower_tick_index); + let upper_tick_bit = + is_tick_initialized!(client, ContractRef, dex, pool_key, upper_tick_index); + let dex_x = balance_of!(client, TokenRef, token_x, dex); + let dex_y = balance_of!(client, TokenRef, token_y, dex); + let expected_withdrawn_x = 499; + let expected_withdrawn_y = 999; + let expected_fee_x = 0; + + assert_eq!( + dex_x_before_remove - dex_x, + expected_withdrawn_x + expected_fee_x + ); + assert_eq!(dex_y_before_remove - dex_y, expected_withdrawn_y); + + // Check ticks + assert_eq!(lower_tick, Err(InvariantError::TickNotFound)); + assert_eq!(upper_tick, Err(InvariantError::TickNotFound)); + + // Check tickmap + assert!(!lower_tick_bit); + assert!(!upper_tick_bit); + + // Check pool + assert!(pool_state.liquidity == liquidity_delta); + assert!(pool_state.current_tick_index == -10); + + Ok(()) + } + + #[ink_e2e::test] + async fn position_within_current_tick_test(mut client: ink_e2e::Client) -> E2EResult<()> { + let max_tick_test = 177_450; // for tickSpacing 4 + let min_tick_test = -max_tick_test; + let alice = ink_e2e::alice(); + let init_tick = -23028; + + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + let initial_balance = 100_000_000; + + let (token_x, token_y) = create_tokens!(client, TokenRef, initial_balance, initial_balance); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 4).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + approve!(client, TokenRef, token_x, dex, initial_balance, alice); + approve!(client, TokenRef, token_y, dex, initial_balance, alice); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + let lower_tick_index = min_tick_test + 10; + let upper_tick_index = max_tick_test - 10; + + let liquidity_delta = Liquidity::new(initial_balance); + + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick_index, + upper_tick_index, + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + + // Load states + let position_state = get_position!(client, ContractRef, dex, 0, alice).unwrap(); + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + let lower_tick = get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); + let upper_tick = get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); + let alice_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); + let alice_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); + let dex_x = balance_of!(client, TokenRef, token_x, dex); + let dex_y = balance_of!(client, TokenRef, token_y, dex); + + let zero_fee = FeeGrowth::new(0); + let expected_x_increase = 317; + let expected_y_increase = 32; + + // Check ticks + assert!(lower_tick.index == lower_tick_index); + assert!(upper_tick.index == upper_tick_index); + assert_eq!(lower_tick.liquidity_gross, liquidity_delta); + assert_eq!(upper_tick.liquidity_gross, liquidity_delta); + assert_eq!(lower_tick.liquidity_change, liquidity_delta); + assert_eq!(upper_tick.liquidity_change, liquidity_delta); + assert!(lower_tick.sign); + assert!(!upper_tick.sign); + + // Check pool + assert!(pool_state.liquidity == liquidity_delta); + assert!(pool_state.current_tick_index == init_tick); + + // Check position + assert!(position_state.pool_key == pool_key); + assert!(position_state.liquidity == liquidity_delta); + assert!(position_state.lower_tick_index == lower_tick_index); + assert!(position_state.upper_tick_index == upper_tick_index); + assert!(position_state.fee_growth_inside_x == zero_fee); + assert!(position_state.fee_growth_inside_y == zero_fee); + + // Check balances + assert_eq!(alice_x, initial_balance.checked_sub(dex_x).unwrap()); + assert_eq!(alice_y, initial_balance.checked_sub(dex_y).unwrap()); + assert_eq!(dex_x, expected_x_increase); + assert_eq!(dex_y, expected_y_increase); + + Ok(()) + } + + #[ink_e2e::test] + async fn position_below_current_tick_test(mut client: ink_e2e::Client) -> E2EResult<()> { + let alice = ink_e2e::alice(); + let init_tick = -23028; + + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + let initial_balance = 100_000_000_00; + + let (token_x, token_y) = create_tokens!(client, TokenRef, initial_balance, initial_balance); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 4).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + approve!(client, TokenRef, token_x, dex, initial_balance, alice); + approve!(client, TokenRef, token_y, dex, initial_balance, alice); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + let lower_tick_index = -46080; + let upper_tick_index = -23040; + + let liquidity_delta = Liquidity::new(initial_balance); + + let pool_state_before = + get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick_index, + upper_tick_index, + liquidity_delta, + pool_state_before.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + + // Load states + let position_state = get_position!(client, ContractRef, dex, 0, alice).unwrap(); + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + let lower_tick = get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); + let upper_tick = get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); + let alice_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); + let alice_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); + let dex_x = balance_of!(client, TokenRef, token_x, dex); + let dex_y = balance_of!(client, TokenRef, token_y, dex); + + let zero_fee = FeeGrowth::new(0); + let expected_x_increase = 0; + let expected_y_increase = 2162; + + // Check ticks + assert!(lower_tick.index == lower_tick_index); + assert!(upper_tick.index == upper_tick_index); + assert_eq!(lower_tick.liquidity_gross, liquidity_delta); + assert_eq!(upper_tick.liquidity_gross, liquidity_delta); + assert_eq!(lower_tick.liquidity_change, liquidity_delta); + assert_eq!(upper_tick.liquidity_change, liquidity_delta); + assert!(lower_tick.sign); + assert!(!upper_tick.sign); + + // Check pool + assert!(pool_state.liquidity == pool_state_before.liquidity); + assert!(pool_state.current_tick_index == init_tick); + + // Check position + assert!(position_state.pool_key == pool_key); + assert!(position_state.liquidity == liquidity_delta); + assert!(position_state.lower_tick_index == lower_tick_index); + assert!(position_state.upper_tick_index == upper_tick_index); + assert!(position_state.fee_growth_inside_x == zero_fee); + assert!(position_state.fee_growth_inside_y == zero_fee); + + // Check balances + assert_eq!(alice_x, initial_balance.checked_sub(dex_x).unwrap()); + assert_eq!(alice_y, initial_balance.checked_sub(dex_y).unwrap()); + + assert_eq!(dex_x, expected_x_increase); + assert_eq!(dex_y, expected_y_increase); + + Ok(()) + } + + #[ink_e2e::test] + async fn position_above_current_tick_test(mut client: ink_e2e::Client) -> E2EResult<()> { + let alice = ink_e2e::alice(); + let init_tick = -23028; + + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + let initial_balance = 10_000_000_000; + + let (token_x, token_y) = create_tokens!(client, TokenRef, initial_balance, initial_balance); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 4).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + approve!(client, TokenRef, token_x, dex, initial_balance, alice); + approve!(client, TokenRef, token_y, dex, initial_balance, alice); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + let lower_tick_index = -22980; + let upper_tick_index = 0; + let liquidity_delta = Liquidity::new(initial_balance); + + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick_index, + upper_tick_index, + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + + // Load states + let position_state = get_position!(client, ContractRef, dex, 0, alice).unwrap(); + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + let lower_tick = get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); + let upper_tick = get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); + let alice_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); + let alice_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); + let dex_x = balance_of!(client, TokenRef, token_x, dex); + let dex_y = balance_of!(client, TokenRef, token_y, dex); + + let zero_fee = FeeGrowth::new(0); + let expected_x_increase = 21549; + let expected_y_increase = 0; + + // Check ticks + assert!(lower_tick.index == lower_tick_index); + assert!(upper_tick.index == upper_tick_index); + assert_eq!(lower_tick.liquidity_gross, liquidity_delta); + assert_eq!(upper_tick.liquidity_gross, liquidity_delta); + assert_eq!(lower_tick.liquidity_change, liquidity_delta); + assert_eq!(upper_tick.liquidity_change, liquidity_delta); + assert!(lower_tick.sign); + assert!(!upper_tick.sign); + + // Check pool + assert!(pool_state.liquidity == Liquidity::new(0)); + assert!(pool_state.current_tick_index == init_tick); + + // Check position + assert!(position_state.pool_key == pool_key); + assert!(position_state.liquidity == liquidity_delta); + assert!(position_state.lower_tick_index == lower_tick_index); + assert!(position_state.upper_tick_index == upper_tick_index); + assert!(position_state.fee_growth_inside_x == zero_fee); + assert!(position_state.fee_growth_inside_y == zero_fee); + + // Check balances + assert_eq!(alice_x, initial_balance.checked_sub(dex_x).unwrap()); + assert_eq!(alice_y, initial_balance.checked_sub(dex_y).unwrap()); + + assert_eq!(dex_x, expected_x_increase); + assert_eq!(dex_y, expected_y_increase); + + Ok(()) + } +} diff --git a/src/tests/position_list.rs b/src/tests/position_list.rs new file mode 100644 index 00000000..a9a69125 --- /dev/null +++ b/src/tests/position_list.rs @@ -0,0 +1,1022 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::ContractRef, + contracts::{entrypoints::Invariant, FeeTier, PoolKey}, + math::types::{ + fee_growth::FeeGrowth, liquidity::Liquidity, percentage::Percentage, + sqrt_price::sqrt_price::SqrtPrice, + }, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{ + add_fee_tier, address_of, approve, create_dex, create_pool, create_position, create_tokens, + get_all_positions, get_pool, get_position, get_tick, is_tick_initialized, positions_equals, + remove_position, transfer_position, + }; + use token::{TokenRef, PSP22}; + + type E2EResult = Result>; + + #[ink_e2e::test] + #[should_panic] + async fn remove_position_from_empty_list(mut client: ink_e2e::Client) -> () { + let dex = create_dex!(client, ContractRef, Percentage::from_scale(6, 3)); + let initial_amount = 10u128.pow(10); + let (token_x, token_y) = create_tokens!(client, TokenRef, initial_amount, initial_amount); + + let alice = ink_e2e::alice(); + + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + let init_tick = -23028; + + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + remove_position!(client, ContractRef, dex, 0, alice).unwrap(); + } + + #[ink_e2e::test] + async fn add_multiple_positions(mut client: ink_e2e::Client) -> E2EResult<()> { + let alice = ink_e2e::alice(); + let init_tick = -23028; + + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + let initial_balance = 10u128.pow(10); + + let (token_x, token_y) = create_tokens!(client, TokenRef, initial_balance, initial_balance); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 3).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + approve!(client, TokenRef, token_x, dex, initial_balance, alice); + approve!(client, TokenRef, token_y, dex, initial_balance, alice); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + let tick_indexes = [-9780, -42, 0, 9, 276, 32343, -50001]; + let liquidity_delta = Liquidity::from_integer(1_000_000); + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + // Open three positions + { + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[0], + tick_indexes[1], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[0], + tick_indexes[1], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[0], + tick_indexes[2], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[1], + tick_indexes[4], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + } + + // Remove middle position + { + let position_index_to_remove = 2; + let positions_list_before = get_all_positions!(client, ContractRef, dex, alice); + let last_position = positions_list_before[positions_list_before.len() - 1]; + + remove_position!(client, ContractRef, dex, position_index_to_remove, alice); + + let positions_list_after = get_all_positions!(client, ContractRef, dex, alice); + let tested_position = positions_list_after[position_index_to_remove as usize]; + + // Last position should be at removed index + assert_eq!(last_position.pool_key, tested_position.pool_key); + assert_eq!(last_position.liquidity, tested_position.liquidity); + assert_eq!( + last_position.lower_tick_index, + tested_position.lower_tick_index + ); + assert_eq!( + last_position.upper_tick_index, + tested_position.upper_tick_index + ); + assert_eq!( + last_position.fee_growth_inside_x, + tested_position.fee_growth_inside_x + ); + assert_eq!( + last_position.fee_growth_inside_y, + tested_position.fee_growth_inside_y + ); + assert_eq!(last_position.tokens_owed_x, tested_position.tokens_owed_x); + assert_eq!(last_position.tokens_owed_y, tested_position.tokens_owed_y); + } + // Add position in place of the removed one + { + let positions_list_before = get_all_positions!(client, ContractRef, dex, alice); + + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[1], + tick_indexes[2], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + + let positions_list_after = get_all_positions!(client, ContractRef, dex, alice); + assert_eq!(positions_list_before.len() + 1, positions_list_after.len()); + } + // Remove last position + { + let last_position_index_before = + get_all_positions!(client, ContractRef, dex, alice).len() - 1; + + remove_position!( + client, + ContractRef, + dex, + last_position_index_before as u32, + alice + ); + + let last_position_index_after = + get_all_positions!(client, ContractRef, dex, alice).len() - 1; + + assert_eq!(last_position_index_before - 1, last_position_index_after) + } + // Remove all positions + { + let last_position_index = get_all_positions!(client, ContractRef, dex, alice).len(); + + for i in (0..last_position_index).rev() { + remove_position!(client, ContractRef, dex, i as u32, alice); + } + + let list_length = get_all_positions!(client, ContractRef, dex, alice).len(); + assert_eq!(list_length, 0); + } + // Add position to cleared list + { + let list_length_before = get_all_positions!(client, ContractRef, dex, alice).len(); + + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[0], + tick_indexes[1], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + let list_length_after = get_all_positions!(client, ContractRef, dex, alice).len(); + assert_eq!(list_length_after, list_length_before + 1); + } + Ok(()) + } + + #[ink_e2e::test] + #[should_panic] + async fn test_only_owner_can_modify_position_list(mut client: ink_e2e::Client) -> () { + let alice = ink_e2e::alice(); + let init_tick = -23028; + + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + let initial_balance = 10u128.pow(10); + + let (token_x, token_y) = create_tokens!(client, TokenRef, initial_balance, initial_balance); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 3).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + approve!(client, TokenRef, token_x, dex, initial_balance, alice); + approve!(client, TokenRef, token_y, dex, initial_balance, alice); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + let tick_indexes = [-9780, -42, 0, 9, 276, 32343, -50001]; + let liquidity_delta = Liquidity::from_integer(1_000_000); + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + // Open three positions + { + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[0], + tick_indexes[1], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[0], + tick_indexes[1], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[0], + tick_indexes[2], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[1], + tick_indexes[4], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + } + + // Remove middle position + { + let position_index_to_remove = 2; + let positions_list_before = get_all_positions!(client, ContractRef, dex, alice); + let last_position = positions_list_before[positions_list_before.len() - 1]; + + remove_position!(client, ContractRef, dex, position_index_to_remove, alice); + + let positions_list_after = get_all_positions!(client, ContractRef, dex, alice); + let tested_position = positions_list_after[position_index_to_remove as usize]; + + // Last position should be at removed index + assert_eq!(last_position.pool_key, tested_position.pool_key); + assert_eq!(last_position.liquidity, tested_position.liquidity); + assert_eq!( + last_position.lower_tick_index, + tested_position.lower_tick_index + ); + assert_eq!( + last_position.upper_tick_index, + tested_position.upper_tick_index + ); + assert_eq!( + last_position.fee_growth_inside_x, + tested_position.fee_growth_inside_x + ); + assert_eq!( + last_position.fee_growth_inside_y, + tested_position.fee_growth_inside_y + ); + assert_eq!(last_position.tokens_owed_x, tested_position.tokens_owed_x); + assert_eq!(last_position.tokens_owed_y, tested_position.tokens_owed_y); + } + // Add position in place of the removed one + { + let positions_list_before = get_all_positions!(client, ContractRef, dex, alice); + + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[1], + tick_indexes[2], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + + let positions_list_after = get_all_positions!(client, ContractRef, dex, alice); + assert_eq!(positions_list_before.len() + 1, positions_list_after.len()); + } + // Remove last position + { + let last_position_index_before = + get_all_positions!(client, ContractRef, dex, alice).len() - 1; + + let unauthorized_user = ink_e2e::bob(); + remove_position!( + client, + ContractRef, + dex, + last_position_index_before as u32, + unauthorized_user + ) + .unwrap(); + } + } + + #[ink_e2e::test] + async fn test_transfer_position_ownership(mut client: ink_e2e::Client) -> E2EResult<()> { + let alice = ink_e2e::alice(); + let init_tick = -23028; + + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + let initial_balance = 10u128.pow(10); + + let (token_x, token_y) = create_tokens!(client, TokenRef, initial_balance, initial_balance); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 3).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + approve!(client, TokenRef, token_x, dex, initial_balance, alice); + approve!(client, TokenRef, token_y, dex, initial_balance, alice); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + let tick_indexes = [-9780, -42, 0, 9, 276, 32343, -50001]; + let liquidity_delta = Liquidity::from_integer(1_000_000); + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + { + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[0], + tick_indexes[1], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + let list_length = get_all_positions!(client, ContractRef, dex, alice).len(); + + assert_eq!(list_length, 1) + } + + let bob_address = address_of!(Bob); + let bob = ink_e2e::bob(); + // Open additional positions + { + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[0], + tick_indexes[1], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[1], + tick_indexes[2], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[1], + tick_indexes[3], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + } + // Transfer first position + { + let transferred_index = 0; + let owner_list_before = get_all_positions!(client, ContractRef, dex, alice); + let recipient_list_before = get_all_positions!(client, ContractRef, dex, bob); + let removed_position = + get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); + let last_position_before = owner_list_before[owner_list_before.len() - 1]; + + transfer_position!( + client, + ContractRef, + dex, + transferred_index, + bob_address, + alice + ); + + let recipient_position = + get_position!(client, ContractRef, dex, transferred_index, bob).unwrap(); + let owner_list_after = get_all_positions!(client, ContractRef, dex, alice); + let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); + let owner_first_position_after = + get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); + + assert_eq!(recipient_list_after.len(), recipient_list_before.len() + 1); + assert_eq!(owner_list_before.len() - 1, owner_list_after.len()); + + // move last position + positions_equals!(owner_first_position_after, last_position_before); + + // Equals fields od transferred position + positions_equals!(recipient_position, removed_position); + } + + // Transfer middle position + { + let transferred_index = 1; + let owner_list_before = get_all_positions!(client, ContractRef, dex, alice); + let recipient_list_before = get_all_positions!(client, ContractRef, dex, bob); + let last_position_before = owner_list_before[owner_list_before.len() - 1]; + + transfer_position!( + client, + ContractRef, + dex, + transferred_index, + bob_address, + alice + ); + + let owner_list_after = get_all_positions!(client, ContractRef, dex, alice); + let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); + let owner_first_position_after = + get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); + + assert_eq!(recipient_list_after.len(), recipient_list_before.len() + 1); + assert_eq!(owner_list_before.len() - 1, owner_list_after.len()); + + // move last position + positions_equals!(owner_first_position_after, last_position_before); + } + // Transfer last position + { + let owner_list_before = get_all_positions!(client, ContractRef, dex, alice); + let transferred_index = (owner_list_before.len() - 1) as u32; + let removed_position = + get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); + + transfer_position!( + client, + ContractRef, + dex, + transferred_index, + bob_address, + alice + ); + + let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); + let recipient_position_index = (recipient_list_after.len() - 1) as u32; + let recipient_position = + get_position!(client, ContractRef, dex, recipient_position_index, bob).unwrap(); + + positions_equals!(removed_position, recipient_position); + } + + // Clear position + { + let transferred_index = 0; + let recipient_list_before = get_all_positions!(client, ContractRef, dex, bob); + let removed_position = + get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); + + transfer_position!( + client, + ContractRef, + dex, + transferred_index, + bob_address, + alice + ); + + let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); + let recipient_position_index = (recipient_list_after.len() - 1) as u32; + let recipient_position = + get_position!(client, ContractRef, dex, recipient_position_index, bob).unwrap(); + let owner_list_after = get_all_positions!(client, ContractRef, dex, alice); + + assert_eq!(recipient_list_after.len(), recipient_list_before.len() + 1); + assert_eq!(0, owner_list_after.len()); + + // Equals fields od transferred position + positions_equals!(recipient_position, removed_position); + } + + // Get back position + { + let transferred_index = 0; + let owner_list_before = get_all_positions!(client, ContractRef, dex, alice); + let recipient_list_before = get_all_positions!(client, ContractRef, dex, bob); + let removed_position = + get_position!(client, ContractRef, dex, transferred_index, bob).unwrap(); + let last_position_before = recipient_list_before[recipient_list_before.len() - 1]; + + transfer_position!( + client, + ContractRef, + dex, + transferred_index, + address_of!(Alice), + bob + ); + + let owner_list_after = get_all_positions!(client, ContractRef, dex, alice); + let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); + let recipient_first_position_after = + get_position!(client, ContractRef, dex, transferred_index, bob).unwrap(); + + let owner_new_position = + get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); + + assert_eq!(recipient_list_after.len(), recipient_list_before.len() - 1); + assert_eq!(owner_list_before.len() + 1, owner_list_after.len()); + + // move last position + positions_equals!(last_position_before, recipient_first_position_after); + + // Equals fields od transferred position + positions_equals!(owner_new_position, removed_position); + } + + Ok(()) + } + + #[ink_e2e::test] + #[should_panic] + async fn test_only_owner_can_transfer_position(mut client: ink_e2e::Client) -> () { + let alice = ink_e2e::alice(); + let init_tick = -23028; + + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + let initial_balance = 10u128.pow(10); + + let (token_x, token_y) = create_tokens!(client, TokenRef, initial_balance, initial_balance); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 3).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + approve!(client, TokenRef, token_x, dex, initial_balance, alice); + approve!(client, TokenRef, token_y, dex, initial_balance, alice); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + let tick_indexes = [-9780, -42, 0, 9, 276, 32343, -50001]; + let liquidity_delta = Liquidity::from_integer(1_000_000); + let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + { + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[0], + tick_indexes[1], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + let list_length = get_all_positions!(client, ContractRef, dex, alice).len(); + + assert_eq!(list_length, 1) + } + + let bob = ink_e2e::bob(); + // Open additional positions + { + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[0], + tick_indexes[1], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[1], + tick_indexes[2], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + create_position!( + client, + ContractRef, + dex, + pool_key, + tick_indexes[1], + tick_indexes[3], + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + } + // Transfer first position + { + let transferred_index = 0; + + transfer_position!( + client, + ContractRef, + dex, + transferred_index, + address_of!(Alice), + bob + ) + .unwrap(); + } + } + + #[ink_e2e::test] + async fn multiple_positions_on_same_tick(mut client: ink_e2e::Client) -> E2EResult<()> { + let alice = ink_e2e::alice(); + let init_tick = 0; + + let dex = create_dex!(client, ContractRef, Percentage::new(0)); + let initial_balance = 100_000_000; + + let (token_x, token_y) = create_tokens!(client, TokenRef, initial_balance, initial_balance); + + let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 10).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + approve!(client, TokenRef, token_x, dex, initial_balance, alice); + approve!(client, TokenRef, token_y, dex, initial_balance, alice); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + // Three position on same lower and upper tick + { + let lower_tick_index = -10; + let upper_tick_index = 10; + + let liquidity_delta = Liquidity::new(100); + + let pool_state = + get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick_index, + upper_tick_index, + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + + let first_position = get_position!(client, ContractRef, dex, 0, alice).unwrap(); + + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick_index, + upper_tick_index, + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + + let second_position = get_position!(client, ContractRef, dex, 1, alice).unwrap(); + + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick_index, + upper_tick_index, + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + + let third_position = get_position!(client, ContractRef, dex, 2, alice).unwrap(); + + assert!(first_position.lower_tick_index == second_position.lower_tick_index); + assert!(first_position.upper_tick_index == second_position.upper_tick_index); + assert!(first_position.lower_tick_index == third_position.lower_tick_index); + assert!(first_position.upper_tick_index == third_position.upper_tick_index); + + // Load states + let pool_state = + get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + let lower_tick = + get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); + let upper_tick = + get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); + let expected_liquidity = Liquidity::new(liquidity_delta.get() * 3); + let zero_fee = FeeGrowth::new(0); + + // Check ticks + assert!(lower_tick.index == lower_tick_index); + assert!(upper_tick.index == upper_tick_index); + assert_eq!(lower_tick.liquidity_gross, expected_liquidity); + assert_eq!(upper_tick.liquidity_gross, expected_liquidity); + assert_eq!(lower_tick.liquidity_change, expected_liquidity); + assert_eq!(upper_tick.liquidity_change, expected_liquidity); + assert!(lower_tick.sign); + assert!(!upper_tick.sign); + + // Check pool + assert_eq!(pool_state.liquidity, expected_liquidity); + assert!(pool_state.current_tick_index == init_tick); + + // Check first position + assert!(first_position.pool_key == pool_key); + assert!(first_position.liquidity == liquidity_delta); + assert!(first_position.lower_tick_index == lower_tick_index); + assert!(first_position.upper_tick_index == upper_tick_index); + assert!(first_position.fee_growth_inside_x == zero_fee); + assert!(first_position.fee_growth_inside_y == zero_fee); + + // Check second position + assert!(second_position.pool_key == pool_key); + assert!(second_position.liquidity == liquidity_delta); + assert!(second_position.lower_tick_index == lower_tick_index); + assert!(second_position.upper_tick_index == upper_tick_index); + assert!(second_position.fee_growth_inside_x == zero_fee); + assert!(second_position.fee_growth_inside_y == zero_fee); + + // Check third position + assert!(third_position.pool_key == pool_key); + assert!(third_position.liquidity == liquidity_delta); + assert!(third_position.lower_tick_index == lower_tick_index); + assert!(third_position.upper_tick_index == upper_tick_index); + assert!(third_position.fee_growth_inside_x == zero_fee); + assert!(third_position.fee_growth_inside_y == zero_fee); + } + { + let lower_tick_index = -10; + let upper_tick_index = 10; + let zero_fee = FeeGrowth::new(0); + + let liquidity_delta = Liquidity::new(100); + + let pool_state = + get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick_index, + upper_tick_index, + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + + let first_position = get_position!(client, ContractRef, dex, 3, alice).unwrap(); + + // Check first position + assert!(first_position.pool_key == pool_key); + assert!(first_position.liquidity == liquidity_delta); + assert!(first_position.lower_tick_index == lower_tick_index); + assert!(first_position.upper_tick_index == upper_tick_index); + assert!(first_position.fee_growth_inside_x == zero_fee); + assert!(first_position.fee_growth_inside_y == zero_fee); + + let lower_tick_index = -20; + let upper_tick_index = -10; + + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick_index, + upper_tick_index, + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + + let second_position = get_position!(client, ContractRef, dex, 4, alice).unwrap(); + + // Check second position + assert!(second_position.pool_key == pool_key); + assert!(second_position.liquidity == liquidity_delta); + assert!(second_position.lower_tick_index == lower_tick_index); + assert!(second_position.upper_tick_index == upper_tick_index); + assert!(second_position.fee_growth_inside_x == zero_fee); + assert!(second_position.fee_growth_inside_y == zero_fee); + + let lower_tick_index = 10; + let upper_tick_index = 20; + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick_index, + upper_tick_index, + liquidity_delta, + pool_state.sqrt_price, + SqrtPrice::max_instance(), + alice + ); + + let third_position = get_position!(client, ContractRef, dex, 5, alice).unwrap(); + + // Check third position + assert!(third_position.pool_key == pool_key); + assert!(third_position.liquidity == liquidity_delta); + assert!(third_position.lower_tick_index == lower_tick_index); + assert!(third_position.upper_tick_index == upper_tick_index); + assert!(third_position.fee_growth_inside_x == zero_fee); + assert!(third_position.fee_growth_inside_y == zero_fee); + + // Load states + let pool_state = + get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + let tick_n20 = get_tick!(client, ContractRef, dex, pool_key, -20).unwrap(); + let tick_n10 = get_tick!(client, ContractRef, dex, pool_key, -10).unwrap(); + let tick_10 = get_tick!(client, ContractRef, dex, pool_key, 10).unwrap(); + let tick_20 = get_tick!(client, ContractRef, dex, pool_key, 20).unwrap(); + let tick_n20_bit = is_tick_initialized!(client, ContractRef, dex, pool_key, -20); + let tick_n10_bit = is_tick_initialized!(client, ContractRef, dex, pool_key, -10); + let tick_20_bit = is_tick_initialized!(client, ContractRef, dex, pool_key, 20); + + let expected_active_liquidity = Liquidity::new(400); + + // Check tick -20 + assert_eq!(tick_n20.index, -20); + assert_eq!(tick_n20.liquidity_gross, Liquidity::new(100)); + assert_eq!(tick_n20.liquidity_change, Liquidity::new(100)); + assert!(tick_n20.sign); + assert!(tick_n20_bit); + + // Check tick -10 + assert_eq!(tick_n10.index, -10); + assert_eq!(tick_n10.liquidity_gross, Liquidity::new(500)); + assert_eq!(tick_n10.liquidity_change, Liquidity::new(300)); + assert!(tick_n10.sign); + assert!(tick_n10_bit); + + // Check tick 10 + assert_eq!(tick_10.index, 10); + assert_eq!(tick_10.liquidity_gross, Liquidity::new(500)); + assert_eq!(tick_10.liquidity_change, Liquidity::new(300)); + assert!(!tick_10.sign); + assert!(tick_20_bit); + + // Check tick 20 + assert_eq!(tick_20.index, 20); + assert_eq!(tick_20.liquidity_gross, Liquidity::new(100)); + assert_eq!(tick_20.liquidity_change, Liquidity::new(100)); + assert!(!tick_20.sign); + assert!(tick_20_bit); + + // Check pool + assert_eq!(pool_state.liquidity, expected_active_liquidity); + assert!(pool_state.current_tick_index == init_tick); + } + Ok(()) + } +} diff --git a/src/tests/position_slippage.rs b/src/tests/position_slippage.rs new file mode 100644 index 00000000..f6a61362 --- /dev/null +++ b/src/tests/position_slippage.rs @@ -0,0 +1,173 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::ContractRef, + contracts::{entrypoints::Invariant, FeeTier, PoolKey}, + math::types::{ + liquidity::Liquidity, percentage::Percentage, sqrt_price::sqrt_price::SqrtPrice, + }, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{ + add_fee_tier, approve, create_dex, create_pool, create_position, create_tokens, get_pool, + init_slippage_dex_and_tokens, init_slippage_pool_with_liquidity, + }; + use token::{TokenRef, PSP22}; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn position_slippage_zero_slippage_and_inside_range( + mut client: ink_e2e::Client, + ) -> E2EResult<()> { + let alice = ink_e2e::alice(); + let (dex, token_x, token_y) = init_slippage_dex_and_tokens!(client, ContractRef, TokenRef); + let pool_key = init_slippage_pool_with_liquidity!( + client, + ContractRef, + TokenRef, + dex, + token_x, + token_y + ); + + let pool = get_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + pool_key.fee_tier + ) + .unwrap(); + + // zero slippage + { + let liquidity_delta = Liquidity::from_integer(1_000_000); + let known_price = pool.sqrt_price; + let tick = pool_key.fee_tier.tick_spacing as i32; + create_position!( + client, + ContractRef, + dex, + pool_key, + -tick, + tick, + liquidity_delta, + known_price, + known_price, + alice + ); + } + // inside range + { + let liquidity_delta = Liquidity::from_integer(1_000_000); + let limit_lower = SqrtPrice::new(994734637981406576896367); + let limit_upper = SqrtPrice::new(1025038048074314166333500); + + let tick = pool_key.fee_tier.tick_spacing as i32; + + create_position!( + client, + ContractRef, + dex, + pool_key, + -tick, + tick, + liquidity_delta, + limit_lower, + limit_upper, + alice + ); + } + + Ok(()) + } + + #[ink_e2e::test] + #[should_panic] + async fn position_slippage_below_range(mut client: ink_e2e::Client) -> () { + let alice = ink_e2e::alice(); + let (dex, token_x, token_y) = init_slippage_dex_and_tokens!(client, ContractRef, TokenRef); + let pool_key = init_slippage_pool_with_liquidity!( + client, + ContractRef, + TokenRef, + dex, + token_x, + token_y + ); + + get_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + pool_key.fee_tier + ) + .unwrap(); + + let liquidity_delta = Liquidity::from_integer(1_000_000); + let limit_lower = SqrtPrice::new(1014432353584998786339859); + let limit_upper = SqrtPrice::new(1045335831204498605270797); + let tick = pool_key.fee_tier.tick_spacing as i32; + create_position!( + client, + ContractRef, + dex, + pool_key, + -tick, + tick, + liquidity_delta, + limit_lower, + limit_upper, + alice + ) + .unwrap(); + } + + #[ink_e2e::test] + #[should_panic] + async fn position_slippage_above_range(mut client: ink_e2e::Client) -> () { + let alice = ink_e2e::alice(); + let (dex, token_x, token_y) = init_slippage_dex_and_tokens!(client, ContractRef, TokenRef); + let pool_key = init_slippage_pool_with_liquidity!( + client, + ContractRef, + TokenRef, + dex, + token_x, + token_y + ); + + get_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + pool_key.fee_tier + ) + .unwrap(); + + let liquidity_delta = Liquidity::from_integer(1_000_000); + let limit_lower = SqrtPrice::new(955339206774222158009382); + let limit_upper = SqrtPrice::new(984442481813945288458906); + let tick = pool_key.fee_tier.tick_spacing as i32; + create_position!( + client, + ContractRef, + dex, + pool_key, + -tick, + tick, + liquidity_delta, + limit_lower, + limit_upper, + alice + ) + .unwrap(); + } +} diff --git a/src/tests/protocol_fee.rs b/src/tests/protocol_fee.rs new file mode 100644 index 00000000..ce8673c0 --- /dev/null +++ b/src/tests/protocol_fee.rs @@ -0,0 +1,80 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::ContractRef, + contracts::{entrypoints::Invariant, FeeTier, PoolKey}, + math::{ + types::{ + fee_growth::FeeGrowth, liquidity::Liquidity, percentage::Percentage, + sqrt_price::sqrt_price::SqrtPrice, token_amount::TokenAmount, + }, + MIN_SQRT_PRICE, + }, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{ + add_fee_tier, address_of, approve, balance_of, create_dex, create_pool, create_position, + create_tokens, get_pool, init_basic_pool, init_basic_position, init_basic_swap, + init_dex_and_tokens, mint, swap, withdraw_protocol_fee, + }; + use token::{TokenRef, PSP22}; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn protocol_fee(mut client: ink_e2e::Client) -> E2EResult<()> { + let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); + init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); + init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); + init_basic_swap!(client, ContractRef, TokenRef, dex, token_x, token_y); + + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + let alice = ink_e2e::alice(); + withdraw_protocol_fee!(client, ContractRef, dex, pool_key, alice); + + let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); + let amount_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); + assert_eq!(amount_x, 9999999501); + assert_eq!(amount_y, 9999999000); + + let amount_x = balance_of!(client, TokenRef, token_x, dex); + let amount_y = balance_of!(client, TokenRef, token_y, dex); + assert_eq!(amount_x, 1499); + assert_eq!(amount_y, 7); + + let pool_after_withdraw = + get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + assert_eq!( + pool_after_withdraw.fee_protocol_token_x, + TokenAmount::new(0) + ); + assert_eq!( + pool_after_withdraw.fee_protocol_token_y, + TokenAmount::new(0) + ); + + Ok(()) + } + + #[ink_e2e::test] + #[should_panic] + async fn protocol_fee_should_panic(mut client: ink_e2e::Client) -> () { + let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); + init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); + init_basic_swap!(client, ContractRef, TokenRef, dex, token_x, token_y); + + let pool_key = PoolKey::new( + token_x, + token_y, + FeeTier { + fee: Percentage::from_scale(6, 3), + tick_spacing: 10, + }, + ) + .unwrap(); + let bob = ink_e2e::bob(); + withdraw_protocol_fee!(client, ContractRef, dex, pool_key, bob); + } +} diff --git a/src/tests/slippage.rs b/src/tests/slippage.rs new file mode 100644 index 00000000..b1cbc8e8 --- /dev/null +++ b/src/tests/slippage.rs @@ -0,0 +1,135 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::ContractRef, + contracts::{entrypoints::Invariant, FeeTier, PoolKey}, + math::{ + types::{ + liquidity::Liquidity, + percentage::Percentage, + sqrt_price::sqrt_price::{calculate_sqrt_price, SqrtPrice}, + token_amount::TokenAmount, + }, + MAX_SQRT_PRICE, MIN_SQRT_PRICE, + }, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{ + add_fee_tier, address_of, approve, balance_of, create_dex, create_pool, create_position, + create_tokens, get_pool, init_basic_pool, init_basic_position, init_dex_and_tokens, + init_slippage_dex_and_tokens, init_slippage_pool_with_liquidity, mint, quote, swap, + swap_exact_limit, + }; + use token::{TokenRef, PSP22}; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn basic_slippage_test(mut client: ink_e2e::Client) -> E2EResult<()> { + let alice = ink_e2e::alice(); + let (dex, token_x, token_y) = init_slippage_dex_and_tokens!(client, ContractRef, TokenRef); + let pool_key = init_slippage_pool_with_liquidity!( + client, + ContractRef, + TokenRef, + dex, + token_x, + token_y + ); + let amount = 10u128.pow(8); + let swap_amount = TokenAmount::new(amount); + approve!(client, TokenRef, token_x, dex, amount, alice); + + let target_sqrt_price = SqrtPrice::new(1009940000000000000000001); + swap!( + client, + ContractRef, + dex, + pool_key, + false, + swap_amount, + true, + target_sqrt_price, + alice + ); + let expected_sqrt_price = SqrtPrice::new(1009940000000000000000000); + let pool = get_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + pool_key.fee_tier + ) + .unwrap(); + + assert_eq!(expected_sqrt_price, pool.sqrt_price); + Ok(()) + } + + #[ink_e2e::test] + #[should_panic] + async fn swap_close_to_limit_test(mut client: ink_e2e::Client) -> () { + let alice = ink_e2e::alice(); + let (dex, token_x, token_y) = init_slippage_dex_and_tokens!(client, ContractRef, TokenRef); + let pool_key = init_slippage_pool_with_liquidity!( + client, + ContractRef, + TokenRef, + dex, + token_x, + token_y + ); + let amount = 10u128.pow(8); + let swap_amount = TokenAmount::new(amount); + approve!(client, TokenRef, token_x, dex, amount, alice); + + let target_sqrt_price = calculate_sqrt_price(-98).unwrap(); + swap!( + client, + ContractRef, + dex, + pool_key, + false, + swap_amount, + true, + target_sqrt_price, + alice + ) + .unwrap(); + } + + #[ink_e2e::test] + async fn swap_exact_limit(mut client: ink_e2e::Client) -> E2EResult<()> { + let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); + init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); + init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); + + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + + let amount = 1000; + let bob = ink_e2e::bob(); + let alice = ink_e2e::alice(); + mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); + let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); + assert_eq!(amount_x, amount); + approve!(client, TokenRef, token_x, dex, amount, bob); + + let swap_amount = TokenAmount::new(amount); + swap_exact_limit!( + client, + ContractRef, + dex, + pool_key, + true, + swap_amount, + true, + bob + ); + + Ok(()) + } +} diff --git a/src/tests/swap.rs b/src/tests/swap.rs new file mode 100644 index 00000000..a41fd89e --- /dev/null +++ b/src/tests/swap.rs @@ -0,0 +1,336 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::ContractRef, + contracts::{entrypoints::Invariant, FeeTier, PoolKey}, + math::{ + types::{ + fee_growth::FeeGrowth, liquidity::Liquidity, percentage::Percentage, + sqrt_price::sqrt_price::SqrtPrice, token_amount::TokenAmount, + }, + MAX_SQRT_PRICE, MIN_SQRT_PRICE, + }, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{ + add_fee_tier, address_of, approve, balance_of, create_dex, create_pool, create_position, + create_tokens, get_pool, get_tick, init_basic_pool, init_basic_position, init_basic_swap, + init_dex_and_tokens, is_tick_initialized, mint, quote, swap, + }; + use token::{TokenRef, PSP22}; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn swap(mut client: ink_e2e::Client) -> E2EResult<()> { + let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); + init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); + init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); + init_basic_swap!(client, ContractRef, TokenRef, dex, token_x, token_y); + Ok(()) + } + + #[ink_e2e::test] + async fn test_swap_x_to_y(mut client: ink_e2e::Client) -> E2EResult<()> { + let dex = create_dex!(client, ContractRef, Percentage::from_scale(6, 3)); + let initial_amount = 10u128.pow(10); + let (token_x, token_y) = create_tokens!(client, TokenRef, initial_amount, initial_amount); + + let alice = ink_e2e::alice(); + + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + 0, + alice + ); + + approve!(client, TokenRef, token_x, dex, initial_amount, alice); + approve!(client, TokenRef, token_y, dex, initial_amount, alice); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + + let lower_tick_index = -20; + let middle_tick_index = -10; + let upper_tick_index = 10; + + let liquidity_delta = Liquidity::from_integer(1000000); + + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick_index, + upper_tick_index, + liquidity_delta, + SqrtPrice::new(0), + SqrtPrice::max_instance(), + alice + ); + + create_position!( + client, + ContractRef, + dex, + pool_key, + middle_tick_index, + upper_tick_index - 20, + liquidity_delta, + SqrtPrice::new(0), + SqrtPrice::max_instance(), + alice + ); + + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + assert_eq!(pool.liquidity, liquidity_delta); + + let amount = 1000; + let swap_amount = TokenAmount(amount); + let bob = ink_e2e::bob(); + mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); + approve!(client, TokenRef, token_x, dex, amount, bob); + + let slippage = SqrtPrice::new(MIN_SQRT_PRICE); + let target_sqrt_price = quote!( + client, + ContractRef, + dex, + pool_key, + true, + swap_amount, + true, + slippage + ) + .unwrap() + .target_sqrt_price; + + let before_dex_x = balance_of!(client, TokenRef, token_x, dex); + let before_dex_y = balance_of!(client, TokenRef, token_y, dex); + + swap!( + client, + ContractRef, + dex, + pool_key, + true, + swap_amount, + true, + target_sqrt_price, + bob + ); + + // Load states + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + let lower_tick = get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); + let middle_tick = get_tick!(client, ContractRef, dex, pool_key, middle_tick_index).unwrap(); + let upper_tick = get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); + let lower_tick_bit = + is_tick_initialized!(client, ContractRef, dex, pool_key, lower_tick_index); + let middle_tick_bit = + is_tick_initialized!(client, ContractRef, dex, pool_key, middle_tick_index); + let upper_tick_bit = + is_tick_initialized!(client, ContractRef, dex, pool_key, upper_tick_index); + let bob_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); + let bob_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); + let dex_x = balance_of!(client, TokenRef, token_x, dex); + let dex_y = balance_of!(client, TokenRef, token_y, dex); + let delta_dex_y = before_dex_y - dex_y; + let delta_dex_x = dex_x - before_dex_x; + let expected_y = amount - 10; + let expected_x = 0; + + // Check balances + assert_eq!(bob_x, expected_x); + assert_eq!(bob_y, expected_y); + assert_eq!(delta_dex_x, amount); + assert_eq!(delta_dex_y, expected_y); + + // Check Pool + assert_eq!(pool.fee_growth_global_y, FeeGrowth::new(0)); + assert_eq!( + pool.fee_growth_global_x, + FeeGrowth::new(40000000000000000000000) + ); + assert_eq!(pool.fee_protocol_token_y, TokenAmount(0)); + assert_eq!(pool.fee_protocol_token_x, TokenAmount(2)); + + // Check Ticks + assert_eq!(lower_tick.liquidity_change, liquidity_delta); + assert_eq!(middle_tick.liquidity_change, liquidity_delta); + assert_eq!(upper_tick.liquidity_change, liquidity_delta); + assert_eq!(upper_tick.fee_growth_outside_x, FeeGrowth::new(0)); + assert_eq!( + middle_tick.fee_growth_outside_x, + FeeGrowth::new(30000000000000000000000) + ); + assert_eq!(lower_tick.fee_growth_outside_x, FeeGrowth::new(0)); + assert!(lower_tick_bit); + assert!(middle_tick_bit); + assert!(upper_tick_bit); + + Ok(()) + } + + #[ink_e2e::test] + async fn test_swap_y_to_x(mut client: ink_e2e::Client) -> E2EResult<()> { + let dex = create_dex!(client, ContractRef, Percentage::from_scale(6, 3)); + let initial_amount = 10u128.pow(10); + let (token_x, token_y) = create_tokens!(client, TokenRef, initial_amount, initial_amount); + + let alice = ink_e2e::alice(); + + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + 0, + alice + ); + + approve!(client, TokenRef, token_x, dex, initial_amount, alice); + approve!(client, TokenRef, token_y, dex, initial_amount, alice); + + let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + + let lower_tick_index = -10; + let middle_tick_index = 10; + let upper_tick_index = 20; + + let liquidity_delta = Liquidity::from_integer(1000000); + + create_position!( + client, + ContractRef, + dex, + pool_key, + lower_tick_index, + upper_tick_index, + liquidity_delta, + SqrtPrice::new(0), + SqrtPrice::max_instance(), + alice + ); + + create_position!( + client, + ContractRef, + dex, + pool_key, + middle_tick_index, + upper_tick_index + 20, + liquidity_delta, + SqrtPrice::new(0), + SqrtPrice::max_instance(), + alice + ); + + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + + assert_eq!(pool.liquidity, liquidity_delta); + + let amount = 1000; + let swap_amount = TokenAmount(amount); + let bob = ink_e2e::bob(); + mint!(client, TokenRef, token_y, address_of!(Bob), amount, alice); + approve!(client, TokenRef, token_y, dex, amount, bob); + + let target_sqrt_price = SqrtPrice::new(MAX_SQRT_PRICE); + + let target_sqrt_price = quote!( + client, + ContractRef, + dex, + pool_key, + false, + swap_amount, + true, + target_sqrt_price + ) + .unwrap() + .target_sqrt_price; + + let before_dex_x = balance_of!(client, TokenRef, token_x, dex); + let before_dex_y = balance_of!(client, TokenRef, token_y, dex); + + swap!( + client, + ContractRef, + dex, + pool_key, + false, + swap_amount, + true, + target_sqrt_price, + bob + ); + + // Load states + let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + let lower_tick = get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); + let middle_tick = get_tick!(client, ContractRef, dex, pool_key, middle_tick_index).unwrap(); + let upper_tick = get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); + let lower_tick_bit = + is_tick_initialized!(client, ContractRef, dex, pool_key, lower_tick_index); + let middle_tick_bit = + is_tick_initialized!(client, ContractRef, dex, pool_key, middle_tick_index); + let upper_tick_bit = + is_tick_initialized!(client, ContractRef, dex, pool_key, upper_tick_index); + let bob_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); + let bob_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); + let dex_x = balance_of!(client, TokenRef, token_x, dex); + let dex_y = balance_of!(client, TokenRef, token_y, dex); + let delta_dex_x = before_dex_x - dex_x; + let delta_dex_y = dex_y - before_dex_y; + let expected_x = amount - 10; + let expected_y = 0; + + // Check balances + assert_eq!(bob_x, expected_x); + assert_eq!(bob_y, expected_y); + assert_eq!(delta_dex_x, expected_x); + assert_eq!(delta_dex_y, amount); + + // Check Pool + assert_eq!(pool.fee_growth_global_x, FeeGrowth::new(0)); + assert_eq!( + pool.fee_growth_global_y, + FeeGrowth::new(40000000000000000000000) + ); + assert_eq!(pool.fee_protocol_token_x, TokenAmount(0)); + assert_eq!(pool.fee_protocol_token_y, TokenAmount(2)); + + // Check Ticks + assert_eq!(lower_tick.liquidity_change, liquidity_delta); + assert_eq!(middle_tick.liquidity_change, liquidity_delta); + assert_eq!(upper_tick.liquidity_change, liquidity_delta); + assert_eq!(upper_tick.fee_growth_outside_y, FeeGrowth::new(0)); + assert_eq!( + middle_tick.fee_growth_outside_y, + FeeGrowth::new(30000000000000000000000) + ); + assert_eq!(lower_tick.fee_growth_outside_y, FeeGrowth::new(0)); + assert!(lower_tick_bit); + assert!(middle_tick_bit); + assert!(upper_tick_bit); + + Ok(()) + } +} diff --git a/src/tests/swap_route.rs b/src/tests/swap_route.rs new file mode 100644 index 00000000..ce588232 --- /dev/null +++ b/src/tests/swap_route.rs @@ -0,0 +1,160 @@ +#[cfg(test)] +pub mod e2e_tests { + use crate::{ + contract::{ContractRef, Hop}, + contracts::{entrypoints::Invariant, FeeTier, PoolKey}, + math::types::{liquidity::Liquidity, percentage::Percentage, token_amount::TokenAmount}, + }; + use decimal::*; + use ink_e2e::build_message; + use test_helpers::{ + add_fee_tier, address_of, approve, balance_of, claim_fee, create_3_tokens, create_dex, + create_pool, create_position, get_pool, init_dex_and_3_tokens, mint, quote_route, + swap_route, + }; + use token::{TokenRef, PSP22}; + + type E2EResult = Result>; + + #[ink_e2e::test] + async fn swap_route(mut client: ink_e2e::Client) -> E2EResult<()> { + let (dex, token_x, token_y, token_z) = + init_dex_and_3_tokens!(client, ContractRef, TokenRef); + + let alice = ink_e2e::alice(); + approve!(client, TokenRef, token_x, dex, u64::MAX as u128, alice); + approve!(client, TokenRef, token_y, dex, u64::MAX as u128, alice); + approve!(client, TokenRef, token_z, dex, u64::MAX as u128, alice); + + let amount = 1000; + let bob = ink_e2e::bob(); + mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); + approve!(client, TokenRef, token_x, dex, amount, bob); + approve!(client, TokenRef, token_y, dex, u64::MAX as u128, bob); + + let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); + + add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + + let init_tick = 0; + create_pool!( + client, + ContractRef, + dex, + token_x, + token_y, + fee_tier, + init_tick, + alice + ); + + let init_tick = 0; + create_pool!( + client, + ContractRef, + dex, + token_y, + token_z, + fee_tier, + init_tick, + alice + ); + + let pool_key_1 = PoolKey::new(token_x, token_y, fee_tier).unwrap(); + let pool_key_2 = PoolKey::new(token_y, token_z, fee_tier).unwrap(); + + let liquidity_delta = Liquidity::new(2u128.pow(63) - 1); + + let pool_1 = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + let slippage_limit_lower = pool_1.sqrt_price; + let slippage_limit_upper = pool_1.sqrt_price; + create_position!( + client, + ContractRef, + dex, + pool_key_1, + -1, + 1, + liquidity_delta, + slippage_limit_lower, + slippage_limit_upper, + alice + ); + + let pool_2 = get_pool!(client, ContractRef, dex, token_y, token_z, fee_tier).unwrap(); + let slippage_limit_lower = pool_2.sqrt_price; + let slippage_limit_upper = pool_2.sqrt_price; + create_position!( + client, + ContractRef, + dex, + pool_key_2, + -1, + 1, + liquidity_delta, + slippage_limit_lower, + slippage_limit_upper, + alice + ); + + let amount_in = TokenAmount(1000); + let slippage = Percentage::new(0); + let swaps = vec![ + Hop { + pool_key: pool_key_1, + x_to_y: true, + }, + Hop { + pool_key: pool_key_2, + x_to_y: true, + }, + ]; + + let expected_token_amount = + quote_route!(client, ContractRef, dex, amount_in, swaps.clone()).unwrap(); + + swap_route!( + client, + ContractRef, + dex, + amount_in, + expected_token_amount, + slippage, + swaps.clone(), + bob + ); + + let bob_amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); + let bob_amount_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); + let bob_amount_z = balance_of!(client, TokenRef, token_z, address_of!(Bob)); + + assert_eq!(bob_amount_x, 0); + assert_eq!(bob_amount_y, 0); + assert_eq!(bob_amount_z, 986); + + let pool_1_after = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); + assert_eq!(pool_1_after.fee_protocol_token_x, TokenAmount(1)); + assert_eq!(pool_1_after.fee_protocol_token_y, TokenAmount(0)); + + let pool_2_after = get_pool!(client, ContractRef, dex, token_y, token_z, fee_tier).unwrap(); + assert_eq!(pool_2_after.fee_protocol_token_x, TokenAmount(1)); + assert_eq!(pool_2_after.fee_protocol_token_y, TokenAmount(0)); + + let alice_amount_x_before = balance_of!(client, TokenRef, token_x, address_of!(Alice)); + let alice_amount_y_before = balance_of!(client, TokenRef, token_y, address_of!(Alice)); + let alice_amount_z_before = balance_of!(client, TokenRef, token_z, address_of!(Alice)); + + claim_fee!(client, ContractRef, dex, 0, alice); + claim_fee!(client, ContractRef, dex, 1, alice); + + let alice_amount_x_after = balance_of!(client, TokenRef, token_x, address_of!(Alice)); + let alice_amount_y_after = balance_of!(client, TokenRef, token_y, address_of!(Alice)); + let alice_amount_z_after = balance_of!(client, TokenRef, token_z, address_of!(Alice)); + + assert_eq!(alice_amount_x_after - alice_amount_x_before, 4); + assert_eq!(alice_amount_y_after - alice_amount_y_before, 4); + assert_eq!(alice_amount_z_after - alice_amount_z_before, 0); + + Ok(()) + } +} From ec4e65702409aa3d450174991841f4b7763c43a7 Mon Sep 17 00:00:00 2001 From: zielvna Date: Mon, 4 Dec 2023 20:19:55 +0100 Subject: [PATCH 4/6] remove tests from lib --- src/lib.rs | 4108 ---------------------------------------------------- 1 file changed, 4108 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8886a69a..c3a4b93e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1052,4112 +1052,4 @@ pub mod contract { assert_eq!(contract.fee_tiers.get_all().len(), 0); } } - - #[cfg(all(test, feature = "e2e-tests"))] - pub mod e2e_tests { - use crate::contracts::{get_liquidity, get_liquidity_by_x, get_liquidity_by_y}; - use crate::math::fee_growth::FeeGrowth; - use crate::math::get_delta_y; - use crate::math::sqrt_price::log::get_tick_at_sqrt_price; - use crate::math::sqrt_price::sqrt_price::{calculate_sqrt_price, get_max_tick}; - use crate::math::MAX_TICK; - use ink::prelude::vec; - use ink::prelude::vec::Vec; - use ink_e2e::build_message; - - use test_helpers::{ - add_fee_tier, address_of, approve, balance_of, big_deposit_and_swap, - change_fee_receiver, claim_fee, create_3_tokens, create_dex, create_pool, - create_position, create_standard_fee_tiers, create_tokens, fee_tier_exist, - get_all_positions, get_fee_tiers, get_pool, get_position, get_tick, init_basic_pool, - init_basic_position, init_basic_swap, init_cross_position, init_cross_swap, - init_dex_and_3_tokens, init_dex_and_tokens, init_dex_and_tokens_max_mint_amount, - init_slippage_dex_and_tokens, init_slippage_pool_with_liquidity, is_tick_initialized, - mint, multiple_swap, positions_equals, quote, quote_route, remove_fee_tier, - remove_position, swap, swap_exact_limit, swap_route, transfer_position, - withdraw_protocol_fee, - }; - use token::TokenRef; - - use super::*; - - type E2EResult = Result>; - - #[ink_e2e::test] - async fn add_multiple_fee_tiers(mut client: ink_e2e::Client) -> E2EResult<()> { - let admin = ink_e2e::alice(); - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - - let first_fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, first_fee_tier, admin); - - let second_fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap(); - add_fee_tier!(client, ContractRef, dex, second_fee_tier, admin); - - let third_fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 4).unwrap(); - add_fee_tier!(client, ContractRef, dex, third_fee_tier, admin); - - let exist = fee_tier_exist!( - client, - ContractRef, - dex, - FeeTier::new(Percentage::from_scale(2, 4), 1u16).unwrap() - ); - assert!(exist); - - let exist = fee_tier_exist!( - client, - ContractRef, - dex, - FeeTier::new(Percentage::from_scale(2, 4), 2u16).unwrap() - ); - assert!(exist); - - let exist = fee_tier_exist!( - client, - ContractRef, - dex, - FeeTier::new(Percentage::from_scale(2, 4), 4u16).unwrap() - ); - assert!(exist); - - let fee_tiers = get_fee_tiers!(client, ContractRef, dex); - assert_eq!(fee_tiers.len(), 3); - assert_eq!(fee_tiers[0], first_fee_tier); - assert_eq!(fee_tiers[1], second_fee_tier); - assert_eq!(fee_tiers[2], third_fee_tier); - - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn add_existing_fee_tier(mut client: ink_e2e::Client) -> () { - let admin = ink_e2e::alice(); - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); - } - - #[ink_e2e::test] - #[should_panic] - async fn add_fee_tier_not_admin(mut client: ink_e2e::Client) -> () { - let user = ink_e2e::bob(); - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, user).unwrap(); - } - - #[ink_e2e::test] - async fn add_fee_tier_zero_fee(mut client: ink_e2e::Client) -> E2EResult<()> { - let admin = ink_e2e::alice(); - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - - let fee_tier = FeeTier::new(Percentage::new(0), 10).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn add_fee_tier_tick_spacing_zero(mut client: ink_e2e::Client) -> () { - let admin = ink_e2e::alice(); - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 0).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); - } - #[ink_e2e::test] - async fn remove_fee_tier_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let admin = ink_e2e::alice(); - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - - remove_fee_tier!(client, ContractRef, dex, fee_tier, admin); - let exist = fee_tier_exist!( - client, - ContractRef, - dex, - FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap() - ); - assert!(!exist); - - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn remove_not_existing_fee_tier(mut client: ink_e2e::Client) -> () { - let admin = ink_e2e::alice(); - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap(); - remove_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); - } - - #[ink_e2e::test] - #[should_panic] - async fn remove_fee_tier_not_admin(mut client: ink_e2e::Client) -> () { - let admin = ink_e2e::alice(); - let user = ink_e2e::bob(); - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - - remove_fee_tier!(client, ContractRef, dex, fee_tier, user).unwrap(); - } - - #[ink_e2e::test] - #[should_panic] - async fn remove_position_from_empty_list(mut client: ink_e2e::Client) -> () { - let dex = create_dex!(client, ContractRef, Percentage::from_scale(6, 3)); - let initial_amount = 10u128.pow(10); - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_amount, initial_amount); - - let alice = ink_e2e::alice(); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let init_tick = -23028; - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - remove_position!(client, ContractRef, dex, 0, alice).unwrap(); - } - - #[ink_e2e::test] - async fn add_multiple_positions(mut client: ink_e2e::Client) -> E2EResult<()> { - let alice = ink_e2e::alice(); - let init_tick = -23028; - - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let initial_balance = 10u128.pow(10); - - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_balance, initial_balance); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 3).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let tick_indexes = [-9780, -42, 0, 9, 276, 32343, -50001]; - let liquidity_delta = Liquidity::from_integer(1_000_000); - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - // Open three positions - { - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[2], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[1], - tick_indexes[4], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - } - - // Remove middle position - { - let position_index_to_remove = 2; - let positions_list_before = get_all_positions!(client, ContractRef, dex, alice); - let last_position = positions_list_before[positions_list_before.len() - 1]; - - remove_position!(client, ContractRef, dex, position_index_to_remove, alice); - - let positions_list_after = get_all_positions!(client, ContractRef, dex, alice); - let tested_position = positions_list_after[position_index_to_remove as usize]; - - // Last position should be at removed index - assert_eq!(last_position.pool_key, tested_position.pool_key); - assert_eq!(last_position.liquidity, tested_position.liquidity); - assert_eq!( - last_position.lower_tick_index, - tested_position.lower_tick_index - ); - assert_eq!( - last_position.upper_tick_index, - tested_position.upper_tick_index - ); - assert_eq!( - last_position.fee_growth_inside_x, - tested_position.fee_growth_inside_x - ); - assert_eq!( - last_position.fee_growth_inside_y, - tested_position.fee_growth_inside_y - ); - assert_eq!(last_position.tokens_owed_x, tested_position.tokens_owed_x); - assert_eq!(last_position.tokens_owed_y, tested_position.tokens_owed_y); - } - // Add position in place of the removed one - { - let positions_list_before = get_all_positions!(client, ContractRef, dex, alice); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[1], - tick_indexes[2], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - let positions_list_after = get_all_positions!(client, ContractRef, dex, alice); - assert_eq!(positions_list_before.len() + 1, positions_list_after.len()); - } - // Remove last position - { - let last_position_index_before = - get_all_positions!(client, ContractRef, dex, alice).len() - 1; - - remove_position!( - client, - ContractRef, - dex, - last_position_index_before as u32, - alice - ); - - let last_position_index_after = - get_all_positions!(client, ContractRef, dex, alice).len() - 1; - - assert_eq!(last_position_index_before - 1, last_position_index_after) - } - // Remove all positions - { - let last_position_index = get_all_positions!(client, ContractRef, dex, alice).len(); - - for i in (0..last_position_index).rev() { - remove_position!(client, ContractRef, dex, i as u32, alice); - } - - let list_length = get_all_positions!(client, ContractRef, dex, alice).len(); - assert_eq!(list_length, 0); - } - // Add position to cleared list - { - let list_length_before = get_all_positions!(client, ContractRef, dex, alice).len(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - let list_length_after = get_all_positions!(client, ContractRef, dex, alice).len(); - assert_eq!(list_length_after, list_length_before + 1); - } - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn test_only_owner_can_modify_position_list(mut client: ink_e2e::Client) -> () { - let alice = ink_e2e::alice(); - let init_tick = -23028; - - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let initial_balance = 10u128.pow(10); - - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_balance, initial_balance); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 3).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let tick_indexes = [-9780, -42, 0, 9, 276, 32343, -50001]; - let liquidity_delta = Liquidity::from_integer(1_000_000); - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - // Open three positions - { - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[2], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[1], - tick_indexes[4], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - } - - // Remove middle position - { - let position_index_to_remove = 2; - let positions_list_before = get_all_positions!(client, ContractRef, dex, alice); - let last_position = positions_list_before[positions_list_before.len() - 1]; - - remove_position!(client, ContractRef, dex, position_index_to_remove, alice); - - let positions_list_after = get_all_positions!(client, ContractRef, dex, alice); - let tested_position = positions_list_after[position_index_to_remove as usize]; - - // Last position should be at removed index - assert_eq!(last_position.pool_key, tested_position.pool_key); - assert_eq!(last_position.liquidity, tested_position.liquidity); - assert_eq!( - last_position.lower_tick_index, - tested_position.lower_tick_index - ); - assert_eq!( - last_position.upper_tick_index, - tested_position.upper_tick_index - ); - assert_eq!( - last_position.fee_growth_inside_x, - tested_position.fee_growth_inside_x - ); - assert_eq!( - last_position.fee_growth_inside_y, - tested_position.fee_growth_inside_y - ); - assert_eq!(last_position.tokens_owed_x, tested_position.tokens_owed_x); - assert_eq!(last_position.tokens_owed_y, tested_position.tokens_owed_y); - } - // Add position in place of the removed one - { - let positions_list_before = get_all_positions!(client, ContractRef, dex, alice); - - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[1], - tick_indexes[2], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - let positions_list_after = get_all_positions!(client, ContractRef, dex, alice); - assert_eq!(positions_list_before.len() + 1, positions_list_after.len()); - } - // Remove last position - { - let last_position_index_before = - get_all_positions!(client, ContractRef, dex, alice).len() - 1; - - let unauthorized_user = ink_e2e::bob(); - remove_position!( - client, - ContractRef, - dex, - last_position_index_before as u32, - unauthorized_user - ) - .unwrap(); - } - } - - #[ink_e2e::test] - async fn test_transfer_position_ownership( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - let alice = ink_e2e::alice(); - let init_tick = -23028; - - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let initial_balance = 10u128.pow(10); - - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_balance, initial_balance); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 3).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let tick_indexes = [-9780, -42, 0, 9, 276, 32343, -50001]; - let liquidity_delta = Liquidity::from_integer(1_000_000); - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - { - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - let list_length = get_all_positions!(client, ContractRef, dex, alice).len(); - - assert_eq!(list_length, 1) - } - - let bob_address = address_of!(Bob); - let bob = ink_e2e::bob(); - // Open additional positions - { - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[1], - tick_indexes[2], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[1], - tick_indexes[3], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - } - // Transfer first position - { - let transferred_index = 0; - let owner_list_before = get_all_positions!(client, ContractRef, dex, alice); - let recipient_list_before = get_all_positions!(client, ContractRef, dex, bob); - let removed_position = - get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); - let last_position_before = owner_list_before[owner_list_before.len() - 1]; - - transfer_position!( - client, - ContractRef, - dex, - transferred_index, - bob_address, - alice - ); - - let recipient_position = - get_position!(client, ContractRef, dex, transferred_index, bob).unwrap(); - let owner_list_after = get_all_positions!(client, ContractRef, dex, alice); - let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); - let owner_first_position_after = - get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); - - assert_eq!(recipient_list_after.len(), recipient_list_before.len() + 1); - assert_eq!(owner_list_before.len() - 1, owner_list_after.len()); - - // move last position - positions_equals!(owner_first_position_after, last_position_before); - - // Equals fields od transferred position - positions_equals!(recipient_position, removed_position); - } - - // Transfer middle position - { - let transferred_index = 1; - let owner_list_before = get_all_positions!(client, ContractRef, dex, alice); - let recipient_list_before = get_all_positions!(client, ContractRef, dex, bob); - let removed_position = - get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); - let last_position_before = owner_list_before[owner_list_before.len() - 1]; - - transfer_position!( - client, - ContractRef, - dex, - transferred_index, - bob_address, - alice - ); - - let recipient_position = - get_position!(client, ContractRef, dex, transferred_index, bob).unwrap(); - let owner_list_after = get_all_positions!(client, ContractRef, dex, alice); - let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); - let owner_first_position_after = - get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); - - assert_eq!(recipient_list_after.len(), recipient_list_before.len() + 1); - assert_eq!(owner_list_before.len() - 1, owner_list_after.len()); - - // move last position - positions_equals!(owner_first_position_after, last_position_before); - } - // Transfer last position - { - let owner_list_before = get_all_positions!(client, ContractRef, dex, alice); - let transferred_index = (owner_list_before.len() - 1) as u32; - let recipient_list_before = get_all_positions!(client, ContractRef, dex, bob); - let removed_position = - get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); - - transfer_position!( - client, - ContractRef, - dex, - transferred_index, - bob_address, - alice - ); - - let owner_list_after = get_all_positions!(client, ContractRef, dex, alice); - let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); - let recipient_position_index = (recipient_list_after.len() - 1) as u32; - let recipient_position = - get_position!(client, ContractRef, dex, recipient_position_index, bob).unwrap(); - - positions_equals!(removed_position, recipient_position); - } - - // Clear position - { - let transferred_index = 0; - let owner_list_before = get_all_positions!(client, ContractRef, dex, alice); - let recipient_list_before = get_all_positions!(client, ContractRef, dex, bob); - let removed_position = - get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); - let last_position_before = owner_list_before[owner_list_before.len() - 1]; - - transfer_position!( - client, - ContractRef, - dex, - transferred_index, - bob_address, - alice - ); - - let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); - let recipient_position_index = (recipient_list_after.len() - 1) as u32; - let recipient_position = - get_position!(client, ContractRef, dex, recipient_position_index, bob).unwrap(); - let owner_list_after = get_all_positions!(client, ContractRef, dex, alice); - - assert_eq!(recipient_list_after.len(), recipient_list_before.len() + 1); - assert_eq!(0, owner_list_after.len()); - - // Equals fields od transferred position - positions_equals!(recipient_position, removed_position); - } - - // Get back position - { - let transferred_index = 0; - let owner_list_before = get_all_positions!(client, ContractRef, dex, alice); - let recipient_list_before = get_all_positions!(client, ContractRef, dex, bob); - let removed_position = - get_position!(client, ContractRef, dex, transferred_index, bob).unwrap(); - let last_position_before = recipient_list_before[recipient_list_before.len() - 1]; - - transfer_position!( - client, - ContractRef, - dex, - transferred_index, - address_of!(Alice), - bob - ); - - let owner_list_after = get_all_positions!(client, ContractRef, dex, alice); - let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); - let recipient_first_position_after = - get_position!(client, ContractRef, dex, transferred_index, bob).unwrap(); - - let owner_new_position = - get_position!(client, ContractRef, dex, transferred_index, alice).unwrap(); - - assert_eq!(recipient_list_after.len(), recipient_list_before.len() - 1); - assert_eq!(owner_list_before.len() + 1, owner_list_after.len()); - - // move last position - positions_equals!(last_position_before, recipient_first_position_after); - - // Equals fields od transferred position - positions_equals!(owner_new_position, removed_position); - } - - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn test_only_owner_can_transfer_position(mut client: ink_e2e::Client) -> () { - let alice = ink_e2e::alice(); - let init_tick = -23028; - - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let initial_balance = 10u128.pow(10); - - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_balance, initial_balance); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 3).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let tick_indexes = [-9780, -42, 0, 9, 276, 32343, -50001]; - let liquidity_delta = Liquidity::from_integer(1_000_000); - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - { - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - let list_length = get_all_positions!(client, ContractRef, dex, alice).len(); - - assert_eq!(list_length, 1) - } - - let bob_address = address_of!(Bob); - let bob = ink_e2e::bob(); - // Open additional positions - { - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[0], - tick_indexes[1], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[1], - tick_indexes[2], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - create_position!( - client, - ContractRef, - dex, - pool_key, - tick_indexes[1], - tick_indexes[3], - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - } - // Transfer first position - { - let transferred_index = 0; - - transfer_position!( - client, - ContractRef, - dex, - transferred_index, - address_of!(Alice), - bob - ) - .unwrap(); - } - } - - #[ink_e2e::test] - async fn test_swap_x_to_y(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::from_scale(6, 3)); - let initial_amount = 10u128.pow(10); - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_amount, initial_amount); - - let alice = ink_e2e::alice(); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - 0, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_amount, alice); - approve!(client, TokenRef, token_y, dex, initial_amount, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - let lower_tick_index = -20; - let middle_tick_index = -10; - let upper_tick_index = 10; - - let liquidity_delta = Liquidity::from_integer(1000000); - - let position = create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - SqrtPrice::new(0), - SqrtPrice::max_instance(), - alice - ); - - let position = create_position!( - client, - ContractRef, - dex, - pool_key, - middle_tick_index, - upper_tick_index - 20, - liquidity_delta, - SqrtPrice::new(0), - SqrtPrice::max_instance(), - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - assert_eq!(pool.liquidity, liquidity_delta); - - let amount = 1000; - let swap_amount = TokenAmount(amount); - let bob = ink_e2e::bob(); - mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); - approve!(client, TokenRef, token_x, dex, amount, bob); - - let slippage = SqrtPrice::new(MIN_SQRT_PRICE); - let target_sqrt_price = quote!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - slippage - ) - .unwrap() - .target_sqrt_price; - - let before_dex_x = balance_of!(client, TokenRef, token_x, dex); - let before_dex_y = balance_of!(client, TokenRef, token_y, dex); - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - target_sqrt_price, - bob - ); - - // Load states - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let lower_tick = - get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); - let middle_tick = - get_tick!(client, ContractRef, dex, pool_key, middle_tick_index).unwrap(); - let upper_tick = - get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); - let lower_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, lower_tick_index); - let middle_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, middle_tick_index); - let upper_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, upper_tick_index); - let bob_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - let bob_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); - let dex_x = balance_of!(client, TokenRef, token_x, dex); - let dex_y = balance_of!(client, TokenRef, token_y, dex); - let delta_dex_y = before_dex_y - dex_y; - let delta_dex_x = dex_x - before_dex_x; - let expected_y = amount - 10; - let expected_x = 0; - - // Check balances - assert_eq!(bob_x, expected_x); - assert_eq!(bob_y, expected_y); - assert_eq!(delta_dex_x, amount); - assert_eq!(delta_dex_y, expected_y); - - // Check Pool - assert_eq!(pool.fee_growth_global_y, FeeGrowth::new(0)); - assert_eq!( - pool.fee_growth_global_x, - FeeGrowth::new(40000000000000000000000) - ); - assert_eq!(pool.fee_protocol_token_y, TokenAmount(0)); - assert_eq!(pool.fee_protocol_token_x, TokenAmount(2)); - - // Check Ticks - assert_eq!(lower_tick.liquidity_change, liquidity_delta); - assert_eq!(middle_tick.liquidity_change, liquidity_delta); - assert_eq!(upper_tick.liquidity_change, liquidity_delta); - assert_eq!(upper_tick.fee_growth_outside_x, FeeGrowth::new(0)); - assert_eq!( - middle_tick.fee_growth_outside_x, - FeeGrowth::new(30000000000000000000000) - ); - assert_eq!(lower_tick.fee_growth_outside_x, FeeGrowth::new(0)); - assert!(lower_tick_bit); - assert!(middle_tick_bit); - assert!(upper_tick_bit); - - Ok(()) - } - - #[ink_e2e::test] - async fn test_swap_y_to_x(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::from_scale(6, 3)); - let initial_amount = 10u128.pow(10); - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_amount, initial_amount); - - let alice = ink_e2e::alice(); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - 0, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_amount, alice); - approve!(client, TokenRef, token_y, dex, initial_amount, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - let lower_tick_index = -10; - let middle_tick_index = 10; - let upper_tick_index = 20; - - let liquidity_delta = Liquidity::from_integer(1000000); - - let position = create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - SqrtPrice::new(0), - SqrtPrice::max_instance(), - alice - ); - - let position = create_position!( - client, - ContractRef, - dex, - pool_key, - middle_tick_index, - upper_tick_index + 20, - liquidity_delta, - SqrtPrice::new(0), - SqrtPrice::max_instance(), - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - assert_eq!(pool.liquidity, liquidity_delta); - - let amount = 1000; - let swap_amount = TokenAmount(amount); - let bob = ink_e2e::bob(); - mint!(client, TokenRef, token_y, address_of!(Bob), amount, alice); - approve!(client, TokenRef, token_y, dex, amount, bob); - - let target_sqrt_price = SqrtPrice::new(MAX_SQRT_PRICE); - - let target_sqrt_price = quote!( - client, - ContractRef, - dex, - pool_key, - false, - swap_amount, - true, - target_sqrt_price - ) - .unwrap() - .target_sqrt_price; - - let before_dex_x = balance_of!(client, TokenRef, token_x, dex); - let before_dex_y = balance_of!(client, TokenRef, token_y, dex); - - swap!( - client, - ContractRef, - dex, - pool_key, - false, - swap_amount, - true, - target_sqrt_price, - bob - ); - - // Load states - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let lower_tick = - get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); - let middle_tick = - get_tick!(client, ContractRef, dex, pool_key, middle_tick_index).unwrap(); - let upper_tick = - get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); - let lower_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, lower_tick_index); - let middle_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, middle_tick_index); - let upper_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, upper_tick_index); - let bob_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - let bob_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); - let dex_x = balance_of!(client, TokenRef, token_x, dex); - let dex_y = balance_of!(client, TokenRef, token_y, dex); - let delta_dex_x = before_dex_x - dex_x; - let delta_dex_y = dex_y - before_dex_y; - let expected_x = amount - 10; - let expected_y = 0; - - // Check balances - assert_eq!(bob_x, expected_x); - assert_eq!(bob_y, expected_y); - assert_eq!(delta_dex_x, expected_x); - assert_eq!(delta_dex_y, amount); - - // Check Pool - assert_eq!(pool.fee_growth_global_x, FeeGrowth::new(0)); - assert_eq!( - pool.fee_growth_global_y, - FeeGrowth::new(40000000000000000000000) - ); - assert_eq!(pool.fee_protocol_token_x, TokenAmount(0)); - assert_eq!(pool.fee_protocol_token_y, TokenAmount(2)); - - // Check Ticks - assert_eq!(lower_tick.liquidity_change, liquidity_delta); - assert_eq!(middle_tick.liquidity_change, liquidity_delta); - assert_eq!(upper_tick.liquidity_change, liquidity_delta); - assert_eq!(upper_tick.fee_growth_outside_y, FeeGrowth::new(0)); - assert_eq!( - middle_tick.fee_growth_outside_y, - FeeGrowth::new(30000000000000000000000) - ); - assert_eq!(lower_tick.fee_growth_outside_y, FeeGrowth::new(0)); - assert!(lower_tick_bit); - assert!(middle_tick_bit); - assert!(upper_tick_bit); - - Ok(()) - } - - #[ink_e2e::test] - async fn swap_route(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y, token_z) = - init_dex_and_3_tokens!(client, ContractRef, TokenRef); - - let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, u64::MAX as u128, alice); - approve!(client, TokenRef, token_y, dex, u64::MAX as u128, alice); - approve!(client, TokenRef, token_z, dex, u64::MAX as u128, alice); - - let amount = 1000; - let bob = ink_e2e::bob(); - mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); - approve!(client, TokenRef, token_x, dex, amount, bob); - approve!(client, TokenRef, token_y, dex, u64::MAX as u128, bob); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let init_tick = 0; - create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let init_tick = 0; - create_pool!( - client, - ContractRef, - dex, - token_y, - token_z, - fee_tier, - init_tick, - alice - ); - - let pool_key_1 = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let pool_key_2 = PoolKey::new(token_y, token_z, fee_tier).unwrap(); - - let liquidity_delta = Liquidity::new(2u128.pow(63) - 1); - - let pool_1 = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let slippage_limit_lower = pool_1.sqrt_price; - let slippage_limit_upper = pool_1.sqrt_price; - create_position!( - client, - ContractRef, - dex, - pool_key_1, - -1, - 1, - liquidity_delta, - slippage_limit_lower, - slippage_limit_upper, - alice - ); - - let pool_2 = get_pool!(client, ContractRef, dex, token_y, token_z, fee_tier).unwrap(); - let slippage_limit_lower = pool_2.sqrt_price; - let slippage_limit_upper = pool_2.sqrt_price; - create_position!( - client, - ContractRef, - dex, - pool_key_2, - -1, - 1, - liquidity_delta, - slippage_limit_lower, - slippage_limit_upper, - alice - ); - - let amount_in = TokenAmount(1000); - let expected_amount_out = TokenAmount(1000); - let slippage = Percentage::new(0); - let swaps = vec![ - Hop { - pool_key: pool_key_1, - x_to_y: true, - }, - Hop { - pool_key: pool_key_2, - x_to_y: true, - }, - ]; - - let expected_token_amount = - quote_route!(client, ContractRef, dex, amount_in, swaps.clone()).unwrap(); - - swap_route!( - client, - ContractRef, - dex, - amount_in, - expected_token_amount, - slippage, - swaps.clone(), - bob - ); - - let bob_amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - let bob_amount_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); - let bob_amount_z = balance_of!(client, TokenRef, token_z, address_of!(Bob)); - - assert_eq!(bob_amount_x, 0); - assert_eq!(bob_amount_y, 0); - assert_eq!(bob_amount_z, 986); - - let pool_1_after = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - assert_eq!(pool_1_after.fee_protocol_token_x, TokenAmount(1)); - assert_eq!(pool_1_after.fee_protocol_token_y, TokenAmount(0)); - - let pool_2_after = - get_pool!(client, ContractRef, dex, token_y, token_z, fee_tier).unwrap(); - assert_eq!(pool_2_after.fee_protocol_token_x, TokenAmount(1)); - assert_eq!(pool_2_after.fee_protocol_token_y, TokenAmount(0)); - - let alice_amount_x_before = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let alice_amount_y_before = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - let alice_amount_z_before = balance_of!(client, TokenRef, token_z, address_of!(Alice)); - - claim_fee!(client, ContractRef, dex, 0, alice); - claim_fee!(client, ContractRef, dex, 1, alice); - - let alice_amount_x_after = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let alice_amount_y_after = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - let alice_amount_z_after = balance_of!(client, TokenRef, token_z, address_of!(Alice)); - - assert_eq!(alice_amount_x_after - alice_amount_x_before, 4); - assert_eq!(alice_amount_y_after - alice_amount_y_before, 4); - assert_eq!(alice_amount_z_after - alice_amount_z_before, 0); - - Ok(()) - } - - #[ink_e2e::test] - async fn limits_full_range_with_max_liquidity(mut client: ink_e2e::Client) -> () { - let (dex, token_x, token_y) = - init_dex_and_tokens_max_mint_amount!(client, ContractRef, TokenRef); - - let mint_amount = u128::MAX; - let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, u128::MAX, alice); - approve!(client, TokenRef, token_y, dex, u128::MAX, alice); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let init_tick = get_max_tick(1); - create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let current_sqrt_price = pool.sqrt_price; - assert_eq!(pool.current_tick_index, init_tick); - assert_eq!(pool.sqrt_price, calculate_sqrt_price(init_tick).unwrap()); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let liquidity_delta = Liquidity::new(2u128.pow(109) - 1); - let slippage_limit_lower = pool.sqrt_price; - let slippage_limit_upper = pool.sqrt_price; - create_position!( - client, - ContractRef, - dex, - pool_key, - -MAX_TICK, - MAX_TICK, - liquidity_delta, - slippage_limit_lower, - slippage_limit_upper, - alice - ); - - let contract_amount_x = balance_of!(client, TokenRef, token_x, dex); - let contract_amount_y = balance_of!(client, TokenRef, token_y, dex); - - let expected_x = 0; - let expected_y = 42534896005851865508212194815854; // < 2^106 - assert_eq!(contract_amount_x, expected_x); - assert_eq!(contract_amount_y, expected_y); - } - - #[ink_e2e::test] - async fn deposit_limits_at_upper_limit(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y) = - init_dex_and_tokens_max_mint_amount!(client, ContractRef, TokenRef); - - let mint_amount = 2u128.pow(105) - 1; - let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, u128::MAX, alice); - approve!(client, TokenRef, token_y, dex, u128::MAX, alice); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let init_tick = get_max_tick(1); - create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let current_sqrt_price = pool.sqrt_price; - assert_eq!(pool.current_tick_index, init_tick); - assert_eq!(pool.sqrt_price, calculate_sqrt_price(init_tick).unwrap()); - - let position_amount = mint_amount - 1; - - let liquidity_delta = get_liquidity_by_y( - TokenAmount(position_amount), - 0, - MAX_TICK, - pool.sqrt_price, - false, - ) - .unwrap() - .l; - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let slippage_limit_lower = pool.sqrt_price; - let slippage_limit_upper = pool.sqrt_price; - create_position!( - client, - ContractRef, - dex, - pool_key, - 0, - MAX_TICK, - liquidity_delta, - slippage_limit_lower, - slippage_limit_upper, - alice - ); - - Ok(()) - } - - #[ink_e2e::test] - async fn limits_big_deposit_and_swaps(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y) = - init_dex_and_tokens_max_mint_amount!(client, ContractRef, TokenRef); - - let mint_amount = 2u128.pow(76) - 1; - let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, u128::MAX, alice); - approve!(client, TokenRef, token_y, dex, u128::MAX, alice); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let init_tick = 0; - create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let pos_amount = mint_amount / 2; - let lower_tick = -(fee_tier.tick_spacing as i32); - let upper_tick = fee_tier.tick_spacing as i32; - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - let liquidity_delta = get_liquidity_by_x( - TokenAmount(pos_amount), - lower_tick, - upper_tick, - pool.sqrt_price, - false, - ) - .unwrap() - .l; - - let y = get_delta_y( - calculate_sqrt_price(lower_tick).unwrap(), - pool.sqrt_price, - liquidity_delta, - true, - ) - .unwrap(); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let slippage_limit_lower = pool.sqrt_price; - let slippage_limit_upper = pool.sqrt_price; - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick, - upper_tick, - liquidity_delta, - slippage_limit_lower, - slippage_limit_upper, - alice - ); - - let user_amount_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let user_amount_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - assert_eq!(user_amount_x, u128::MAX - pos_amount); - assert_eq!(user_amount_y, u128::MAX - y.get()); - - let contract_amount_x = balance_of!(client, TokenRef, token_x, dex); - let contract_amount_y = balance_of!(client, TokenRef, token_y, dex); - assert_eq!(contract_amount_x, pos_amount); - assert_eq!(contract_amount_y, y.get()); - - let swap_amount = TokenAmount(mint_amount / 8); - - for i in 1..=4 { - let (x_to_y, sqrt_price_limit) = if i % 2 == 0 { - (true, SqrtPrice::new(MIN_SQRT_PRICE)) - } else { - (false, SqrtPrice::new(MAX_SQRT_PRICE)) - }; - - swap!( - client, - ContractRef, - dex, - pool_key, - i % 2 == 0, - swap_amount, - true, - sqrt_price_limit, - alice - ); - } - - Ok(()) - } - - #[ink_e2e::test] - async fn multiple_swap_x_to_y(mut client: ink_e2e::Client) -> E2EResult<()> { - multiple_swap!(client, ContractRef, TokenRef, true); - Ok(()) - } - - #[ink_e2e::test] - async fn limits_big_deposit_x_and_swap_y( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - big_deposit_and_swap!(client, ContractRef, TokenRef, true); - - Ok(()) - } - - #[ink_e2e::test] - async fn multiple_swap_y_to_x(mut client: ink_e2e::Client) -> E2EResult<()> { - multiple_swap!(client, ContractRef, TokenRef, false); - Ok(()) - } - - #[ink_e2e::test] - async fn limits_big_deposit_y_and_swap_x( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - big_deposit_and_swap!(client, ContractRef, TokenRef, false); - - Ok(()) - } - - #[ink_e2e::test] - async fn limits_big_deposit_both_tokens( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - let (dex, token_x, token_y) = - init_dex_and_tokens_max_mint_amount!(client, ContractRef, TokenRef); - - let mint_amount = 2u128.pow(75) - 1; - let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, u128::MAX, alice); - approve!(client, TokenRef, token_y, dex, u128::MAX, alice); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let init_tick = 0; - create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let lower_tick = -(fee_tier.tick_spacing as i32); - let upper_tick = fee_tier.tick_spacing as i32; - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let liquidity_delta = get_liquidity_by_x( - TokenAmount(mint_amount), - lower_tick, - upper_tick, - pool.sqrt_price, - false, - ) - .unwrap() - .l; - let y = get_delta_y( - calculate_sqrt_price(lower_tick).unwrap(), - pool.sqrt_price, - liquidity_delta, - true, - ) - .unwrap(); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let slippage_limit_lower = pool.sqrt_price; - let slippage_limit_upper = pool.sqrt_price; - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick, - upper_tick, - liquidity_delta, - slippage_limit_lower, - slippage_limit_upper, - alice - ); - - let user_amount_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let user_amount_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - assert_eq!(user_amount_x, u128::MAX - mint_amount); - assert_eq!(user_amount_y, u128::MAX - y.get()); - - let contract_amount_x = balance_of!(client, TokenRef, token_x, dex); - let contract_amount_y = balance_of!(client, TokenRef, token_y, dex); - assert_eq!(contract_amount_x, mint_amount); - assert_eq!(contract_amount_y, y.get()); - - Ok(()) - } - - #[ink_e2e::test] - async fn max_tick_cross(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); - init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); - - let mint_amount = u128::MAX; - let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); - - let liquidity = Liquidity::from_integer(10000000); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - for i in (-2560..20).step_by(10) { - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - let slippage_limit_lower = pool.sqrt_price; - let slippage_limit_upper = pool.sqrt_price; - - create_position!( - client, - ContractRef, - dex, - pool_key, - i, - i + 10, - liquidity, - slippage_limit_lower, - slippage_limit_upper, - alice - ); - } - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - assert_eq!(pool.liquidity, liquidity); - - let amount = 760_000; - let bob = ink_e2e::bob(); - mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); - let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - assert_eq!(amount_x, amount); - approve!(client, TokenRef, token_x, dex, amount, bob); - - let pool_before = get_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - pool_key.fee_tier - ) - .unwrap(); - - let swap_amount = TokenAmount::new(amount); - let slippage = SqrtPrice::new(MIN_SQRT_PRICE); - let quote_result = quote!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - slippage - ) - .unwrap(); - - let pool_after_quote = get_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - pool_key.fee_tier - ) - .unwrap(); - - let crosses_after_quote = - ((pool_after_quote.current_tick_index - pool_before.current_tick_index) / 10).abs(); - assert_eq!(crosses_after_quote, 0); - assert_eq!(quote_result.ticks.len() - 1, 145); - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - slippage, - bob - ); - - let pool_after = get_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - pool_key.fee_tier - ) - .unwrap(); - - let crosses = - ((pool_after.current_tick_index - pool_before.current_tick_index) / 10).abs(); - assert_eq!(crosses, 146); - assert_eq!( - pool_after.current_tick_index, - get_tick_at_sqrt_price(quote_result.target_sqrt_price, 10).unwrap() - ); - - Ok(()) - } - - #[ink_e2e::test] - async fn swap_exact_limit(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); - init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - let amount = 1000; - let bob = ink_e2e::bob(); - let alice = ink_e2e::alice(); - mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); - let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - assert_eq!(amount_x, amount); - approve!(client, TokenRef, token_x, dex, amount, bob); - - let swap_amount = TokenAmount::new(amount); - swap_exact_limit!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - bob - ); - - Ok(()) - } - - #[ink_e2e::test] - async fn claim(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); - init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_swap!(client, ContractRef, TokenRef, dex, token_x, token_y); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let alice = ink_e2e::alice(); - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let user_amount_before_claim = - balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let dex_amount_before_claim = balance_of!(client, TokenRef, token_x, dex); - - claim_fee!(client, ContractRef, dex, 0, alice); - - let user_amount_after_claim = - balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let dex_amount_after_claim = balance_of!(client, TokenRef, token_x, dex); - let position = get_position!(client, ContractRef, dex, 0, alice).unwrap(); - let expected_tokens_claimed = 5; - - assert_eq!( - user_amount_after_claim - expected_tokens_claimed, - user_amount_before_claim - ); - assert_eq!( - dex_amount_after_claim + expected_tokens_claimed, - dex_amount_before_claim - ); - assert_eq!(position.fee_growth_inside_x, pool.fee_growth_global_x); - assert_eq!(position.tokens_owed_x, TokenAmount(0)); - - Ok(()) - } - - #[ink_e2e::test] - async fn basic_slippage_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let alice = ink_e2e::alice(); - let (dex, token_x, token_y) = - init_slippage_dex_and_tokens!(client, ContractRef, TokenRef); - let pool_key = init_slippage_pool_with_liquidity!( - client, - ContractRef, - TokenRef, - dex, - token_x, - token_y - ); - let amount = 10u128.pow(8); - let swap_amount = TokenAmount::new(amount); - approve!(client, TokenRef, token_x, dex, amount, alice); - - let target_sqrt_price = SqrtPrice::new(1009940000000000000000001); - swap!( - client, - ContractRef, - dex, - pool_key, - false, - swap_amount, - true, - target_sqrt_price, - alice - ); - let expected_sqrt_price = SqrtPrice::new(1009940000000000000000000); - let pool = get_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - pool_key.fee_tier - ) - .unwrap(); - - assert_eq!(expected_sqrt_price, pool.sqrt_price); - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn swap_close_to_limit_test(mut client: ink_e2e::Client) -> () { - let alice = ink_e2e::alice(); - let (dex, token_x, token_y) = - init_slippage_dex_and_tokens!(client, ContractRef, TokenRef); - let pool_key = init_slippage_pool_with_liquidity!( - client, - ContractRef, - TokenRef, - dex, - token_x, - token_y - ); - let amount = 10u128.pow(8); - let swap_amount = TokenAmount::new(amount); - approve!(client, TokenRef, token_x, dex, amount, alice); - - let target_sqrt_price = calculate_sqrt_price(-98).unwrap(); - swap!( - client, - ContractRef, - dex, - pool_key, - false, - swap_amount, - true, - target_sqrt_price, - alice - ) - .unwrap(); - } - - #[ink_e2e::test] - async fn cross(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); - init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_cross_position!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_cross_swap!(client, ContractRef, TokenRef, dex, token_x, token_y); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let alice = ink_e2e::alice(); - - let upper_tick_index = 10; - let middle_tick_index = -10; - let lower_tick_index = -20; - - let upper_tick = - get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); - let middle_tick = - get_tick!(client, ContractRef, dex, pool_key, middle_tick_index).unwrap(); - let lower_tick = - get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); - - assert_eq!( - upper_tick.liquidity_change, - Liquidity::from_integer(1000000) - ); - assert_eq!( - middle_tick.liquidity_change, - Liquidity::from_integer(1000000) - ); - assert_eq!( - lower_tick.liquidity_change, - Liquidity::from_integer(1000000) - ); - - assert_eq!(upper_tick.fee_growth_outside_x, FeeGrowth::new(0)); - assert_eq!( - middle_tick.fee_growth_outside_x, - FeeGrowth::new(30000000000000000000000) - ); - assert_eq!(lower_tick.fee_growth_outside_x, FeeGrowth::new(0)); - - Ok(()) - } - - #[ink_e2e::test] - async fn swap(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); - init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_swap!(client, ContractRef, TokenRef, dex, token_x, token_y); - Ok(()) - } - - #[ink_e2e::test] - async fn protocol_fee(mut client: ink_e2e::Client) -> E2EResult<()> { - let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); - init_basic_pool!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_swap!(client, ContractRef, TokenRef, dex, token_x, token_y); - - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let alice = ink_e2e::alice(); - withdraw_protocol_fee!(client, ContractRef, dex, pool_key, alice); - - let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let amount_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - assert_eq!(amount_x, 9999999501); - assert_eq!(amount_y, 9999999000); - - let amount_x = balance_of!(client, TokenRef, token_x, dex); - let amount_y = balance_of!(client, TokenRef, token_y, dex); - assert_eq!(amount_x, 1499); - assert_eq!(amount_y, 7); - - let pool_after_withdraw = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - assert_eq!( - pool_after_withdraw.fee_protocol_token_x, - TokenAmount::new(0) - ); - assert_eq!( - pool_after_withdraw.fee_protocol_token_y, - TokenAmount::new(0) - ); - - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn protocol_fee_should_panic(mut client: ink_e2e::Client) -> () { - let (dex, token_x, token_y) = init_dex_and_tokens!(client, ContractRef, TokenRef); - init_basic_position!(client, ContractRef, TokenRef, dex, token_x, token_y); - init_basic_swap!(client, ContractRef, TokenRef, dex, token_x, token_y); - - let pool_key = PoolKey::new( - token_x, - token_y, - FeeTier { - fee: Percentage::from_scale(6, 3), - tick_spacing: 10, - }, - ) - .unwrap(); - let bob = ink_e2e::bob(); - withdraw_protocol_fee!(client, ContractRef, dex, pool_key, bob); - } - - #[ink_e2e::test] - async fn constructor_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let constructor = TokenRef::new(500, None, None, 0); - let _token: AccountId = client - .instantiate("token", &ink_e2e::alice(), constructor, 0, None) - .await - .expect("Instantiate failed") - .account_id; - - let constructor = ContractRef::new(Percentage::new(0)); - - let _contract: AccountId = client - .instantiate("contract", &ink_e2e::alice(), constructor, 0, None) - .await - .expect("Instantiate failed") - .account_id; - Ok(()) - } - - #[ink_e2e::test] - async fn change_protocol_fee(mut client: ink_e2e::Client) -> E2EResult<()> { - let contract = create_dex!(client, ContractRef, Percentage::new(0)); - - let protocol_fee = { - let _msg = build_message::(contract.clone()) - .call(|contract| contract.get_protocol_fee()); - client - .call(&ink_e2e::alice(), _msg, 0, None) - .await - .expect("getting protocol fee failed") - } - .return_value(); - - assert_eq!(protocol_fee, Percentage::new(0)); - - let _result = { - let _msg = build_message::(contract.clone()) - .call(|contract| contract.change_protocol_fee(Percentage::new(1))); - client - .call(&ink_e2e::alice(), _msg, 0, None) - .await - .expect("changing protocol fee failed") - }; - - let protocol_fee = { - let _msg = build_message::(contract.clone()) - .call(|contract| contract.get_protocol_fee()); - client - .call(&ink_e2e::alice(), _msg, 0, None) - .await - .expect("getting protocol fee failed") - } - .return_value(); - - assert_eq!(protocol_fee, Percentage::new(1)); - - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn change_protocol_fee_should_panic(mut client: ink_e2e::Client) -> () { - let contract = create_dex!(client, ContractRef, Percentage::new(0)); - - let result = { - let _msg = build_message::(contract.clone()) - .call(|contract| contract.change_protocol_fee(Percentage::new(1))); - client - .call(&ink_e2e::bob(), _msg, 0, None) - .await - .expect("changing protocol fee failed") - }; - } - - #[ink_e2e::test] - async fn create_position(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let (token_x, token_y) = create_tokens!(client, TokenRef, 500, 500); - - let alice = ink_e2e::alice(); - - let fee_tier = FeeTier::new(Percentage::new(0), 1).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - 10, - alice - ); - - approve!(client, TokenRef, token_x, dex, 500, alice); - approve!(client, TokenRef, token_y, dex, 500, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - let position = create_position!( - client, - ContractRef, - dex, - pool_key, - -10, - 10, - Liquidity::new(10), - SqrtPrice::new(0), - SqrtPrice::max_instance(), - alice - ); - - Ok(()) - } - - #[ink_e2e::test] - async fn add_fee_tier_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let fee_tier = FeeTier::new(Percentage::new(0), 10u16).unwrap(); - let alice = ink_e2e::alice(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - let fee_tier = fee_tier_exist!( - client, - ContractRef, - dex, - FeeTier::new(Percentage::new(0), 10).unwrap() - ); - assert!(fee_tier); - Ok(()) - } - - #[ink_e2e::test] - async fn create_standard_fee_tier_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - create_standard_fee_tiers!(client, ContractRef, dex); - let alice = ink_e2e::alice(); - let fee_tier = fee_tier_exist!( - client, - ContractRef, - dex, - FeeTier::new(Percentage::from_scale(5, 2), 100).unwrap() - ); - assert!(fee_tier); - Ok(()) - } - - #[ink_e2e::test] - async fn create_pool_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let (token_x, token_y) = create_tokens!(client, TokenRef, 500, 500); - - let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 100).unwrap(); - let init_tick = 0; - - let alice = ink_e2e::alice(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let result = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - assert!(result.is_ok()); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - Ok(()) - } - - #[ink_e2e::test] - async fn fee_tier_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let admin = ink_e2e::alice(); - let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 100).unwrap(); - let result = add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - assert!(result.is_ok()); - Ok(()) - } - #[ink_e2e::test] - #[should_panic] - async fn invalid_spacing_fee_tier_test(mut client: ink_e2e::Client) -> () { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let admin = ink_e2e::alice(); - // 0 tick spacing | should fail - let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 0).unwrap(); - let result = add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - } - - #[ink_e2e::test] - #[should_panic] - async fn non_admin_fee_tier_caller_test(mut client: ink_e2e::Client) -> () { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let user = ink_e2e::bob(); - // not-admin - let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 10).unwrap(); - let result = add_fee_tier!(client, ContractRef, dex, fee_tier, user).unwrap(); - } - - #[ink_e2e::test] - async fn position_above_current_tick_test( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - let alice = ink_e2e::alice(); - let init_tick = -23028; - - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let initial_balance = 10_000_000_000; - - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_balance, initial_balance); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 4).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let lower_tick_index = -22980; - let upper_tick_index = 0; - let liquidity_delta = Liquidity::new(initial_balance); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - // Load states - let position_state = get_position!(client, ContractRef, dex, 0, alice).unwrap(); - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let lower_tick = - get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); - let upper_tick = - get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); - let lower_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, lower_tick_index); - let upper_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, upper_tick_index); - let alice_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let alice_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - let dex_x = balance_of!(client, TokenRef, token_x, dex); - let dex_y = balance_of!(client, TokenRef, token_y, dex); - - let zero_fee = FeeGrowth::new(0); - let expected_x_increase = 21549; - let expected_y_increase = 0; - - // Check ticks - assert!(lower_tick.index == lower_tick_index); - assert!(upper_tick.index == upper_tick_index); - assert_eq!(lower_tick.liquidity_gross, liquidity_delta); - assert_eq!(upper_tick.liquidity_gross, liquidity_delta); - assert_eq!(lower_tick.liquidity_change, liquidity_delta); - assert_eq!(upper_tick.liquidity_change, liquidity_delta); - assert!(lower_tick.sign); - assert!(!upper_tick.sign); - - // Check pool - assert!(pool_state.liquidity == Liquidity::new(0)); - assert!(pool_state.current_tick_index == init_tick); - - // Check position - assert!(position_state.pool_key == pool_key); - assert!(position_state.liquidity == liquidity_delta); - assert!(position_state.lower_tick_index == lower_tick_index); - assert!(position_state.upper_tick_index == upper_tick_index); - assert!(position_state.fee_growth_inside_x == zero_fee); - assert!(position_state.fee_growth_inside_y == zero_fee); - - // Check balances - assert_eq!(alice_x, initial_balance.checked_sub(dex_x).unwrap()); - assert_eq!(alice_y, initial_balance.checked_sub(dex_y).unwrap()); - - assert_eq!(dex_x, expected_x_increase); - assert_eq!(dex_y, expected_y_increase); - - Ok(()) - } - - #[ink_e2e::test] - async fn multiple_positions_on_same_tick( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - let alice = ink_e2e::alice(); - let init_tick = 0; - - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let initial_balance = 100_000_000; - - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_balance, initial_balance); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 10).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - // Three position on same lower and upper tick - { - let lower_tick_index = -10; - let upper_tick_index = 10; - - let liquidity_delta = Liquidity::new(100); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - let first_position = get_position!(client, ContractRef, dex, 0, alice).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - let second_position = get_position!(client, ContractRef, dex, 1, alice).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - let third_position = get_position!(client, ContractRef, dex, 2, alice).unwrap(); - - assert!(first_position.lower_tick_index == second_position.lower_tick_index); - assert!(first_position.upper_tick_index == second_position.upper_tick_index); - assert!(first_position.lower_tick_index == third_position.lower_tick_index); - assert!(first_position.upper_tick_index == third_position.upper_tick_index); - - // Load states - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let lower_tick = - get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); - let upper_tick = - get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); - let lower_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, lower_tick_index); - let upper_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, upper_tick_index); - let expected_liquidity = Liquidity::new(liquidity_delta.get() * 3); - let zero_fee = FeeGrowth::new(0); - - // Check ticks - assert!(lower_tick.index == lower_tick_index); - assert!(upper_tick.index == upper_tick_index); - assert_eq!(lower_tick.liquidity_gross, expected_liquidity); - assert_eq!(upper_tick.liquidity_gross, expected_liquidity); - assert_eq!(lower_tick.liquidity_change, expected_liquidity); - assert_eq!(upper_tick.liquidity_change, expected_liquidity); - assert!(lower_tick.sign); - assert!(!upper_tick.sign); - - // Check pool - assert_eq!(pool_state.liquidity, expected_liquidity); - assert!(pool_state.current_tick_index == init_tick); - - // Check first position - assert!(first_position.pool_key == pool_key); - assert!(first_position.liquidity == liquidity_delta); - assert!(first_position.lower_tick_index == lower_tick_index); - assert!(first_position.upper_tick_index == upper_tick_index); - assert!(first_position.fee_growth_inside_x == zero_fee); - assert!(first_position.fee_growth_inside_y == zero_fee); - - // Check second position - assert!(second_position.pool_key == pool_key); - assert!(second_position.liquidity == liquidity_delta); - assert!(second_position.lower_tick_index == lower_tick_index); - assert!(second_position.upper_tick_index == upper_tick_index); - assert!(second_position.fee_growth_inside_x == zero_fee); - assert!(second_position.fee_growth_inside_y == zero_fee); - - // Check third position - assert!(third_position.pool_key == pool_key); - assert!(third_position.liquidity == liquidity_delta); - assert!(third_position.lower_tick_index == lower_tick_index); - assert!(third_position.upper_tick_index == upper_tick_index); - assert!(third_position.fee_growth_inside_x == zero_fee); - assert!(third_position.fee_growth_inside_y == zero_fee); - } - { - let lower_tick_index = -10; - let upper_tick_index = 10; - let zero_fee = FeeGrowth::new(0); - - let liquidity_delta = Liquidity::new(100); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - let first_position = get_position!(client, ContractRef, dex, 3, alice).unwrap(); - - // Check first position - assert!(first_position.pool_key == pool_key); - assert!(first_position.liquidity == liquidity_delta); - assert!(first_position.lower_tick_index == lower_tick_index); - assert!(first_position.upper_tick_index == upper_tick_index); - assert!(first_position.fee_growth_inside_x == zero_fee); - assert!(first_position.fee_growth_inside_y == zero_fee); - - let lower_tick_index = -20; - let upper_tick_index = -10; - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - let second_position = get_position!(client, ContractRef, dex, 4, alice).unwrap(); - - // Check second position - assert!(second_position.pool_key == pool_key); - assert!(second_position.liquidity == liquidity_delta); - assert!(second_position.lower_tick_index == lower_tick_index); - assert!(second_position.upper_tick_index == upper_tick_index); - assert!(second_position.fee_growth_inside_x == zero_fee); - assert!(second_position.fee_growth_inside_y == zero_fee); - - let lower_tick_index = 10; - let upper_tick_index = 20; - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - let third_position = get_position!(client, ContractRef, dex, 5, alice).unwrap(); - - // Check third position - assert!(third_position.pool_key == pool_key); - assert!(third_position.liquidity == liquidity_delta); - assert!(third_position.lower_tick_index == lower_tick_index); - assert!(third_position.upper_tick_index == upper_tick_index); - assert!(third_position.fee_growth_inside_x == zero_fee); - assert!(third_position.fee_growth_inside_y == zero_fee); - - // Load states - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let tick_n20 = get_tick!(client, ContractRef, dex, pool_key, -20).unwrap(); - let tick_n10 = get_tick!(client, ContractRef, dex, pool_key, -10).unwrap(); - let tick_10 = get_tick!(client, ContractRef, dex, pool_key, 10).unwrap(); - let tick_20 = get_tick!(client, ContractRef, dex, pool_key, 20).unwrap(); - let tick_n20_bit = is_tick_initialized!(client, ContractRef, dex, pool_key, -20); - let tick_n10_bit = is_tick_initialized!(client, ContractRef, dex, pool_key, -10); - let tick_10_bit = is_tick_initialized!(client, ContractRef, dex, pool_key, 10); - let tick_20_bit = is_tick_initialized!(client, ContractRef, dex, pool_key, 20); - - let expected_active_liquidity = Liquidity::new(400); - - // Check tick -20 - assert_eq!(tick_n20.index, -20); - assert_eq!(tick_n20.liquidity_gross, Liquidity::new(100)); - assert_eq!(tick_n20.liquidity_change, Liquidity::new(100)); - assert!(tick_n20.sign); - assert!(tick_n20_bit); - - // Check tick -10 - assert_eq!(tick_n10.index, -10); - assert_eq!(tick_n10.liquidity_gross, Liquidity::new(500)); - assert_eq!(tick_n10.liquidity_change, Liquidity::new(300)); - assert!(tick_n10.sign); - assert!(tick_n10_bit); - - // Check tick 10 - assert_eq!(tick_10.index, 10); - assert_eq!(tick_10.liquidity_gross, Liquidity::new(500)); - assert_eq!(tick_10.liquidity_change, Liquidity::new(300)); - assert!(!tick_10.sign); - assert!(tick_20_bit); - - // Check tick 20 - assert_eq!(tick_20.index, 20); - assert_eq!(tick_20.liquidity_gross, Liquidity::new(100)); - assert_eq!(tick_20.liquidity_change, Liquidity::new(100)); - assert!(!tick_20.sign); - assert!(tick_20_bit); - - // Check pool - assert_eq!(pool_state.liquidity, expected_active_liquidity); - assert!(pool_state.current_tick_index == init_tick); - } - Ok(()) - } - - #[ink_e2e::test] - async fn position_within_current_tick_test( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - let MAX_TICK_TEST = 177_450; // for tickSpacing 4 - let MIN_TICK_TEST = -MAX_TICK_TEST; - let alice = ink_e2e::alice(); - let init_tick = -23028; - - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let initial_balance = 100_000_000; - - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_balance, initial_balance); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 4).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let lower_tick_index = MIN_TICK_TEST + 10; - let upper_tick_index = MAX_TICK_TEST - 10; - - let liquidity_delta = Liquidity::new(initial_balance); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - // Load states - let position_state = get_position!(client, ContractRef, dex, 0, alice).unwrap(); - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let lower_tick = - get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); - let upper_tick = - get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); - let lower_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, lower_tick_index); - let upper_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, upper_tick_index); - let alice_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let alice_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - let dex_x = balance_of!(client, TokenRef, token_x, dex); - let dex_y = balance_of!(client, TokenRef, token_y, dex); - - let zero_fee = FeeGrowth::new(0); - let expected_x_increase = 317; - let expected_y_increase = 32; - - // Check ticks - assert!(lower_tick.index == lower_tick_index); - assert!(upper_tick.index == upper_tick_index); - assert_eq!(lower_tick.liquidity_gross, liquidity_delta); - assert_eq!(upper_tick.liquidity_gross, liquidity_delta); - assert_eq!(lower_tick.liquidity_change, liquidity_delta); - assert_eq!(upper_tick.liquidity_change, liquidity_delta); - assert!(lower_tick.sign); - assert!(!upper_tick.sign); - - // Check pool - assert!(pool_state.liquidity == liquidity_delta); - assert!(pool_state.current_tick_index == init_tick); - - // Check position - assert!(position_state.pool_key == pool_key); - assert!(position_state.liquidity == liquidity_delta); - assert!(position_state.lower_tick_index == lower_tick_index); - assert!(position_state.upper_tick_index == upper_tick_index); - assert!(position_state.fee_growth_inside_x == zero_fee); - assert!(position_state.fee_growth_inside_y == zero_fee); - - // Check balances - assert_eq!(alice_x, initial_balance.checked_sub(dex_x).unwrap()); - assert_eq!(alice_y, initial_balance.checked_sub(dex_y).unwrap()); - assert_eq!(dex_x, expected_x_increase); - assert_eq!(dex_y, expected_y_increase); - - Ok(()) - } - - #[ink_e2e::test] - async fn position_below_current_tick_test( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - let alice = ink_e2e::alice(); - let init_tick = -23028; - - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let initial_balance = 100_000_000_00; - - let (token_x, token_y) = - create_tokens!(client, TokenRef, initial_balance, initial_balance); - - let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 4).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - let lower_tick_index = -46080; - let upper_tick_index = -23040; - - let liquidity_delta = Liquidity::new(initial_balance); - - let pool_state_before = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state_before.sqrt_price, - SqrtPrice::max_instance(), - alice - ); - - // Load states - let position_state = get_position!(client, ContractRef, dex, 0, alice).unwrap(); - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let lower_tick = - get_tick!(client, ContractRef, dex, pool_key, lower_tick_index).unwrap(); - let upper_tick = - get_tick!(client, ContractRef, dex, pool_key, upper_tick_index).unwrap(); - let lower_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, lower_tick_index); - let upper_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, upper_tick_index); - let alice_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let alice_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - let dex_x = balance_of!(client, TokenRef, token_x, dex); - let dex_y = balance_of!(client, TokenRef, token_y, dex); - - let zero_fee = FeeGrowth::new(0); - let expected_x_increase = 0; - let expected_y_increase = 2162; - - // Check ticks - assert!(lower_tick.index == lower_tick_index); - assert!(upper_tick.index == upper_tick_index); - assert_eq!(lower_tick.liquidity_gross, liquidity_delta); - assert_eq!(upper_tick.liquidity_gross, liquidity_delta); - assert_eq!(lower_tick.liquidity_change, liquidity_delta); - assert_eq!(upper_tick.liquidity_change, liquidity_delta); - assert!(lower_tick.sign); - assert!(!upper_tick.sign); - - // Check pool - assert!(pool_state.liquidity == pool_state_before.liquidity); - assert!(pool_state.current_tick_index == init_tick); - - // Check position - assert!(position_state.pool_key == pool_key); - assert!(position_state.liquidity == liquidity_delta); - assert!(position_state.lower_tick_index == lower_tick_index); - assert!(position_state.upper_tick_index == upper_tick_index); - assert!(position_state.fee_growth_inside_x == zero_fee); - assert!(position_state.fee_growth_inside_y == zero_fee); - - // Check balances - assert_eq!(alice_x, initial_balance.checked_sub(dex_x).unwrap()); - assert_eq!(alice_y, initial_balance.checked_sub(dex_y).unwrap()); - - assert_eq!(dex_x, expected_x_increase); - assert_eq!(dex_y, expected_y_increase); - - Ok(()) - } - - #[ink_e2e::test] - async fn change_fee_reciever_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let (token_x, token_y) = create_tokens!(client, TokenRef, 500, 500); - - let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 1).unwrap(); - let init_tick = 0; - - let alice = ink_e2e::alice(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let result = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - assert!(result.is_ok()); - - let admin = ink_e2e::alice(); - let alice = address_of!(Alice); - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - change_fee_receiver!(client, ContractRef, dex, pool_key, alice, admin); - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - assert_eq!(pool.fee_receiver, alice); - - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn not_admin_change_fee_reciever_test(mut client: ink_e2e::Client) -> () { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let (token_x, token_y) = create_tokens!(client, TokenRef, 500, 500); - - let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 100).unwrap(); - let init_tick = 0; - - let admin = ink_e2e::alice(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - - let result = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - admin - ); - assert!(result.is_ok()); - - let user = ink_e2e::bob(); - let bob = address_of!(Bob); - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - change_fee_receiver!(client, ContractRef, dex, pool_key, bob, user).unwrap(); - } - - #[ink_e2e::test] - async fn remove_position_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - let alice = ink_e2e::alice(); - let bob = ink_e2e::bob(); - let init_tick = 0; - let remove_position_index = 0; - - let initial_mint = 10u128.pow(10); - - let dex = create_dex!(client, ContractRef, Percentage::from_scale(1, 2)); - let (token_x, token_y) = create_tokens!(client, TokenRef, initial_mint, initial_mint); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let lower_tick_index = -20; - let upper_tick_index = 10; - let liquidity_delta = Liquidity::from_integer(1_000_000); - - approve!(client, TokenRef, token_x, dex, initial_mint, alice); - approve!(client, TokenRef, token_y, dex, initial_mint, alice); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - assert_eq!(pool_state.liquidity, liquidity_delta); - - let liquidity_delta = Liquidity::new(liquidity_delta.get() * 1_000_000); - { - let incorrect_lower_tick_index = lower_tick_index - 50; - let incorrect_upper_tick_index = upper_tick_index + 50; - - approve!(client, TokenRef, token_x, dex, liquidity_delta.get(), alice); - approve!(client, TokenRef, token_y, dex, liquidity_delta.get(), alice); - - create_position!( - client, - ContractRef, - dex, - pool_key, - incorrect_lower_tick_index, - incorrect_upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - let position_state = get_position!(client, ContractRef, dex, 1, alice).unwrap(); - // Check position - assert!(position_state.lower_tick_index == incorrect_lower_tick_index); - assert!(position_state.upper_tick_index == incorrect_upper_tick_index); - } - - let amount = 1000; - mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); - let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - assert_eq!(amount_x, amount); - - approve!(client, TokenRef, token_x, dex, amount, bob); - - let pool_state_before = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - let swap_amount = TokenAmount::new(amount); - let slippage = SqrtPrice::new(MIN_SQRT_PRICE); - swap!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - slippage, - bob - ); - - let pool_state_after = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - assert_eq!( - pool_state_after.fee_growth_global_x, - FeeGrowth::new(49999950000049999) - ); - assert_eq!(pool_state_after.fee_protocol_token_x, TokenAmount(1)); - assert_eq!(pool_state_after.fee_protocol_token_y, TokenAmount(0)); - - assert!(pool_state_after - .sqrt_price - .lt(&pool_state_before.sqrt_price)); - - assert_eq!(pool_state_after.liquidity, pool_state_before.liquidity); - assert_eq!(pool_state_after.current_tick_index, -10); - assert_ne!(pool_state_after.sqrt_price, pool_state_before.sqrt_price); - - let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - let amount_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); - assert_eq!(amount_x, 0); - assert_eq!(amount_y, 993); - - // pre load dex balances - let dex_x_before_remove = balance_of!(client, TokenRef, token_x, dex); - let dex_y_before_remove = balance_of!(client, TokenRef, token_y, dex); - - // Remove position - let remove_result = - remove_position!(client, ContractRef, dex, remove_position_index, alice); - - // Load states - let position_state = - get_position!(client, ContractRef, dex, remove_position_index, alice); - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let lower_tick = get_tick!(client, ContractRef, dex, pool_key, lower_tick_index); - let upper_tick = get_tick!(client, ContractRef, dex, pool_key, upper_tick_index); - let lower_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, lower_tick_index); - let upper_tick_bit = - is_tick_initialized!(client, ContractRef, dex, pool_key, upper_tick_index); - let alice_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); - let alice_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); - let dex_x = balance_of!(client, TokenRef, token_x, dex); - let dex_y = balance_of!(client, TokenRef, token_y, dex); - let expected_withdrawn_x = 499; - let expected_withdrawn_y = 999; - let expected_fee_x = 0; - - assert_eq!( - dex_x_before_remove - dex_x, - expected_withdrawn_x + expected_fee_x - ); - assert_eq!(dex_y_before_remove - dex_y, expected_withdrawn_y); - - // Check ticks - assert_eq!(lower_tick, Err(InvariantError::TickNotFound)); - assert_eq!(upper_tick, Err(InvariantError::TickNotFound)); - - // Check tickmap - assert!(!lower_tick_bit); - assert!(!upper_tick_bit); - - // Check pool - assert!(pool_state.liquidity == liquidity_delta); - assert!(pool_state.current_tick_index == -10); - - Ok(()) - } - - #[ink_e2e::test] - async fn position_slippage_zero_slippage_and_inside_range( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - let alice = ink_e2e::alice(); - let (dex, token_x, token_y) = - init_slippage_dex_and_tokens!(client, ContractRef, TokenRef); - let pool_key = init_slippage_pool_with_liquidity!( - client, - ContractRef, - TokenRef, - dex, - token_x, - token_y - ); - - let pool = get_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - pool_key.fee_tier - ) - .unwrap(); - - // zero slippage - { - let liquidity_delta = Liquidity::from_integer(1_000_000); - let known_price = pool.sqrt_price; - let tick = pool_key.fee_tier.tick_spacing as i32; - create_position!( - client, - ContractRef, - dex, - pool_key, - -tick, - tick, - liquidity_delta, - known_price, - known_price, - alice - ); - } - // inside range - { - let liquidity_delta = Liquidity::from_integer(1_000_000); - let known_price = SqrtPrice::new(1010000000000000000000000); - let limit_lower = SqrtPrice::new(994734637981406576896367); - let limit_upper = SqrtPrice::new(1025038048074314166333500); - - let tick = pool_key.fee_tier.tick_spacing as i32; - - create_position!( - client, - ContractRef, - dex, - pool_key, - -tick, - tick, - liquidity_delta, - limit_lower, - limit_upper, - alice - ); - } - - Ok(()) - } - #[ink_e2e::test] - #[should_panic] - async fn position_slippage_below_range(mut client: ink_e2e::Client) -> () { - let alice = ink_e2e::alice(); - let (dex, token_x, token_y) = - init_slippage_dex_and_tokens!(client, ContractRef, TokenRef); - let pool_key = init_slippage_pool_with_liquidity!( - client, - ContractRef, - TokenRef, - dex, - token_x, - token_y - ); - - let pool = get_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - pool_key.fee_tier - ) - .unwrap(); - - let liquidity_delta = Liquidity::from_integer(1_000_000); - let known_price = SqrtPrice::new(1030000000000000000000000); - let limit_lower = SqrtPrice::new(1014432353584998786339859); - let limit_upper = SqrtPrice::new(1045335831204498605270797); - let tick = pool_key.fee_tier.tick_spacing as i32; - create_position!( - client, - ContractRef, - dex, - pool_key, - -tick, - tick, - liquidity_delta, - limit_lower, - limit_upper, - alice - ) - .unwrap(); - } - #[ink_e2e::test] - #[should_panic] - async fn position_slippage_above_range(mut client: ink_e2e::Client) -> () { - let alice = ink_e2e::alice(); - let (dex, token_x, token_y) = - init_slippage_dex_and_tokens!(client, ContractRef, TokenRef); - let pool_key = init_slippage_pool_with_liquidity!( - client, - ContractRef, - TokenRef, - dex, - token_x, - token_y - ); - - let pool = get_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - pool_key.fee_tier - ) - .unwrap(); - - let liquidity_delta = Liquidity::from_integer(1_000_000); - let known_price = pool.sqrt_price; - let limit_lower = SqrtPrice::new(955339206774222158009382); - let limit_upper = SqrtPrice::new(984442481813945288458906); - let tick = pool_key.fee_tier.tick_spacing as i32; - create_position!( - client, - ContractRef, - dex, - pool_key, - -tick, - tick, - liquidity_delta, - limit_lower, - limit_upper, - alice - ) - .unwrap(); - } - - #[ink_e2e::test] - #[should_panic] - async fn no_liquidity_swap(mut client: ink_e2e::Client) -> () { - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - let alice = ink_e2e::alice(); - let bob = ink_e2e::bob(); - let init_tick = 0; - - let initial_mint = 10u128.pow(10); - - let dex = create_dex!(client, ContractRef, Percentage::from_scale(1, 2)); - let (token_x, token_y) = create_tokens!(client, TokenRef, initial_mint, initial_mint); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let lower_tick_index = -10; - let upper_tick_index = 10; - - let mint_amount = 10u128.pow(10); - mint!( - client, - TokenRef, - token_x, - address_of!(Alice), - mint_amount, - alice - ); - mint!( - client, - TokenRef, - token_y, - address_of!(Alice), - mint_amount, - alice - ); - - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); - - let liquidity_delta = Liquidity::from_integer(20_006_000); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - assert_eq!(pool_state.liquidity, liquidity_delta); - - let mint_amount = 10067; - mint!( - client, - TokenRef, - token_x, - address_of!(Bob), - mint_amount, - alice - ); - - approve!(client, TokenRef, token_x, dex, mint_amount, bob); - - let dex_x_before = balance_of!(client, TokenRef, token_x, dex); - let dex_y_before = balance_of!(client, TokenRef, token_y, dex); - - let swap_amount = TokenAmount::new(10067); - let target_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); - let quoted_target_sqrt_price = quote!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - target_sqrt_price - ) - .unwrap() - .target_sqrt_price; - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - quoted_target_sqrt_price, - bob - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let expected_price = calculate_sqrt_price(-10).unwrap(); - let expected_y_amount_out = 9999; - - assert_eq!(pool.liquidity, liquidity_delta); - assert_eq!(pool.current_tick_index, lower_tick_index); - assert_eq!(pool.sqrt_price, expected_price); - - let bob_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - let bob_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); - let dex_x_after = balance_of!(client, TokenRef, token_x, dex); - let dex_y_after = balance_of!(client, TokenRef, token_y, dex); - - let delta_dex_x = dex_x_after - dex_x_before; - let delta_dex_y = dex_y_before - dex_y_after; - - assert_eq!(bob_x, 0); - assert_eq!(bob_y, expected_y_amount_out); - assert_eq!(delta_dex_x, swap_amount.get()); - assert_eq!(delta_dex_y, expected_y_amount_out); - assert_eq!( - pool.fee_growth_global_x, - FeeGrowth::new(29991002699190242927121) - ); - assert_eq!(pool.fee_growth_global_y, FeeGrowth::new(0)); - assert_eq!(pool.fee_protocol_token_x, TokenAmount::new(1)); - assert_eq!(pool.fee_protocol_token_y, TokenAmount::new(0)); - - let swap_amount = TokenAmount(1); - let target_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); - let quoted_target_sqrt_price = quote!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - target_sqrt_price - ) - .unwrap() - .target_sqrt_price; - swap!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - quoted_target_sqrt_price, - bob - ); - } - - #[ink_e2e::test] - async fn liquidity_gap_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - let alice = ink_e2e::alice(); - let bob = ink_e2e::bob(); - let init_tick = 0; - - let initial_mint = 10u128.pow(10); - - let dex = create_dex!(client, ContractRef, Percentage::from_scale(1, 2)); - let (token_x, token_y) = create_tokens!(client, TokenRef, initial_mint, initial_mint); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let lower_tick_index = -10; - let upper_tick_index = 10; - - let mint_amount = 10u128.pow(10); - mint!( - client, - TokenRef, - token_x, - address_of!(Alice), - mint_amount, - alice - ); - mint!( - client, - TokenRef, - token_y, - address_of!(Alice), - mint_amount, - alice - ); - - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); - - let liquidity_delta = Liquidity::from_integer(20_006_000); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - assert_eq!(pool_state.liquidity, liquidity_delta); - - let mint_amount = 10067; - mint!( - client, - TokenRef, - token_x, - address_of!(Bob), - mint_amount, - alice - ); - - approve!(client, TokenRef, token_x, dex, mint_amount, bob); - - let dex_x_before = balance_of!(client, TokenRef, token_x, dex); - let dex_y_before = balance_of!(client, TokenRef, token_y, dex); - - let swap_amount = TokenAmount::new(10067); - let target_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); - let quoted_target_sqrt_price = quote!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - target_sqrt_price - ) - .unwrap() - .target_sqrt_price; - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - quoted_target_sqrt_price, - bob - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let expected_price = calculate_sqrt_price(-10).unwrap(); - let expected_y_amount_out = 9999; - - assert_eq!(pool.liquidity, liquidity_delta); - assert_eq!(pool.current_tick_index, lower_tick_index); - assert_eq!(pool.sqrt_price, expected_price); - - let bob_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - let bob_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); - let dex_x_after = balance_of!(client, TokenRef, token_x, dex); - let dex_y_after = balance_of!(client, TokenRef, token_y, dex); - - let delta_dex_x = dex_x_after - dex_x_before; - let delta_dex_y = dex_y_before - dex_y_after; - - assert_eq!(bob_x, 0); - assert_eq!(bob_y, expected_y_amount_out); - assert_eq!(delta_dex_x, swap_amount.get()); - assert_eq!(delta_dex_y, expected_y_amount_out); - assert_eq!( - pool.fee_growth_global_x, - FeeGrowth::new(29991002699190242927121) - ); - assert_eq!(pool.fee_growth_global_y, FeeGrowth::new(0)); - assert_eq!(pool.fee_protocol_token_x, TokenAmount::new(1)); - assert_eq!(pool.fee_protocol_token_y, TokenAmount::new(0)); - - // Should skip gap and then swap - let lower_tick_after_swap = -90; - let upper_tick_after_swap = -50; - let liquidity_delta = Liquidity::from_integer(20008000); - - approve!(client, TokenRef, token_x, dex, liquidity_delta.get(), alice); - approve!(client, TokenRef, token_y, dex, liquidity_delta.get(), alice); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_after_swap, - upper_tick_after_swap, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - let swap_amount = TokenAmount::new(5000); - mint!( - client, - TokenRef, - token_x, - address_of!(Bob), - swap_amount.get(), - alice - ); - - approve!(client, TokenRef, token_x, dex, swap_amount.get(), bob); - - let dex_x_before = balance_of!(client, TokenRef, token_x, dex); - let dex_y_before = balance_of!(client, TokenRef, token_y, dex); - - let target_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); - let quoted_target_sqrt_price = quote!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - target_sqrt_price - ) - .unwrap() - .target_sqrt_price; - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - swap_amount, - true, - quoted_target_sqrt_price, - bob - ); - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - let bob_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); - let bob_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); - let dex_x_after = balance_of!(client, TokenRef, token_x, dex); - let dex_y_after = balance_of!(client, TokenRef, token_y, dex); - - let delta_dex_x = dex_x_after - dex_x_before; - let delta_dex_y = dex_y_before - dex_y_after; - Ok(()) - } - - #[ink_e2e::test] - async fn cross_both_side_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - let alice = ink_e2e::alice(); - let bob = ink_e2e::bob(); - let init_tick = 0; - - let initial_mint = 10u128.pow(10); - - let dex = create_dex!(client, ContractRef, Percentage::from_scale(1, 2)); - let (token_x, token_y) = create_tokens!(client, TokenRef, initial_mint, initial_mint); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let lower_tick_index = -10; - let upper_tick_index = 10; - - let mint_amount = 10u128.pow(5); - mint!( - client, - TokenRef, - token_x, - address_of!(Bob), - mint_amount, - alice - ); - mint!( - client, - TokenRef, - token_y, - address_of!(Alice), - mint_amount, - alice - ); - - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); - - let liquidity_delta = Liquidity::new(20006000000000); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - create_position!( - client, - ContractRef, - dex, - pool_key, - -20, - lower_tick_index, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - assert_eq!(pool.liquidity, liquidity_delta); - - let limit_without_cross_tick_amount = TokenAmount(10_068); - let not_cross_amount = TokenAmount(1); - let min_amount_to_cross_from_tick_price = TokenAmount(3); - let crossing_amount_by_amount_out = TokenAmount(20136101434); - - let mint_amount = limit_without_cross_tick_amount.get() - + not_cross_amount.get() - + min_amount_to_cross_from_tick_price.get() - + crossing_amount_by_amount_out.get(); - - mint!( - client, - TokenRef, - token_x, - address_of!(Alice), - mint_amount, - alice - ); - mint!( - client, - TokenRef, - token_y, - address_of!(Alice), - mint_amount, - alice - ); - - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); - - let pool_before = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - let limit_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - limit_without_cross_tick_amount, - true, - limit_sqrt_price, - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let expected_tick = -10; - let expected_price = calculate_sqrt_price(expected_tick).unwrap(); - - assert_eq!(pool.current_tick_index, expected_tick); - assert_eq!(pool.liquidity, pool_before.liquidity); - assert_eq!(pool.sqrt_price, expected_price); - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - min_amount_to_cross_from_tick_price, - true, - limit_sqrt_price, - alice - ); - - swap!( - client, - ContractRef, - dex, - pool_key, - false, - min_amount_to_cross_from_tick_price, - true, - SqrtPrice::new(MAX_SQRT_PRICE), - alice - ); - - let massive_x = 10u128.pow(19); - let massive_y = 10u128.pow(19); - - mint!( - client, - TokenRef, - token_x, - address_of!(Alice), - massive_x, - alice - ); - mint!( - client, - TokenRef, - token_y, - address_of!(Alice), - massive_y, - alice - ); - approve!(client, TokenRef, token_x, dex, massive_x, alice); - approve!(client, TokenRef, token_y, dex, massive_y, alice); - - let massive_liquidity_delta = Liquidity::new(19996000399699881985603000000); - - create_position!( - client, - ContractRef, - dex, - pool_key, - -20, - 0, - massive_liquidity_delta, - SqrtPrice::new(MIN_SQRT_PRICE), - SqrtPrice::new(MAX_SQRT_PRICE), - alice - ); - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - TokenAmount(1), - false, - limit_sqrt_price, - alice - ); - - swap!( - client, - ContractRef, - dex, - pool_key, - false, - TokenAmount(2), - true, - SqrtPrice::new(MAX_SQRT_PRICE), - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - assert_eq!(pool.current_tick_index, -20); - assert_eq!( - pool.fee_growth_global_x, - FeeGrowth::new(29991002699190242927121) - ); - assert_eq!(pool.fee_growth_global_y, FeeGrowth::new(0)); - assert_eq!(pool.fee_protocol_token_x, TokenAmount(4)); - assert_eq!(pool.fee_protocol_token_y, TokenAmount(2)); - assert_eq!( - pool.liquidity, - Liquidity::new(19996000399699901991603000000) - ); - assert_eq!(pool.sqrt_price, SqrtPrice::new(999500149964999999999999)); - - let final_last_tick = get_tick!(client, ContractRef, dex, pool_key, -20).unwrap(); - assert_eq!(final_last_tick.fee_growth_outside_x, FeeGrowth::new(0)); - assert_eq!(final_last_tick.fee_growth_outside_y, FeeGrowth::new(0)); - assert_eq!( - final_last_tick.liquidity_change, - Liquidity::new(19996000399699901991603000000) - ); - - let final_lower_tick = get_tick!(client, ContractRef, dex, pool_key, -10).unwrap(); - assert_eq!( - final_lower_tick.fee_growth_outside_x, - FeeGrowth::new(29991002699190242927121) - ); - assert_eq!(final_lower_tick.fee_growth_outside_y, FeeGrowth::new(0)); - assert_eq!(final_lower_tick.liquidity_change, Liquidity::new(0)); - - let final_upper_tick = get_tick!(client, ContractRef, dex, pool_key, 10).unwrap(); - assert_eq!(final_upper_tick.fee_growth_outside_x, FeeGrowth::new(0)); - assert_eq!(final_upper_tick.fee_growth_outside_y, FeeGrowth::new(0)); - assert_eq!( - final_upper_tick.liquidity_change, - Liquidity::new(20006000000000) - ); - - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn cross_both_side_not_cross_case_test(mut client: ink_e2e::Client) -> () { - let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - let alice = ink_e2e::alice(); - let bob = ink_e2e::bob(); - let init_tick = 0; - - let initial_mint = 10u128.pow(10); - - let dex = create_dex!(client, ContractRef, Percentage::from_scale(1, 2)); - let (token_x, token_y) = create_tokens!(client, TokenRef, initial_mint, initial_mint); - - let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - - let pool = create_pool!( - client, - ContractRef, - dex, - token_x, - token_y, - fee_tier, - init_tick, - alice - ); - - let lower_tick_index = -10; - let upper_tick_index = 10; - - let mint_amount = 10u128.pow(5); - mint!( - client, - TokenRef, - token_x, - address_of!(Alice), - mint_amount, - alice - ); - mint!( - client, - TokenRef, - token_y, - address_of!(Alice), - mint_amount, - alice - ); - - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); - - let liquidity_delta = Liquidity::new(20006000000000); - - let pool_state = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - create_position!( - client, - ContractRef, - dex, - pool_key, - lower_tick_index, - upper_tick_index, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - create_position!( - client, - ContractRef, - dex, - pool_key, - -20, - lower_tick_index, - liquidity_delta, - pool_state.sqrt_price, - pool_state.sqrt_price, - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - assert_eq!(pool.liquidity, liquidity_delta); - - let limit_without_cross_tick_amount = TokenAmount(10_068); - let not_cross_amount = TokenAmount(1); - let min_amount_to_cross_from_tick_price = TokenAmount(3); - let crossing_amount_by_amount_out = TokenAmount(20136101434); - - let mint_amount = limit_without_cross_tick_amount.get() - + not_cross_amount.get() - + min_amount_to_cross_from_tick_price.get() - + crossing_amount_by_amount_out.get(); - - mint!( - client, - TokenRef, - token_x, - address_of!(Alice), - mint_amount, - alice - ); - mint!( - client, - TokenRef, - token_y, - address_of!(Alice), - mint_amount, - alice - ); - - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); - - let pool_before = - get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - - let limit_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - limit_without_cross_tick_amount, - true, - limit_sqrt_price, - alice - ); - - let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); - let expected_tick = -10; - let expected_price = calculate_sqrt_price(expected_tick).unwrap(); - - assert_eq!(pool.current_tick_index, expected_tick); - assert_eq!(pool.liquidity, pool_before.liquidity); - assert_eq!(pool.sqrt_price, expected_price); - - let slippage = SqrtPrice::new(MIN_SQRT_PRICE); - let target_sqrt_price = quote!( - client, - ContractRef, - dex, - pool_key, - true, - not_cross_amount, - true, - slippage - ) - .unwrap() - .target_sqrt_price; - - swap!( - client, - ContractRef, - dex, - pool_key, - true, - not_cross_amount, - true, - target_sqrt_price, - alice - ); - } - } } From a90e544ebca9a9a98312286dcfcb72e8301134e9 Mon Sep 17 00:00:00 2001 From: zielvna Date: Mon, 4 Dec 2023 20:20:58 +0100 Subject: [PATCH 5/6] remove unnecessary fee tier tests --- src/tests/fee_tier.rs | 73 ------------------------------------------- 1 file changed, 73 deletions(-) delete mode 100644 src/tests/fee_tier.rs diff --git a/src/tests/fee_tier.rs b/src/tests/fee_tier.rs deleted file mode 100644 index e2d7290e..00000000 --- a/src/tests/fee_tier.rs +++ /dev/null @@ -1,73 +0,0 @@ -#[cfg(test)] -pub mod e2e_tests { - use crate::{ - contract::ContractRef, - contracts::{entrypoints::Invariant, FeeTier}, - math::types::percentage::Percentage, - }; - use decimal::*; - use ink_e2e::build_message; - use test_helpers::{add_fee_tier, create_dex, create_standard_fee_tiers, fee_tier_exist}; - - type E2EResult = Result>; - - #[ink_e2e::test] - async fn add_fee_tier_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let fee_tier = FeeTier::new(Percentage::new(0), 10u16).unwrap(); - let alice = ink_e2e::alice(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); - let fee_tier = fee_tier_exist!( - client, - ContractRef, - dex, - FeeTier::new(Percentage::new(0), 10).unwrap() - ); - assert!(fee_tier); - Ok(()) - } - - #[ink_e2e::test] - async fn fee_tier_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let admin = ink_e2e::alice(); - let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 100).unwrap(); - let result = add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - assert!(result.is_ok()); - Ok(()) - } - - #[ink_e2e::test] - #[should_panic] - async fn invalid_spacing_fee_tier_test(mut client: ink_e2e::Client) -> () { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let admin = ink_e2e::alice(); - // 0 tick spacing | should fail - let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 0).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); - } - - #[ink_e2e::test] - #[should_panic] - async fn non_admin_fee_tier_caller_test(mut client: ink_e2e::Client) -> () { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let user = ink_e2e::bob(); - // not-admin - let fee_tier = FeeTier::new(Percentage::from_scale(5, 1), 10).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, user).unwrap(); - } - - #[ink_e2e::test] - async fn create_standard_fee_tier_test(mut client: ink_e2e::Client) -> E2EResult<()> { - let dex = create_dex!(client, ContractRef, Percentage::new(0)); - create_standard_fee_tiers!(client, ContractRef, dex); - let fee_tier = fee_tier_exist!( - client, - ContractRef, - dex, - FeeTier::new(Percentage::from_scale(5, 2), 100).unwrap() - ); - assert!(fee_tier); - Ok(()) - } -} From 57c77fae0fe591a42ce98a2cab851641ec7e1fb2 Mon Sep 17 00:00:00 2001 From: zielvna Date: Mon, 4 Dec 2023 21:18:54 +0100 Subject: [PATCH 6/6] fix clippy errors --- src/lib.rs | 1 + src/test_helpers/snippets.rs | 89 +++++++++++------- src/tests/add_fee_tier.rs | 10 +- src/tests/change_fee_receiver.rs | 6 +- src/tests/change_protocol_fee.rs | 12 +-- src/tests/claim.rs | 4 +- src/tests/create_pool.rs | 2 +- src/tests/cross.rs | 2 +- src/tests/cross_both_side.rs | 98 ++++++++++++-------- src/tests/limits.rs | 55 ++++++----- src/tests/liquidity_gap.rs | 72 +++++++++------ src/tests/max_tick_cross.rs | 19 ++-- src/tests/mod.rs | 1 - src/tests/multiple_swap.rs | 2 +- src/tests/position.rs | 80 +++++++++------- src/tests/position_list.rs | 151 +++++++++++++++++++------------ src/tests/position_slippage.rs | 10 +- src/tests/protocol_fee.rs | 6 +- src/tests/remove_fee_tier.rs | 12 +-- src/tests/slippage.rs | 13 +-- src/tests/swap.rs | 46 ++++++---- src/tests/swap_route.rs | 33 ++++--- 22 files changed, 428 insertions(+), 296 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c3a4b93e..87594d45 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ extern crate alloc; mod contracts; pub mod math; +pub mod tests; #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] #[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] diff --git a/src/test_helpers/snippets.rs b/src/test_helpers/snippets.rs index 860bc712..958f5283 100644 --- a/src/test_helpers/snippets.rs +++ b/src/test_helpers/snippets.rs @@ -194,7 +194,7 @@ macro_rules! init_basic_pool { tick_spacing: 10, }; let alice = ink_e2e::alice(); - add_fee_tier!($client, $dex, $dex_address, fee_tier, alice); + add_fee_tier!($client, $dex, $dex_address, fee_tier, alice).unwrap(); let init_tick = 0; create_pool!( @@ -206,7 +206,8 @@ macro_rules! init_basic_pool { fee_tier, init_tick, alice - ); + ) + .unwrap(); }}; } @@ -218,7 +219,7 @@ macro_rules! init_slippage_pool_with_liquidity { tick_spacing: 10, }; let alice = ink_e2e::alice(); - add_fee_tier!($client, $dex, $dex_address, fee_tier, alice); + add_fee_tier!($client, $dex, $dex_address, fee_tier, alice).unwrap(); let init_tick = 0; create_pool!( @@ -230,7 +231,8 @@ macro_rules! init_slippage_pool_with_liquidity { fee_tier, init_tick, alice - ); + ) + .unwrap(); let fee_tier = FeeTier { fee: Percentage::from_scale(6, 3), tick_spacing: 10, @@ -245,7 +247,8 @@ macro_rules! init_slippage_pool_with_liquidity { $dex_address, mint_amount, alice - ); + ) + .unwrap(); approve!( $client, $token, @@ -253,7 +256,8 @@ macro_rules! init_slippage_pool_with_liquidity { $dex_address, mint_amount, alice - ); + ) + .unwrap(); let pool_key = PoolKey::new($token_x_address, $token_y_address, fee_tier).unwrap(); let lower_tick = -1000; @@ -282,7 +286,8 @@ macro_rules! init_slippage_pool_with_liquidity { slippage_limit_lower, slippage_limit_upper, alice - ); + ) + .unwrap(); let pool_after = get_pool!( $client, @@ -317,7 +322,8 @@ macro_rules! init_basic_position { $dex_address, mint_amount, alice - ); + ) + .unwrap(); approve!( $client, $token, @@ -325,7 +331,8 @@ macro_rules! init_basic_position { $dex_address, mint_amount, alice - ); + ) + .unwrap(); let pool_key = PoolKey::new($token_x_address, $token_y_address, fee_tier).unwrap(); let lower_tick = -20; @@ -354,7 +361,8 @@ macro_rules! init_basic_position { slippage_limit_lower, slippage_limit_upper, alice - ); + ) + .unwrap(); let pool_after = get_pool!( $client, @@ -387,7 +395,8 @@ macro_rules! init_cross_position { $dex_address, mint_amount, alice - ); + ) + .unwrap(); approve!( $client, $token, @@ -395,7 +404,8 @@ macro_rules! init_cross_position { $dex_address, mint_amount, alice - ); + ) + .unwrap(); let pool_key = PoolKey::new($token_x_address, $token_y_address, fee_tier).unwrap(); let lower_tick = -40; @@ -424,7 +434,8 @@ macro_rules! init_cross_position { slippage_limit_lower, slippage_limit_upper, alice - ); + ) + .unwrap(); let pool_after = get_pool!( $client, @@ -458,10 +469,11 @@ macro_rules! init_basic_swap { address_of!(Bob), amount, bob - ); + ) + .unwrap(); let amount_x = balance_of!($client, $token, $token_x_address, address_of!(Bob)); assert_eq!(amount_x, amount); - approve!($client, $token, $token_x_address, $dex_address, amount, bob); + approve!($client, $token, $token_x_address, $dex_address, amount, bob).unwrap(); let amount_x = balance_of!($client, $token, $token_x_address, $dex_address); let amount_y = balance_of!($client, $token, $token_y_address, $dex_address); @@ -490,7 +502,8 @@ macro_rules! init_basic_swap { true, slippage, bob - ); + ) + .unwrap(); let pool_after = get_pool!( $client, @@ -544,10 +557,11 @@ macro_rules! init_cross_swap { address_of!(Bob), amount, bob - ); + ) + .unwrap(); let amount_x = balance_of!($client, $token, $token_x_address, address_of!(Bob)); assert_eq!(amount_x, amount); - approve!($client, $token, $token_x_address, $dex_address, amount, bob); + approve!($client, $token, $token_x_address, $dex_address, amount, bob).unwrap(); let amount_x = balance_of!($client, $token, $token_x_address, $dex_address); let amount_y = balance_of!($client, $token, $token_y_address, $dex_address); @@ -576,7 +590,8 @@ macro_rules! init_cross_swap { true, slippage, bob - ); + ) + .unwrap(); let pool_after = get_pool!( $client, @@ -646,7 +661,8 @@ macro_rules! swap_exact_limit { $by_amount_in, quote_result.target_sqrt_price, $caller - ); + ) + .unwrap(); }}; } @@ -657,17 +673,17 @@ macro_rules! big_deposit_and_swap { let mint_amount = 2u128.pow(75) - 1; let alice = ink_e2e::alice(); - approve!($client, $token, token_x, dex, u128::MAX, alice); - approve!($client, $token, token_y, dex, u128::MAX, alice); + approve!($client, $token, token_x, dex, u128::MAX, alice).unwrap(); + approve!($client, $token, token_y, dex, u128::MAX, alice).unwrap(); let fee_tier = FeeTier { fee: Percentage::from_scale(6, 3), tick_spacing: 1, }; - add_fee_tier!($client, $dex, dex, fee_tier, alice); + add_fee_tier!($client, $dex, dex, fee_tier, alice).unwrap(); let init_tick = 0; - create_pool!($client, $dex, dex, token_x, token_y, fee_tier, init_tick, alice); + create_pool!($client, $dex, dex, token_x, token_y, fee_tier, init_tick, alice).unwrap(); let lower_tick = if $x_to_y { -(fee_tier.tick_spacing as i32) @@ -717,7 +733,8 @@ macro_rules! big_deposit_and_swap { slippage_limit_lower, slippage_limit_upper, alice - ); + ) + .unwrap(); let amount_x = balance_of!($client, $token, token_x, address_of!(Alice)); let amount_y = balance_of!($client, $token, token_y, address_of!(Alice)); @@ -745,7 +762,8 @@ macro_rules! big_deposit_and_swap { true, sqrt_price_limit, alice - ); + ) + .unwrap(); let amount_x = balance_of!($client, $token, token_x, address_of!(Alice)); let amount_y = balance_of!($client, $token, token_y, address_of!(Alice)); @@ -769,14 +787,14 @@ macro_rules! multiple_swap { tick_spacing: 1, }; let alice = ink_e2e::alice(); - add_fee_tier!($client, $dex, dex, fee_tier, alice); + add_fee_tier!($client, $dex, dex, fee_tier, alice).unwrap(); let init_tick = 0; - create_pool!($client, $dex, dex, token_x, token_y, fee_tier, init_tick, alice); + create_pool!($client, $dex, dex, token_x, token_y, fee_tier, init_tick, alice).unwrap(); let mint_amount = 10u128.pow(10); - approve!($client, $token, token_x, dex, mint_amount, alice); - approve!($client, $token, token_y, dex, mint_amount, alice); + approve!($client, $token, token_x, dex, mint_amount, alice).unwrap(); + approve!($client, $token, token_y, dex, mint_amount, alice).unwrap(); let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); let mut upper_tick = 953; @@ -810,19 +828,20 @@ macro_rules! multiple_swap { slippage_limit_lower, slippage_limit_upper, alice - ); + ) + .unwrap(); let bob = ink_e2e::bob(); if $x_to_y { - mint!($client, $token, token_x, address_of!(Bob), amount, bob); + mint!($client, $token, token_x, address_of!(Bob), amount, bob).unwrap(); let amount_x = balance_of!($client, $token, token_x, address_of!(Bob)); assert_eq!(amount_x, amount); - approve!($client, $token, token_x, dex, amount, bob); + approve!($client, $token, token_x, dex, amount, bob).unwrap(); } else { - mint!($client, $token, token_y, address_of!(Bob), amount, bob); + mint!($client, $token, token_y, address_of!(Bob), amount, bob).unwrap(); let amount_y = balance_of!($client, $token, token_y, address_of!(Bob)); assert_eq!(amount_y, amount); - approve!($client, $token, token_y, dex, amount, bob); + approve!($client, $token, token_y, dex, amount, bob).unwrap(); } let swap_amount = TokenAmount(10); diff --git a/src/tests/add_fee_tier.rs b/src/tests/add_fee_tier.rs index b4171ddc..936d1833 100644 --- a/src/tests/add_fee_tier.rs +++ b/src/tests/add_fee_tier.rs @@ -17,13 +17,13 @@ pub mod e2e_tests { let dex = create_dex!(client, ContractRef, Percentage::new(0)); let first_fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, first_fee_tier, admin); + add_fee_tier!(client, ContractRef, dex, first_fee_tier, admin).unwrap(); let second_fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap(); - add_fee_tier!(client, ContractRef, dex, second_fee_tier, admin); + add_fee_tier!(client, ContractRef, dex, second_fee_tier, admin).unwrap(); let third_fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 4).unwrap(); - add_fee_tier!(client, ContractRef, dex, third_fee_tier, admin); + add_fee_tier!(client, ContractRef, dex, third_fee_tier, admin).unwrap(); let exist = fee_tier_exist!( client, @@ -65,7 +65,7 @@ pub mod e2e_tests { let dex = create_dex!(client, ContractRef, Percentage::new(0)); let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); add_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); @@ -87,7 +87,7 @@ pub mod e2e_tests { let dex = create_dex!(client, ContractRef, Percentage::new(0)); let fee_tier = FeeTier::new(Percentage::new(0), 10).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); Ok(()) } diff --git a/src/tests/change_fee_receiver.rs b/src/tests/change_fee_receiver.rs index 5a1dc092..ad1a40df 100644 --- a/src/tests/change_fee_receiver.rs +++ b/src/tests/change_fee_receiver.rs @@ -25,7 +25,7 @@ pub mod e2e_tests { let alice = ink_e2e::alice(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); let result = create_pool!( client, @@ -42,7 +42,7 @@ pub mod e2e_tests { let admin = ink_e2e::alice(); let alice = address_of!(Alice); let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - change_fee_receiver!(client, ContractRef, dex, pool_key, alice, admin); + change_fee_receiver!(client, ContractRef, dex, pool_key, alice, admin).unwrap(); let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); assert_eq!(pool.fee_receiver, alice); @@ -60,7 +60,7 @@ pub mod e2e_tests { let admin = ink_e2e::alice(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); let result = create_pool!( client, diff --git a/src/tests/change_protocol_fee.rs b/src/tests/change_protocol_fee.rs index 1f295aff..cd59dacf 100644 --- a/src/tests/change_protocol_fee.rs +++ b/src/tests/change_protocol_fee.rs @@ -15,8 +15,8 @@ pub mod e2e_tests { let contract = create_dex!(client, ContractRef, Percentage::new(0)); let protocol_fee = { - let _msg = build_message::(contract.clone()) - .call(|contract| contract.get_protocol_fee()); + let _msg = + build_message::(contract).call(|contract| contract.get_protocol_fee()); client .call(&ink_e2e::alice(), _msg, 0, None) .await @@ -27,7 +27,7 @@ pub mod e2e_tests { assert_eq!(protocol_fee, Percentage::new(0)); let _result = { - let _msg = build_message::(contract.clone()) + let _msg = build_message::(contract) .call(|contract| contract.change_protocol_fee(Percentage::new(1))); client .call(&ink_e2e::alice(), _msg, 0, None) @@ -36,8 +36,8 @@ pub mod e2e_tests { }; let protocol_fee = { - let _msg = build_message::(contract.clone()) - .call(|contract| contract.get_protocol_fee()); + let _msg = + build_message::(contract).call(|contract| contract.get_protocol_fee()); client .call(&ink_e2e::alice(), _msg, 0, None) .await @@ -55,7 +55,7 @@ pub mod e2e_tests { async fn change_protocol_fee_should_panic(mut client: ink_e2e::Client) -> () { let contract = create_dex!(client, ContractRef, Percentage::new(0)); - let _msg = build_message::(contract.clone()) + let _msg = build_message::(contract) .call(|contract| contract.change_protocol_fee(Percentage::new(1))); client .call(&ink_e2e::bob(), _msg, 0, None) diff --git a/src/tests/claim.rs b/src/tests/claim.rs index c7e1f0f1..17c5cb04 100644 --- a/src/tests/claim.rs +++ b/src/tests/claim.rs @@ -6,7 +6,7 @@ pub mod e2e_tests { math::{ types::{ fee_growth::FeeGrowth, liquidity::Liquidity, percentage::Percentage, - sqrt_price::sqrt_price::SqrtPrice, token_amount::TokenAmount, + sqrt_price::SqrtPrice, token_amount::TokenAmount, }, MIN_SQRT_PRICE, }, @@ -35,7 +35,7 @@ pub mod e2e_tests { let user_amount_before_claim = balance_of!(client, TokenRef, token_x, address_of!(Alice)); let dex_amount_before_claim = balance_of!(client, TokenRef, token_x, dex); - claim_fee!(client, ContractRef, dex, 0, alice); + claim_fee!(client, ContractRef, dex, 0, alice).unwrap(); let user_amount_after_claim = balance_of!(client, TokenRef, token_x, address_of!(Alice)); let dex_amount_after_claim = balance_of!(client, TokenRef, token_x, dex); diff --git a/src/tests/create_pool.rs b/src/tests/create_pool.rs index 1ea755d4..7c579256 100644 --- a/src/tests/create_pool.rs +++ b/src/tests/create_pool.rs @@ -22,7 +22,7 @@ pub mod e2e_tests { let alice = ink_e2e::alice(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); let result = create_pool!( client, diff --git a/src/tests/cross.rs b/src/tests/cross.rs index 7afcbe6f..05bb412a 100644 --- a/src/tests/cross.rs +++ b/src/tests/cross.rs @@ -6,7 +6,7 @@ pub mod e2e_tests { math::{ types::{ fee_growth::FeeGrowth, liquidity::Liquidity, percentage::Percentage, - sqrt_price::sqrt_price::SqrtPrice, token_amount::TokenAmount, + sqrt_price::SqrtPrice, token_amount::TokenAmount, }, MIN_SQRT_PRICE, }, diff --git a/src/tests/cross_both_side.rs b/src/tests/cross_both_side.rs index 10bb5e9e..fb40bfab 100644 --- a/src/tests/cross_both_side.rs +++ b/src/tests/cross_both_side.rs @@ -8,7 +8,7 @@ pub mod e2e_tests { fee_growth::FeeGrowth, liquidity::Liquidity, percentage::Percentage, - sqrt_price::sqrt_price::{calculate_sqrt_price, SqrtPrice}, + sqrt_price::{calculate_sqrt_price, SqrtPrice}, token_amount::TokenAmount, }, MAX_SQRT_PRICE, MIN_SQRT_PRICE, @@ -37,7 +37,7 @@ pub mod e2e_tests { let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); create_pool!( client, @@ -48,7 +48,8 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); let lower_tick_index = -10; let upper_tick_index = 10; @@ -61,7 +62,8 @@ pub mod e2e_tests { address_of!(Bob), mint_amount, alice - ); + ) + .unwrap(); mint!( client, TokenRef, @@ -69,10 +71,11 @@ pub mod e2e_tests { address_of!(Alice), mint_amount, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); + approve!(client, TokenRef, token_x, dex, mint_amount, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, mint_amount, alice).unwrap(); let liquidity_delta = Liquidity::new(20006000000000); @@ -89,7 +92,8 @@ pub mod e2e_tests { pool_state.sqrt_price, pool_state.sqrt_price, alice - ); + ) + .unwrap(); create_position!( client, @@ -102,7 +106,8 @@ pub mod e2e_tests { pool_state.sqrt_price, pool_state.sqrt_price, alice - ); + ) + .unwrap(); let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); @@ -125,7 +130,8 @@ pub mod e2e_tests { address_of!(Alice), mint_amount, alice - ); + ) + .unwrap(); mint!( client, TokenRef, @@ -133,10 +139,11 @@ pub mod e2e_tests { address_of!(Alice), mint_amount, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); + approve!(client, TokenRef, token_x, dex, mint_amount, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, mint_amount, alice).unwrap(); let pool_before = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); @@ -152,7 +159,8 @@ pub mod e2e_tests { true, limit_sqrt_price, alice - ); + ) + .unwrap(); let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); let expected_tick = -10; @@ -172,7 +180,8 @@ pub mod e2e_tests { true, limit_sqrt_price, alice - ); + ) + .unwrap(); swap!( client, @@ -184,7 +193,8 @@ pub mod e2e_tests { true, SqrtPrice::new(MAX_SQRT_PRICE), alice - ); + ) + .unwrap(); let massive_x = 10u128.pow(19); let massive_y = 10u128.pow(19); @@ -196,7 +206,8 @@ pub mod e2e_tests { address_of!(Alice), massive_x, alice - ); + ) + .unwrap(); mint!( client, TokenRef, @@ -204,9 +215,10 @@ pub mod e2e_tests { address_of!(Alice), massive_y, alice - ); - approve!(client, TokenRef, token_x, dex, massive_x, alice); - approve!(client, TokenRef, token_y, dex, massive_y, alice); + ) + .unwrap(); + approve!(client, TokenRef, token_x, dex, massive_x, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, massive_y, alice).unwrap(); let massive_liquidity_delta = Liquidity::new(19996000399699881985603000000); @@ -221,7 +233,8 @@ pub mod e2e_tests { SqrtPrice::new(MIN_SQRT_PRICE), SqrtPrice::new(MAX_SQRT_PRICE), alice - ); + ) + .unwrap(); swap!( client, @@ -233,7 +246,8 @@ pub mod e2e_tests { false, limit_sqrt_price, alice - ); + ) + .unwrap(); swap!( client, @@ -245,7 +259,8 @@ pub mod e2e_tests { true, SqrtPrice::new(MAX_SQRT_PRICE), alice - ); + ) + .unwrap(); let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); assert_eq!(pool.current_tick_index, -20); @@ -303,7 +318,7 @@ pub mod e2e_tests { let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); create_pool!( client, @@ -314,7 +329,8 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); let lower_tick_index = -10; let upper_tick_index = 10; @@ -327,7 +343,8 @@ pub mod e2e_tests { address_of!(Alice), mint_amount, alice - ); + ) + .unwrap(); mint!( client, TokenRef, @@ -335,10 +352,11 @@ pub mod e2e_tests { address_of!(Alice), mint_amount, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); + approve!(client, TokenRef, token_x, dex, mint_amount, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, mint_amount, alice).unwrap(); let liquidity_delta = Liquidity::new(20006000000000); @@ -355,7 +373,8 @@ pub mod e2e_tests { pool_state.sqrt_price, pool_state.sqrt_price, alice - ); + ) + .unwrap(); create_position!( client, @@ -368,7 +387,8 @@ pub mod e2e_tests { pool_state.sqrt_price, pool_state.sqrt_price, alice - ); + ) + .unwrap(); let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); @@ -391,7 +411,8 @@ pub mod e2e_tests { address_of!(Alice), mint_amount, alice - ); + ) + .unwrap(); mint!( client, TokenRef, @@ -399,10 +420,11 @@ pub mod e2e_tests { address_of!(Alice), mint_amount, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); + approve!(client, TokenRef, token_x, dex, mint_amount, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, mint_amount, alice).unwrap(); let pool_before = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); @@ -418,7 +440,8 @@ pub mod e2e_tests { true, limit_sqrt_price, alice - ); + ) + .unwrap(); let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); let expected_tick = -10; @@ -452,6 +475,7 @@ pub mod e2e_tests { true, target_sqrt_price, alice - ); + ) + .unwrap(); } } diff --git a/src/tests/limits.rs b/src/tests/limits.rs index f0900336..dc374d33 100644 --- a/src/tests/limits.rs +++ b/src/tests/limits.rs @@ -6,11 +6,11 @@ pub mod e2e_tests { entrypoints::Invariant, get_liquidity_by_x, get_liquidity_by_y, FeeTier, PoolKey, }, math::{ + clamm::get_delta_y, liquidity::Liquidity, - math::get_delta_y, types::{ percentage::Percentage, - sqrt_price::sqrt_price::{calculate_sqrt_price, get_max_tick, SqrtPrice}, + sqrt_price::{calculate_sqrt_price, get_max_tick, SqrtPrice}, token_amount::TokenAmount, }, MAX_SQRT_PRICE, MAX_TICK, MIN_SQRT_PRICE, @@ -48,12 +48,12 @@ pub mod e2e_tests { let mint_amount = 2u128.pow(75) - 1; let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, u128::MAX, alice); - approve!(client, TokenRef, token_y, dex, u128::MAX, alice); + approve!(client, TokenRef, token_x, dex, u128::MAX, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, u128::MAX, alice).unwrap(); let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); let init_tick = 0; create_pool!( @@ -65,7 +65,8 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); let lower_tick = -(fee_tier.tick_spacing as i32); let upper_tick = fee_tier.tick_spacing as i32; @@ -101,7 +102,8 @@ pub mod e2e_tests { slippage_limit_lower, slippage_limit_upper, alice - ); + ) + .unwrap(); let user_amount_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); let user_amount_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); @@ -123,11 +125,11 @@ pub mod e2e_tests { let mint_amount = 2u128.pow(105) - 1; let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, u128::MAX, alice); - approve!(client, TokenRef, token_y, dex, u128::MAX, alice); + approve!(client, TokenRef, token_x, dex, u128::MAX, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, u128::MAX, alice).unwrap(); let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); let init_tick = get_max_tick(1); create_pool!( @@ -139,7 +141,8 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); assert_eq!(pool.current_tick_index, init_tick); @@ -171,7 +174,8 @@ pub mod e2e_tests { slippage_limit_lower, slippage_limit_upper, alice - ); + ) + .unwrap(); Ok(()) } @@ -183,11 +187,11 @@ pub mod e2e_tests { let mint_amount = 2u128.pow(76) - 1; let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, u128::MAX, alice); - approve!(client, TokenRef, token_y, dex, u128::MAX, alice); + approve!(client, TokenRef, token_x, dex, u128::MAX, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, u128::MAX, alice).unwrap(); let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); let init_tick = 0; create_pool!( @@ -199,7 +203,8 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); let pos_amount = mint_amount / 2; let lower_tick = -(fee_tier.tick_spacing as i32); @@ -238,7 +243,8 @@ pub mod e2e_tests { slippage_limit_lower, slippage_limit_upper, alice - ); + ) + .unwrap(); let user_amount_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); let user_amount_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); @@ -269,7 +275,8 @@ pub mod e2e_tests { true, sqrt_price_limit, alice - ); + ) + .unwrap(); } Ok(()) @@ -281,11 +288,11 @@ pub mod e2e_tests { init_dex_and_tokens_max_mint_amount!(client, ContractRef, TokenRef); let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, u128::MAX, alice); - approve!(client, TokenRef, token_y, dex, u128::MAX, alice); + approve!(client, TokenRef, token_x, dex, u128::MAX, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, u128::MAX, alice).unwrap(); let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); let init_tick = get_max_tick(1); create_pool!( @@ -297,7 +304,8 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); assert_eq!(pool.current_tick_index, init_tick); @@ -318,7 +326,8 @@ pub mod e2e_tests { slippage_limit_lower, slippage_limit_upper, alice - ); + ) + .unwrap(); let contract_amount_x = balance_of!(client, TokenRef, token_x, dex); let contract_amount_y = balance_of!(client, TokenRef, token_y, dex); diff --git a/src/tests/liquidity_gap.rs b/src/tests/liquidity_gap.rs index a91081dd..fe186f73 100644 --- a/src/tests/liquidity_gap.rs +++ b/src/tests/liquidity_gap.rs @@ -8,7 +8,7 @@ pub mod e2e_tests { fee_growth::FeeGrowth, liquidity::Liquidity, percentage::Percentage, - sqrt_price::sqrt_price::{calculate_sqrt_price, SqrtPrice}, + sqrt_price::{calculate_sqrt_price, SqrtPrice}, token_amount::TokenAmount, }, MIN_SQRT_PRICE, @@ -38,7 +38,7 @@ pub mod e2e_tests { let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); create_pool!( client, @@ -49,7 +49,8 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); let lower_tick_index = -10; let upper_tick_index = 10; @@ -62,7 +63,8 @@ pub mod e2e_tests { address_of!(Alice), mint_amount, alice - ); + ) + .unwrap(); mint!( client, TokenRef, @@ -70,10 +72,11 @@ pub mod e2e_tests { address_of!(Alice), mint_amount, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); + approve!(client, TokenRef, token_x, dex, mint_amount, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, mint_amount, alice).unwrap(); let liquidity_delta = Liquidity::from_integer(20_006_000); @@ -90,7 +93,8 @@ pub mod e2e_tests { pool_state.sqrt_price, pool_state.sqrt_price, alice - ); + ) + .unwrap(); let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); @@ -104,9 +108,10 @@ pub mod e2e_tests { address_of!(Bob), mint_amount, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, mint_amount, bob); + approve!(client, TokenRef, token_x, dex, mint_amount, bob).unwrap(); let dex_x_before = balance_of!(client, TokenRef, token_x, dex); let dex_y_before = balance_of!(client, TokenRef, token_y, dex); @@ -136,7 +141,8 @@ pub mod e2e_tests { true, quoted_target_sqrt_price, bob - ); + ) + .unwrap(); let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); let expected_price = calculate_sqrt_price(-10).unwrap(); @@ -171,8 +177,8 @@ pub mod e2e_tests { let upper_tick_after_swap = -50; let liquidity_delta = Liquidity::from_integer(20008000); - approve!(client, TokenRef, token_x, dex, liquidity_delta.get(), alice); - approve!(client, TokenRef, token_y, dex, liquidity_delta.get(), alice); + approve!(client, TokenRef, token_x, dex, liquidity_delta.get(), alice).unwrap(); + approve!(client, TokenRef, token_y, dex, liquidity_delta.get(), alice).unwrap(); let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); @@ -187,7 +193,8 @@ pub mod e2e_tests { pool_state.sqrt_price, pool_state.sqrt_price, alice - ); + ) + .unwrap(); let swap_amount = TokenAmount::new(5000); mint!( @@ -197,9 +204,10 @@ pub mod e2e_tests { address_of!(Bob), swap_amount.get(), alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, swap_amount.get(), bob); + approve!(client, TokenRef, token_x, dex, swap_amount.get(), bob).unwrap(); let target_sqrt_price = SqrtPrice::new(MIN_SQRT_PRICE); let quoted_target_sqrt_price = quote!( @@ -225,7 +233,8 @@ pub mod e2e_tests { true, quoted_target_sqrt_price, bob - ); + ) + .unwrap(); get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); Ok(()) @@ -246,7 +255,7 @@ pub mod e2e_tests { let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); create_pool!( client, @@ -257,7 +266,8 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); let lower_tick_index = -10; let upper_tick_index = 10; @@ -270,7 +280,8 @@ pub mod e2e_tests { address_of!(Alice), mint_amount, alice - ); + ) + .unwrap(); mint!( client, TokenRef, @@ -278,10 +289,11 @@ pub mod e2e_tests { address_of!(Alice), mint_amount, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); + approve!(client, TokenRef, token_x, dex, mint_amount, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, mint_amount, alice).unwrap(); let liquidity_delta = Liquidity::from_integer(20_006_000); @@ -298,7 +310,8 @@ pub mod e2e_tests { pool_state.sqrt_price, pool_state.sqrt_price, alice - ); + ) + .unwrap(); let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); @@ -312,9 +325,10 @@ pub mod e2e_tests { address_of!(Bob), mint_amount, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, mint_amount, bob); + approve!(client, TokenRef, token_x, dex, mint_amount, bob).unwrap(); let dex_x_before = balance_of!(client, TokenRef, token_x, dex); let dex_y_before = balance_of!(client, TokenRef, token_y, dex); @@ -344,7 +358,8 @@ pub mod e2e_tests { true, quoted_target_sqrt_price, bob - ); + ) + .unwrap(); let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); let expected_price = calculate_sqrt_price(-10).unwrap(); @@ -398,6 +413,7 @@ pub mod e2e_tests { true, quoted_target_sqrt_price, bob - ); + ) + .unwrap(); } } diff --git a/src/tests/max_tick_cross.rs b/src/tests/max_tick_cross.rs index 207875e7..5c79ded1 100644 --- a/src/tests/max_tick_cross.rs +++ b/src/tests/max_tick_cross.rs @@ -4,10 +4,9 @@ pub mod e2e_tests { contract::ContractRef, contracts::{entrypoints::Invariant, FeeTier, PoolKey}, math::{ + log::get_tick_at_sqrt_price, types::{ - liquidity::Liquidity, - percentage::Percentage, - sqrt_price::{log::get_tick_at_sqrt_price, sqrt_price::SqrtPrice}, + liquidity::Liquidity, percentage::Percentage, sqrt_price::SqrtPrice, token_amount::TokenAmount, }, MIN_SQRT_PRICE, @@ -30,8 +29,8 @@ pub mod e2e_tests { let mint_amount = u128::MAX; let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, mint_amount, alice); - approve!(client, TokenRef, token_y, dex, mint_amount, alice); + approve!(client, TokenRef, token_x, dex, mint_amount, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, mint_amount, alice).unwrap(); let liquidity = Liquidity::from_integer(10000000); @@ -56,7 +55,8 @@ pub mod e2e_tests { slippage_limit_lower, slippage_limit_upper, alice - ); + ) + .unwrap(); } let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); @@ -64,10 +64,10 @@ pub mod e2e_tests { let amount = 760_000; let bob = ink_e2e::bob(); - mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); + mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice).unwrap(); let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); assert_eq!(amount_x, amount); - approve!(client, TokenRef, token_x, dex, amount, bob); + approve!(client, TokenRef, token_x, dex, amount, bob).unwrap(); let pool_before = get_pool!( client, @@ -118,7 +118,8 @@ pub mod e2e_tests { true, slippage, bob - ); + ) + .unwrap(); let pool_after = get_pool!( client, diff --git a/src/tests/mod.rs b/src/tests/mod.rs index b22b4ea1..1ede7b9f 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -6,7 +6,6 @@ pub mod constructor; pub mod create_pool; pub mod cross; pub mod cross_both_side; -pub mod fee_tier; pub mod limits; pub mod liquidity_gap; pub mod max_tick_cross; diff --git a/src/tests/multiple_swap.rs b/src/tests/multiple_swap.rs index 3104487e..7bea09a8 100644 --- a/src/tests/multiple_swap.rs +++ b/src/tests/multiple_swap.rs @@ -5,7 +5,7 @@ pub mod e2e_tests { contracts::{entrypoints::Invariant, get_liquidity, FeeTier, PoolKey}, math::{ types::{ - fee_growth::FeeGrowth, percentage::Percentage, sqrt_price::sqrt_price::SqrtPrice, + fee_growth::FeeGrowth, percentage::Percentage, sqrt_price::SqrtPrice, token_amount::TokenAmount, }, MAX_SQRT_PRICE, MIN_SQRT_PRICE, diff --git a/src/tests/position.rs b/src/tests/position.rs index 92a5f6c1..0f7e409b 100644 --- a/src/tests/position.rs +++ b/src/tests/position.rs @@ -6,7 +6,7 @@ pub mod e2e_tests { math::{ types::{ fee_growth::FeeGrowth, liquidity::Liquidity, percentage::Percentage, - sqrt_price::sqrt_price::SqrtPrice, token_amount::TokenAmount, + sqrt_price::SqrtPrice, token_amount::TokenAmount, }, MIN_SQRT_PRICE, }, @@ -32,7 +32,7 @@ pub mod e2e_tests { let fee_tier = FeeTier::new(Percentage::new(0), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); create_pool!( client, @@ -43,10 +43,11 @@ pub mod e2e_tests { fee_tier, 10, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, 500, alice); - approve!(client, TokenRef, token_y, dex, 500, alice); + approve!(client, TokenRef, token_x, dex, 500, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, 500, alice).unwrap(); let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); @@ -61,7 +62,8 @@ pub mod e2e_tests { SqrtPrice::new(0), SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); Ok(()) } @@ -81,7 +83,7 @@ pub mod e2e_tests { let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); create_pool!( client, @@ -92,14 +94,15 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); let lower_tick_index = -20; let upper_tick_index = 10; let liquidity_delta = Liquidity::from_integer(1_000_000); - approve!(client, TokenRef, token_x, dex, initial_mint, alice); - approve!(client, TokenRef, token_y, dex, initial_mint, alice); + approve!(client, TokenRef, token_x, dex, initial_mint, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, initial_mint, alice).unwrap(); let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); @@ -114,7 +117,8 @@ pub mod e2e_tests { pool_state.sqrt_price, pool_state.sqrt_price, alice - ); + ) + .unwrap(); let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); @@ -125,8 +129,8 @@ pub mod e2e_tests { let incorrect_lower_tick_index = lower_tick_index - 50; let incorrect_upper_tick_index = upper_tick_index + 50; - approve!(client, TokenRef, token_x, dex, liquidity_delta.get(), alice); - approve!(client, TokenRef, token_y, dex, liquidity_delta.get(), alice); + approve!(client, TokenRef, token_x, dex, liquidity_delta.get(), alice).unwrap(); + approve!(client, TokenRef, token_y, dex, liquidity_delta.get(), alice).unwrap(); create_position!( client, @@ -139,7 +143,8 @@ pub mod e2e_tests { pool_state.sqrt_price, pool_state.sqrt_price, alice - ); + ) + .unwrap(); let position_state = get_position!(client, ContractRef, dex, 1, alice).unwrap(); // Check position @@ -148,11 +153,11 @@ pub mod e2e_tests { } let amount = 1000; - mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); + mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice).unwrap(); let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); assert_eq!(amount_x, amount); - approve!(client, TokenRef, token_x, dex, amount, bob); + approve!(client, TokenRef, token_x, dex, amount, bob).unwrap(); let pool_state_before = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); @@ -169,7 +174,8 @@ pub mod e2e_tests { true, slippage, bob - ); + ) + .unwrap(); let pool_state_after = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); @@ -198,7 +204,7 @@ pub mod e2e_tests { let dex_y_before_remove = balance_of!(client, TokenRef, token_y, dex); // Remove position - remove_position!(client, ContractRef, dex, remove_position_index, alice); + remove_position!(client, ContractRef, dex, remove_position_index, alice).unwrap(); // Load states let pool_state = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); @@ -249,7 +255,7 @@ pub mod e2e_tests { let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 4).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); create_pool!( client, @@ -260,10 +266,11 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); + approve!(client, TokenRef, token_x, dex, initial_balance, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, initial_balance, alice).unwrap(); let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); let lower_tick_index = min_tick_test + 10; @@ -284,7 +291,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); // Load states let position_state = get_position!(client, ContractRef, dex, 0, alice).unwrap(); @@ -337,13 +345,13 @@ pub mod e2e_tests { let init_tick = -23028; let dex = create_dex!(client, ContractRef, Percentage::new(0)); - let initial_balance = 100_000_000_00; + let initial_balance = 10_000_000_000; let (token_x, token_y) = create_tokens!(client, TokenRef, initial_balance, initial_balance); let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 4).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); create_pool!( client, @@ -354,10 +362,11 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); + approve!(client, TokenRef, token_x, dex, initial_balance, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, initial_balance, alice).unwrap(); let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); let lower_tick_index = -46080; @@ -379,7 +388,8 @@ pub mod e2e_tests { pool_state_before.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); // Load states let position_state = get_position!(client, ContractRef, dex, 0, alice).unwrap(); @@ -439,7 +449,7 @@ pub mod e2e_tests { let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 4).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); create_pool!( client, @@ -450,10 +460,11 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); + approve!(client, TokenRef, token_x, dex, initial_balance, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, initial_balance, alice).unwrap(); let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); let lower_tick_index = -22980; @@ -473,7 +484,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); // Load states let position_state = get_position!(client, ContractRef, dex, 0, alice).unwrap(); diff --git a/src/tests/position_list.rs b/src/tests/position_list.rs index a9a69125..302f55be 100644 --- a/src/tests/position_list.rs +++ b/src/tests/position_list.rs @@ -5,7 +5,7 @@ pub mod e2e_tests { contracts::{entrypoints::Invariant, FeeTier, PoolKey}, math::types::{ fee_growth::FeeGrowth, liquidity::Liquidity, percentage::Percentage, - sqrt_price::sqrt_price::SqrtPrice, + sqrt_price::SqrtPrice, }, }; use decimal::*; @@ -30,7 +30,7 @@ pub mod e2e_tests { let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); let init_tick = -23028; @@ -43,7 +43,8 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); remove_position!(client, ContractRef, dex, 0, alice).unwrap(); } @@ -60,7 +61,7 @@ pub mod e2e_tests { let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 3).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); create_pool!( client, @@ -71,10 +72,11 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); + approve!(client, TokenRef, token_x, dex, initial_balance, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, initial_balance, alice).unwrap(); let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); let tick_indexes = [-9780, -42, 0, 9, 276, 32343, -50001]; @@ -94,7 +96,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); create_position!( client, @@ -107,7 +110,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); create_position!( client, @@ -120,7 +124,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); create_position!( client, @@ -133,7 +138,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); } // Remove middle position @@ -142,7 +148,7 @@ pub mod e2e_tests { let positions_list_before = get_all_positions!(client, ContractRef, dex, alice); let last_position = positions_list_before[positions_list_before.len() - 1]; - remove_position!(client, ContractRef, dex, position_index_to_remove, alice); + remove_position!(client, ContractRef, dex, position_index_to_remove, alice).unwrap(); let positions_list_after = get_all_positions!(client, ContractRef, dex, alice); let tested_position = positions_list_after[position_index_to_remove as usize]; @@ -184,7 +190,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); let positions_list_after = get_all_positions!(client, ContractRef, dex, alice); assert_eq!(positions_list_before.len() + 1, positions_list_after.len()); @@ -200,7 +207,8 @@ pub mod e2e_tests { dex, last_position_index_before as u32, alice - ); + ) + .unwrap(); let last_position_index_after = get_all_positions!(client, ContractRef, dex, alice).len() - 1; @@ -212,7 +220,7 @@ pub mod e2e_tests { let last_position_index = get_all_positions!(client, ContractRef, dex, alice).len(); for i in (0..last_position_index).rev() { - remove_position!(client, ContractRef, dex, i as u32, alice); + remove_position!(client, ContractRef, dex, i as u32, alice).unwrap(); } let list_length = get_all_positions!(client, ContractRef, dex, alice).len(); @@ -233,7 +241,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); let list_length_after = get_all_positions!(client, ContractRef, dex, alice).len(); assert_eq!(list_length_after, list_length_before + 1); } @@ -253,7 +262,7 @@ pub mod e2e_tests { let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 3).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); create_pool!( client, @@ -264,10 +273,11 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); + approve!(client, TokenRef, token_x, dex, initial_balance, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, initial_balance, alice).unwrap(); let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); let tick_indexes = [-9780, -42, 0, 9, 276, 32343, -50001]; @@ -287,7 +297,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); create_position!( client, @@ -300,7 +311,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); create_position!( client, @@ -313,7 +325,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); create_position!( client, @@ -326,7 +339,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); } // Remove middle position @@ -335,7 +349,7 @@ pub mod e2e_tests { let positions_list_before = get_all_positions!(client, ContractRef, dex, alice); let last_position = positions_list_before[positions_list_before.len() - 1]; - remove_position!(client, ContractRef, dex, position_index_to_remove, alice); + remove_position!(client, ContractRef, dex, position_index_to_remove, alice).unwrap(); let positions_list_after = get_all_positions!(client, ContractRef, dex, alice); let tested_position = positions_list_after[position_index_to_remove as usize]; @@ -377,7 +391,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); let positions_list_after = get_all_positions!(client, ContractRef, dex, alice); assert_eq!(positions_list_before.len() + 1, positions_list_after.len()); @@ -411,7 +426,7 @@ pub mod e2e_tests { let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 3).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); create_pool!( client, @@ -422,10 +437,11 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); + approve!(client, TokenRef, token_x, dex, initial_balance, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, initial_balance, alice).unwrap(); let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); let tick_indexes = [-9780, -42, 0, 9, 276, 32343, -50001]; @@ -443,7 +459,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); let list_length = get_all_positions!(client, ContractRef, dex, alice).len(); assert_eq!(list_length, 1) @@ -464,7 +481,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); create_position!( client, ContractRef, @@ -476,7 +494,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); create_position!( client, ContractRef, @@ -488,7 +507,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); } // Transfer first position { @@ -506,7 +526,8 @@ pub mod e2e_tests { transferred_index, bob_address, alice - ); + ) + .unwrap(); let recipient_position = get_position!(client, ContractRef, dex, transferred_index, bob).unwrap(); @@ -539,7 +560,8 @@ pub mod e2e_tests { transferred_index, bob_address, alice - ); + ) + .unwrap(); let owner_list_after = get_all_positions!(client, ContractRef, dex, alice); let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); @@ -566,7 +588,8 @@ pub mod e2e_tests { transferred_index, bob_address, alice - ); + ) + .unwrap(); let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); let recipient_position_index = (recipient_list_after.len() - 1) as u32; @@ -590,7 +613,8 @@ pub mod e2e_tests { transferred_index, bob_address, alice - ); + ) + .unwrap(); let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); let recipient_position_index = (recipient_list_after.len() - 1) as u32; @@ -621,7 +645,8 @@ pub mod e2e_tests { transferred_index, address_of!(Alice), bob - ); + ) + .unwrap(); let owner_list_after = get_all_positions!(client, ContractRef, dex, alice); let recipient_list_after = get_all_positions!(client, ContractRef, dex, bob); @@ -657,7 +682,7 @@ pub mod e2e_tests { let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 3).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); create_pool!( client, @@ -668,10 +693,11 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); + approve!(client, TokenRef, token_x, dex, initial_balance, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, initial_balance, alice).unwrap(); let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); let tick_indexes = [-9780, -42, 0, 9, 276, 32343, -50001]; @@ -689,7 +715,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); let list_length = get_all_positions!(client, ContractRef, dex, alice).len(); assert_eq!(list_length, 1) @@ -709,7 +736,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); create_position!( client, ContractRef, @@ -721,7 +749,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); create_position!( client, ContractRef, @@ -733,7 +762,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); } // Transfer first position { @@ -763,7 +793,7 @@ pub mod e2e_tests { let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 10).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); create_pool!( client, @@ -774,10 +804,11 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, initial_balance, alice); - approve!(client, TokenRef, token_y, dex, initial_balance, alice); + approve!(client, TokenRef, token_x, dex, initial_balance, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, initial_balance, alice).unwrap(); let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); // Three position on same lower and upper tick @@ -801,7 +832,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); let first_position = get_position!(client, ContractRef, dex, 0, alice).unwrap(); @@ -816,7 +848,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); let second_position = get_position!(client, ContractRef, dex, 1, alice).unwrap(); @@ -831,7 +864,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); let third_position = get_position!(client, ContractRef, dex, 2, alice).unwrap(); @@ -909,7 +943,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); let first_position = get_position!(client, ContractRef, dex, 3, alice).unwrap(); @@ -935,7 +970,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); let second_position = get_position!(client, ContractRef, dex, 4, alice).unwrap(); @@ -960,7 +996,8 @@ pub mod e2e_tests { pool_state.sqrt_price, SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); let third_position = get_position!(client, ContractRef, dex, 5, alice).unwrap(); diff --git a/src/tests/position_slippage.rs b/src/tests/position_slippage.rs index f6a61362..a2789c52 100644 --- a/src/tests/position_slippage.rs +++ b/src/tests/position_slippage.rs @@ -3,9 +3,7 @@ pub mod e2e_tests { use crate::{ contract::ContractRef, contracts::{entrypoints::Invariant, FeeTier, PoolKey}, - math::types::{ - liquidity::Liquidity, percentage::Percentage, sqrt_price::sqrt_price::SqrtPrice, - }, + math::types::{liquidity::Liquidity, percentage::Percentage, sqrt_price::SqrtPrice}, }; use decimal::*; use ink_e2e::build_message; @@ -58,7 +56,8 @@ pub mod e2e_tests { known_price, known_price, alice - ); + ) + .unwrap(); } // inside range { @@ -79,7 +78,8 @@ pub mod e2e_tests { limit_lower, limit_upper, alice - ); + ) + .unwrap(); } Ok(()) diff --git a/src/tests/protocol_fee.rs b/src/tests/protocol_fee.rs index ce8673c0..738f7e48 100644 --- a/src/tests/protocol_fee.rs +++ b/src/tests/protocol_fee.rs @@ -6,7 +6,7 @@ pub mod e2e_tests { math::{ types::{ fee_growth::FeeGrowth, liquidity::Liquidity, percentage::Percentage, - sqrt_price::sqrt_price::SqrtPrice, token_amount::TokenAmount, + sqrt_price::SqrtPrice, token_amount::TokenAmount, }, MIN_SQRT_PRICE, }, @@ -32,7 +32,7 @@ pub mod e2e_tests { let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); let alice = ink_e2e::alice(); - withdraw_protocol_fee!(client, ContractRef, dex, pool_key, alice); + withdraw_protocol_fee!(client, ContractRef, dex, pool_key, alice).unwrap(); let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Alice)); let amount_y = balance_of!(client, TokenRef, token_y, address_of!(Alice)); @@ -75,6 +75,6 @@ pub mod e2e_tests { ) .unwrap(); let bob = ink_e2e::bob(); - withdraw_protocol_fee!(client, ContractRef, dex, pool_key, bob); + withdraw_protocol_fee!(client, ContractRef, dex, pool_key, bob).unwrap(); } } diff --git a/src/tests/remove_fee_tier.rs b/src/tests/remove_fee_tier.rs index 7e3e9f94..d17c45e2 100644 --- a/src/tests/remove_fee_tier.rs +++ b/src/tests/remove_fee_tier.rs @@ -17,12 +17,12 @@ pub mod e2e_tests { let dex = create_dex!(client, ContractRef, Percentage::new(0)); let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); - remove_fee_tier!(client, ContractRef, dex, fee_tier, admin); + remove_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); let exist = fee_tier_exist!( client, ContractRef, @@ -41,7 +41,7 @@ pub mod e2e_tests { let dex = create_dex!(client, ContractRef, Percentage::new(0)); let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap(); remove_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); @@ -55,10 +55,10 @@ pub mod e2e_tests { let dex = create_dex!(client, ContractRef, Percentage::new(0)); let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); let fee_tier = FeeTier::new(Percentage::from_scale(2, 4), 2).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, admin); + add_fee_tier!(client, ContractRef, dex, fee_tier, admin).unwrap(); remove_fee_tier!(client, ContractRef, dex, fee_tier, user).unwrap(); } diff --git a/src/tests/slippage.rs b/src/tests/slippage.rs index b1cbc8e8..e5da65c7 100644 --- a/src/tests/slippage.rs +++ b/src/tests/slippage.rs @@ -7,7 +7,7 @@ pub mod e2e_tests { types::{ liquidity::Liquidity, percentage::Percentage, - sqrt_price::sqrt_price::{calculate_sqrt_price, SqrtPrice}, + sqrt_price::{calculate_sqrt_price, SqrtPrice}, token_amount::TokenAmount, }, MAX_SQRT_PRICE, MIN_SQRT_PRICE, @@ -39,7 +39,7 @@ pub mod e2e_tests { ); let amount = 10u128.pow(8); let swap_amount = TokenAmount::new(amount); - approve!(client, TokenRef, token_x, dex, amount, alice); + approve!(client, TokenRef, token_x, dex, amount, alice).unwrap(); let target_sqrt_price = SqrtPrice::new(1009940000000000000000001); swap!( @@ -52,7 +52,8 @@ pub mod e2e_tests { true, target_sqrt_price, alice - ); + ) + .unwrap(); let expected_sqrt_price = SqrtPrice::new(1009940000000000000000000); let pool = get_pool!( client, @@ -83,7 +84,7 @@ pub mod e2e_tests { ); let amount = 10u128.pow(8); let swap_amount = TokenAmount::new(amount); - approve!(client, TokenRef, token_x, dex, amount, alice); + approve!(client, TokenRef, token_x, dex, amount, alice).unwrap(); let target_sqrt_price = calculate_sqrt_price(-98).unwrap(); swap!( @@ -113,10 +114,10 @@ pub mod e2e_tests { let amount = 1000; let bob = ink_e2e::bob(); let alice = ink_e2e::alice(); - mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); + mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice).unwrap(); let amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); assert_eq!(amount_x, amount); - approve!(client, TokenRef, token_x, dex, amount, bob); + approve!(client, TokenRef, token_x, dex, amount, bob).unwrap(); let swap_amount = TokenAmount::new(amount); swap_exact_limit!( diff --git a/src/tests/swap.rs b/src/tests/swap.rs index a41fd89e..38b8138a 100644 --- a/src/tests/swap.rs +++ b/src/tests/swap.rs @@ -6,7 +6,7 @@ pub mod e2e_tests { math::{ types::{ fee_growth::FeeGrowth, liquidity::Liquidity, percentage::Percentage, - sqrt_price::sqrt_price::SqrtPrice, token_amount::TokenAmount, + sqrt_price::SqrtPrice, token_amount::TokenAmount, }, MAX_SQRT_PRICE, MIN_SQRT_PRICE, }, @@ -41,7 +41,7 @@ pub mod e2e_tests { let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); create_pool!( client, @@ -52,10 +52,11 @@ pub mod e2e_tests { fee_tier, 0, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, initial_amount, alice); - approve!(client, TokenRef, token_y, dex, initial_amount, alice); + approve!(client, TokenRef, token_x, dex, initial_amount, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, initial_amount, alice).unwrap(); let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); @@ -76,7 +77,8 @@ pub mod e2e_tests { SqrtPrice::new(0), SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); create_position!( client, @@ -89,7 +91,8 @@ pub mod e2e_tests { SqrtPrice::new(0), SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); @@ -98,8 +101,8 @@ pub mod e2e_tests { let amount = 1000; let swap_amount = TokenAmount(amount); let bob = ink_e2e::bob(); - mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); - approve!(client, TokenRef, token_x, dex, amount, bob); + mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice).unwrap(); + approve!(client, TokenRef, token_x, dex, amount, bob).unwrap(); let slippage = SqrtPrice::new(MIN_SQRT_PRICE); let target_sqrt_price = quote!( @@ -128,7 +131,8 @@ pub mod e2e_tests { true, target_sqrt_price, bob - ); + ) + .unwrap(); // Load states let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); @@ -192,7 +196,7 @@ pub mod e2e_tests { let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 10).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); create_pool!( client, @@ -203,10 +207,11 @@ pub mod e2e_tests { fee_tier, 0, alice - ); + ) + .unwrap(); - approve!(client, TokenRef, token_x, dex, initial_amount, alice); - approve!(client, TokenRef, token_y, dex, initial_amount, alice); + approve!(client, TokenRef, token_x, dex, initial_amount, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, initial_amount, alice).unwrap(); let pool_key = PoolKey::new(token_x, token_y, fee_tier).unwrap(); @@ -227,7 +232,8 @@ pub mod e2e_tests { SqrtPrice::new(0), SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); create_position!( client, @@ -240,7 +246,8 @@ pub mod e2e_tests { SqrtPrice::new(0), SqrtPrice::max_instance(), alice - ); + ) + .unwrap(); let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); @@ -249,8 +256,8 @@ pub mod e2e_tests { let amount = 1000; let swap_amount = TokenAmount(amount); let bob = ink_e2e::bob(); - mint!(client, TokenRef, token_y, address_of!(Bob), amount, alice); - approve!(client, TokenRef, token_y, dex, amount, bob); + mint!(client, TokenRef, token_y, address_of!(Bob), amount, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, amount, bob).unwrap(); let target_sqrt_price = SqrtPrice::new(MAX_SQRT_PRICE); @@ -280,7 +287,8 @@ pub mod e2e_tests { true, target_sqrt_price, bob - ); + ) + .unwrap(); // Load states let pool = get_pool!(client, ContractRef, dex, token_x, token_y, fee_tier).unwrap(); diff --git a/src/tests/swap_route.rs b/src/tests/swap_route.rs index ce588232..abaabe02 100644 --- a/src/tests/swap_route.rs +++ b/src/tests/swap_route.rs @@ -22,19 +22,19 @@ pub mod e2e_tests { init_dex_and_3_tokens!(client, ContractRef, TokenRef); let alice = ink_e2e::alice(); - approve!(client, TokenRef, token_x, dex, u64::MAX as u128, alice); - approve!(client, TokenRef, token_y, dex, u64::MAX as u128, alice); - approve!(client, TokenRef, token_z, dex, u64::MAX as u128, alice); + approve!(client, TokenRef, token_x, dex, u64::MAX as u128, alice).unwrap(); + approve!(client, TokenRef, token_y, dex, u64::MAX as u128, alice).unwrap(); + approve!(client, TokenRef, token_z, dex, u64::MAX as u128, alice).unwrap(); let amount = 1000; let bob = ink_e2e::bob(); - mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice); - approve!(client, TokenRef, token_x, dex, amount, bob); - approve!(client, TokenRef, token_y, dex, u64::MAX as u128, bob); + mint!(client, TokenRef, token_x, address_of!(Bob), amount, alice).unwrap(); + approve!(client, TokenRef, token_x, dex, amount, bob).unwrap(); + approve!(client, TokenRef, token_y, dex, u64::MAX as u128, bob).unwrap(); let fee_tier = FeeTier::new(Percentage::from_scale(6, 3), 1).unwrap(); - add_fee_tier!(client, ContractRef, dex, fee_tier, alice); + add_fee_tier!(client, ContractRef, dex, fee_tier, alice).unwrap(); let init_tick = 0; create_pool!( @@ -46,7 +46,8 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); let init_tick = 0; create_pool!( @@ -58,7 +59,8 @@ pub mod e2e_tests { fee_tier, init_tick, alice - ); + ) + .unwrap(); let pool_key_1 = PoolKey::new(token_x, token_y, fee_tier).unwrap(); let pool_key_2 = PoolKey::new(token_y, token_z, fee_tier).unwrap(); @@ -79,7 +81,8 @@ pub mod e2e_tests { slippage_limit_lower, slippage_limit_upper, alice - ); + ) + .unwrap(); let pool_2 = get_pool!(client, ContractRef, dex, token_y, token_z, fee_tier).unwrap(); let slippage_limit_lower = pool_2.sqrt_price; @@ -95,7 +98,8 @@ pub mod e2e_tests { slippage_limit_lower, slippage_limit_upper, alice - ); + ) + .unwrap(); let amount_in = TokenAmount(1000); let slippage = Percentage::new(0); @@ -122,7 +126,8 @@ pub mod e2e_tests { slippage, swaps.clone(), bob - ); + ) + .unwrap(); let bob_amount_x = balance_of!(client, TokenRef, token_x, address_of!(Bob)); let bob_amount_y = balance_of!(client, TokenRef, token_y, address_of!(Bob)); @@ -144,8 +149,8 @@ pub mod e2e_tests { let alice_amount_y_before = balance_of!(client, TokenRef, token_y, address_of!(Alice)); let alice_amount_z_before = balance_of!(client, TokenRef, token_z, address_of!(Alice)); - claim_fee!(client, ContractRef, dex, 0, alice); - claim_fee!(client, ContractRef, dex, 1, alice); + claim_fee!(client, ContractRef, dex, 0, alice).unwrap(); + claim_fee!(client, ContractRef, dex, 1, alice).unwrap(); let alice_amount_x_after = balance_of!(client, TokenRef, token_x, address_of!(Alice)); let alice_amount_y_after = balance_of!(client, TokenRef, token_y, address_of!(Alice));