From 92e783a44d8040ecdea0390fada51f67d5027251 Mon Sep 17 00:00:00 2001 From: esteblock Date: Tue, 16 Jul 2024 18:04:41 +0700 Subject: [PATCH 01/11] add comments --- contracts/adapters/phoenix/src/lib.rs | 34 ++++++++++++----- .../phoenix/src/protocol_interface.rs | 37 +++++++++++++++---- 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/contracts/adapters/phoenix/src/lib.rs b/contracts/adapters/phoenix/src/lib.rs index d8a6843b..59fa7f18 100644 --- a/contracts/adapters/phoenix/src/lib.rs +++ b/contracts/adapters/phoenix/src/lib.rs @@ -1,23 +1,26 @@ #![no_std] use soroban_sdk::{contract, contractimpl, Address, Env, Vec, String}; - mod event; mod storage; mod protocol_interface; mod test; use storage::{ - extend_instance_ttl, - set_initialized, - is_initialized, + extend_instance_ttl, + set_initialized, + is_initialized, set_protocol_id, get_protocol_id, - set_protocol_address, - get_protocol_address, + set_protocol_address, + get_protocol_address, +}; +use soroswap_aggregator_adapter_interface::{ + SoroswapAggregatorAdapterTrait, AdapterError +}; +use protocol_interface::{ + protocol_swap_exact_tokens_for_tokens, + protocol_swap_tokens_for_exact_tokens }; -use soroswap_aggregator_adapter_interface::{SoroswapAggregatorAdapterTrait, AdapterError}; -use protocol_interface::{protocol_swap_exact_tokens_for_tokens, - protocol_swap_tokens_for_exact_tokens}; pub fn check_nonnegative_amount(amount: i128) -> Result<(), AdapterError> { if amount < 0 { @@ -49,7 +52,18 @@ struct SoroswapAggregatorPhoenixAdapter; #[contractimpl] impl SoroswapAggregatorAdapterTrait for SoroswapAggregatorPhoenixAdapter { - /// Initializes the contract and sets the phoenix multihop address + + /// Initializes the contract and sets the Phoenix multihop address. + /// + /// # Arguments + /// + /// * `e` - The contract environment. + /// * `protocol_id` - The identifier for the protocol. + /// * `protocol_address` - The address associated with the protocol. + /// + /// # Errors + /// + /// Returns an error if the contract is already initialized (`AdapterError::AlreadyInitialized`). fn initialize( e: Env, protocol_id: String, diff --git a/contracts/adapters/phoenix/src/protocol_interface.rs b/contracts/adapters/phoenix/src/protocol_interface.rs index 64219ee7..f4fdf571 100644 --- a/contracts/adapters/phoenix/src/protocol_interface.rs +++ b/contracts/adapters/phoenix/src/protocol_interface.rs @@ -9,18 +9,34 @@ soroban_sdk::contractimport!( ); pub type PhoenixMultihopClient<'a> = Client<'a>; -fn convert_to_swaps(e: &Env, addresses: &Vec
) -> Vec { +fn convert_to_swaps(e: &Env, path: &Vec
) -> Vec { let mut swaps = Vec::new(e); - // Iterate through the addresses, creating a Swap for each pair - // Skip the last address since it cannot be an offer_asset without a corresponding ask_asset + // Iterate through the addresses in the path, creating a Swap object for each pair + // If path is [token0, token1, token2, token3], swaps should be + // swap_0 = Swap{ + // offer_asset: token0, + // ask_asset: token1, + // ask_asset_min_amount: None, + // }, + // swap_1 = Swap{ + // offer_asset: token1, + // ask_asset: token2, + // ask_asset_min_amount: None, + // }, + // swap_2 = Swap{ + // offer_asset: token2, + // ask_asset: token3, + // ask_asset_min_amount: None, + // } + for i in 0..(addresses.len() - 1) { let offer_asset = addresses.get(i).expect("Failed to get offer asset"); - let ask_asset = addresses.get(i + 1).expect("Failed to get ask asset"); + let ask_asset = addresses.get(i + 1).expect("Failed to get ask a sset"); swaps.push_back(Swap { - ask_asset: ask_asset.clone(), - offer_asset: offer_asset.clone(), + offer_asset: offer_asset.clone(), // asset being sold (token_in) + ask_asset: ask_asset.clone(), // asset buying (token_out) ask_asset_min_amount: None, }); } @@ -42,8 +58,13 @@ pub fn protocol_swap_exact_tokens_for_tokens( let phoenix_multihop_client = PhoenixMultihopClient::new(&e, &phoenix_multihop_address); let operations = convert_to_swaps(e, path); - // TODO: CHECK AND TEST - phoenix_multihop_client.swap(&to, &operations, &None, &amount_in); + // By using max_spread_bps = None, the Phoenix LP will use the maximum allowed slippage + // amount_in is the amount being sold of the first token in the operations. + phoenix_multihop_client.swap( + &to, // recipient: Address, + &operations, // operations: Vec, + &None, // max_spread_bps: Option. + &amount_in); //amout: i128. Amount being sold. Input from the user, // Returning empty array (should check phoenix response if it return amounts, apparently it doesnt) Ok(vec![&e]) From e0054c6861638f03f0a36648285273dd3d2f35eb Mon Sep 17 00:00:00 2001 From: esteblock Date: Tue, 16 Jul 2024 18:44:22 +0700 Subject: [PATCH 02/11] ask for reverse quote in Phoenix --- .../phoenix/src/protocol_interface.rs | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/contracts/adapters/phoenix/src/protocol_interface.rs b/contracts/adapters/phoenix/src/protocol_interface.rs index f4fdf571..f92090b4 100644 --- a/contracts/adapters/phoenix/src/protocol_interface.rs +++ b/contracts/adapters/phoenix/src/protocol_interface.rs @@ -30,9 +30,9 @@ fn convert_to_swaps(e: &Env, path: &Vec
) -> Vec { // ask_asset_min_amount: None, // } - for i in 0..(addresses.len() - 1) { - let offer_asset = addresses.get(i).expect("Failed to get offer asset"); - let ask_asset = addresses.get(i + 1).expect("Failed to get ask a sset"); + for i in 0..(path.len() - 1) { + let offer_asset = path.get(i).expect("Failed to get offer asset"); + let ask_asset = path.get(i + 1).expect("Failed to get ask a sset"); swaps.push_back(Swap { offer_asset: offer_asset.clone(), // asset being sold (token_in) @@ -44,7 +44,6 @@ fn convert_to_swaps(e: &Env, path: &Vec
) -> Vec { swaps } - pub fn protocol_swap_exact_tokens_for_tokens( e: &Env, amount_in: &i128, @@ -83,8 +82,39 @@ pub fn protocol_swap_tokens_for_exact_tokens( let phoenix_multihop_client = PhoenixMultihopClient::new(&e, &phoenix_multihop_address); let operations = convert_to_swaps(e, path); - // TODO: CHECK AND TEST - phoenix_multihop_client.swap(&to, &operations, &None, &amount_in_max); + // We first need to get the "reverse_amount from phoenix.simulate_reverse_swap" + // however here, if the path is [t0, t1, t2, t3, t4], the operations should be + // swap_0 = Swap{ + // offer_asset: t3, + // ask_asset: t4, + // ask_asset_min_amount: None, + // }, + // swap_1 = Swap{ + // offer_asset: t2, + // ask_asset: t3, + // ask_asset_min_amount: None, + // }, + // swap_2 = Swap{ + // offer_asset: t1, + // ask_asset: t2, + // ask_asset_min_amount: None, + // }, + // swap_3 = Swap{ + // offer_asset: t0, + // ask_asset: t1, + // ask_asset_min_amount: None, + // } + + let revert_operations = convert_to_revert_swaps(e, path); + let reverse_simulated_swap = phoenix_multihop_client.simulate_reverse_swap( + operations.rev(), //operations: Vec, + amount_out); //amount: i128, + + phoenix_multihop_client.swap( + &to, // recipient: Address, + &operations, // operations: Vec, + &None, // max_spread_bps: Option. + &reverse_simulated_swap.offer_amount); //amout: i128. Amount being sold. Input from the user, // Returning empty array (should check phoenix response if it return amounts, apparently it doesnt) Ok(vec![&e]) From a7a244e61defb8351b76311404dab417055c3d83 Mon Sep 17 00:00:00 2001 From: esteblock Date: Wed, 17 Jul 2024 23:08:36 +0700 Subject: [PATCH 03/11] Comments --- .../phoenix/src/protocol_interface.rs | 19 +++++++++++++++++-- protocols/phoenix | 1 - protocols/soroswap | 1 - 3 files changed, 17 insertions(+), 4 deletions(-) delete mode 160000 protocols/phoenix delete mode 160000 protocols/soroswap diff --git a/contracts/adapters/phoenix/src/protocol_interface.rs b/contracts/adapters/phoenix/src/protocol_interface.rs index f92090b4..7efd4f99 100644 --- a/contracts/adapters/phoenix/src/protocol_interface.rs +++ b/contracts/adapters/phoenix/src/protocol_interface.rs @@ -66,6 +66,15 @@ pub fn protocol_swap_exact_tokens_for_tokens( &amount_in); //amout: i128. Amount being sold. Input from the user, // Returning empty array (should check phoenix response if it return amounts, apparently it doesnt) + // We dont know the amount of the output token, unless we do an extra cross contract call to the token contract + // In order to avoid extra calls, we are returning an empty array + + //To be more exact, this adapter should do the cross contract call and check for amount_out_min... + // But in order to calculate the exact amount_out we should do 2 cross_contract calls to the token contract, + // one before and one after.... + + // Because our Aggregator contract checks for everything, we wont add this here. + // Can we do Benchmark studies to see the amount of extra operations/fees that this incurrs? Ok(vec![&e]) } @@ -105,10 +114,15 @@ pub fn protocol_swap_tokens_for_exact_tokens( // ask_asset_min_amount: None, // } - let revert_operations = convert_to_revert_swaps(e, path); + // This is the same of operations.rev() + let reverse_simulated_swap = phoenix_multihop_client.simulate_reverse_swap( operations.rev(), //operations: Vec, amount_out); //amount: i128, + + if reverse_simulated_swap.offer_amount > amount_in_max { + // TODO: Here we should have a new Error object + } phoenix_multihop_client.swap( &to, // recipient: Address, @@ -116,6 +130,7 @@ pub fn protocol_swap_tokens_for_exact_tokens( &None, // max_spread_bps: Option. &reverse_simulated_swap.offer_amount); //amout: i128. Amount being sold. Input from the user, - // Returning empty array (should check phoenix response if it return amounts, apparently it doesnt) + // Here we are not 100% sure if the amount_in will be exactely reverse_simulated_swap.offer_amount + // and if the amount_out will be indeed amount_out Ok(vec![&e]) } \ No newline at end of file diff --git a/protocols/phoenix b/protocols/phoenix deleted file mode 160000 index 36e24211..00000000 --- a/protocols/phoenix +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 36e24211c4c5e2ba485c7a80dc18a553fc98671a diff --git a/protocols/soroswap b/protocols/soroswap deleted file mode 160000 index c9e046ae..00000000 --- a/protocols/soroswap +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c9e046aebfcb0549104ee46e9d0be480ab08ebd7 From 4d0a5fa8e773ef78b1605c54e40bb12f432dbce1 Mon Sep 17 00:00:00 2001 From: esteblock Date: Thu, 18 Jul 2024 17:36:36 +0200 Subject: [PATCH 04/11] set phoenix swap functions --- .../phoenix/src/protocol_interface.rs | 66 ++++++++++++------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/contracts/adapters/phoenix/src/protocol_interface.rs b/contracts/adapters/phoenix/src/protocol_interface.rs index 7efd4f99..b9c3c074 100644 --- a/contracts/adapters/phoenix/src/protocol_interface.rs +++ b/contracts/adapters/phoenix/src/protocol_interface.rs @@ -1,6 +1,6 @@ // based on https://github.com/Phoenix-Protocol-Group/phoenix_contracts/tree/v1.0.0 -use soroban_sdk::{Env, Address, Vec, vec}; +use soroban_sdk::{Env, Address, Vec, token::Client as TokenClient}; use crate::storage::{get_protocol_address}; use soroswap_aggregator_adapter_interface::{AdapterError}; @@ -50,13 +50,18 @@ pub fn protocol_swap_exact_tokens_for_tokens( amount_out_min: &i128, path: &Vec
, to: &Address, - deadline: &u64, + _deadline: &u64, ) -> Result, AdapterError> { let phoenix_multihop_address = get_protocol_address(&e)?; let phoenix_multihop_client = PhoenixMultihopClient::new(&e, &phoenix_multihop_address); let operations = convert_to_swaps(e, path); - + + // TODO: Remove this checks if we want to reduce the number of total instructions + // TODO: Do benchmarking + let token_out_address = path.get(path.len() - 1).expect("Failed to get token out address"); + let initial_token_out_balance = TokenClient::new(&e, &token_out_address).balance(&to); + // By using max_spread_bps = None, the Phoenix LP will use the maximum allowed slippage // amount_in is the amount being sold of the first token in the operations. phoenix_multihop_client.swap( @@ -64,18 +69,23 @@ pub fn protocol_swap_exact_tokens_for_tokens( &operations, // operations: Vec, &None, // max_spread_bps: Option. &amount_in); //amout: i128. Amount being sold. Input from the user, - - // Returning empty array (should check phoenix response if it return amounts, apparently it doesnt) - // We dont know the amount of the output token, unless we do an extra cross contract call to the token contract - // In order to avoid extra calls, we are returning an empty array - - //To be more exact, this adapter should do the cross contract call and check for amount_out_min... - // But in order to calculate the exact amount_out we should do 2 cross_contract calls to the token contract, - // one before and one after.... - - // Because our Aggregator contract checks for everything, we wont add this here. - // Can we do Benchmark studies to see the amount of extra operations/fees that this incurrs? - Ok(vec![&e]) + + let final_token_out_balance = TokenClient::new(&e, &token_out_address).balance(&to); + + // check if the amount of token_out received is greater than the minimum amount expected + // TODO: Remove this checks if we want to reduce the number of total instructions + // TODO: Do benchmarking + let final_amount_out = final_token_out_balance.checked_sub(initial_token_out_balance).unwrap(); + if final_amount_out < *amount_out_min { + // panic + panic!("Amount of token out received is less than the minimum amount expected"); + } + + let mut swap_amounts: Vec = Vec::new(e); + swap_amounts.push_back(amount_in.clone()); + swap_amounts.push_back(final_amount_out); + + Ok(swap_amounts) } pub fn protocol_swap_tokens_for_exact_tokens( @@ -84,7 +94,7 @@ pub fn protocol_swap_tokens_for_exact_tokens( amount_in_max: &i128, path: &Vec
, to: &Address, - deadline: &u64, + _deadline: &u64, ) -> Result, AdapterError> { let phoenix_multihop_address = get_protocol_address(&e)?; @@ -114,14 +124,19 @@ pub fn protocol_swap_tokens_for_exact_tokens( // ask_asset_min_amount: None, // } - // This is the same of operations.rev() - + let mut operations_reversed = soroban_sdk::Vec::new(&e); + for op in operations.iter().rev() { + operations_reversed.push_back(op.clone()); + } let reverse_simulated_swap = phoenix_multihop_client.simulate_reverse_swap( - operations.rev(), //operations: Vec, + &operations_reversed, //operations: Vec, amount_out); //amount: i128, - if reverse_simulated_swap.offer_amount > amount_in_max { - // TODO: Here we should have a new Error object + // TODO: Eliminate this check. The overall in max is checked by the Aggregator + // Removing this check will reduce the amount of instructions/ + // TODO: Do Benchmarking + if reverse_simulated_swap.offer_amount > *amount_in_max { + panic!("Amount of token in required is greater than the maximum amount expected"); } phoenix_multihop_client.swap( @@ -130,7 +145,10 @@ pub fn protocol_swap_tokens_for_exact_tokens( &None, // max_spread_bps: Option. &reverse_simulated_swap.offer_amount); //amout: i128. Amount being sold. Input from the user, - // Here we are not 100% sure if the amount_in will be exactely reverse_simulated_swap.offer_amount - // and if the amount_out will be indeed amount_out - Ok(vec![&e]) + // Here we trust in the amounts returned by Phoenix contracts + let mut swap_amounts: Vec = Vec::new(e); + swap_amounts.push_back(reverse_simulated_swap.offer_amount); + swap_amounts.push_back(*amount_out); + + Ok(swap_amounts) } \ No newline at end of file From d41ec750c81a51b39dd1609a1a6c5329dc0b7357 Mon Sep 17 00:00:00 2001 From: esteblock Date: Thu, 18 Jul 2024 17:38:52 +0200 Subject: [PATCH 05/11] remove warnings --- contracts/adapters/phoenix/src/test.rs | 4 +- .../phoenix/src/test/phoenix_setup.rs | 38 +++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/contracts/adapters/phoenix/src/test.rs b/contracts/adapters/phoenix/src/test.rs index c6ffb572..08524172 100644 --- a/contracts/adapters/phoenix/src/test.rs +++ b/contracts/adapters/phoenix/src/test.rs @@ -26,7 +26,7 @@ pub struct PhoenixAggregatorAdapterTest<'a> { token_2: TokenClient<'a>, token_3: TokenClient<'a>, user: Address, - admin: Address + // admin: Address } impl<'a> PhoenixAggregatorAdapterTest<'a> { @@ -44,7 +44,7 @@ impl<'a> PhoenixAggregatorAdapterTest<'a> { token_2: test.token_2, token_3: test.token_3, user: test.user, - admin: test.admin + // admin: test.admin } } } diff --git a/contracts/adapters/phoenix/src/test/phoenix_setup.rs b/contracts/adapters/phoenix/src/test/phoenix_setup.rs index 58e302a6..5c4be5f6 100644 --- a/contracts/adapters/phoenix/src/test/phoenix_setup.rs +++ b/contracts/adapters/phoenix/src/test/phoenix_setup.rs @@ -2,7 +2,7 @@ // extern crate std; use soroban_sdk::{ vec, - IntoVal, + // IntoVal, String, Env, Bytes, @@ -72,20 +72,20 @@ pub mod token_contract { pub use token_contract::Client as TokenClient; -pub fn create_token_contract_with_metadata<'a>( - env: &Env, - admin: &Address, - decimals: u32, - name: String, - symbol: String, - amount: i128, -) -> TokenClient<'a> { - let token = - TokenClient::new(env, &env.register_contract_wasm(None, token_contract::WASM)); - token.initialize(admin, &decimals, &name.into_val(env), &symbol.into_val(env)); - token.mint(admin, &amount); - token -} +// pub fn create_token_contract_with_metadata<'a>( +// env: &Env, +// admin: &Address, +// decimals: u32, +// name: String, +// symbol: String, +// amount: i128, +// ) -> TokenClient<'a> { +// let token = +// TokenClient::new(env, &env.register_contract_wasm(None, token_contract::WASM)); +// token.initialize(admin, &decimals, &name.into_val(env), &symbol.into_val(env)); +// token.mint(admin, &amount); +// token +// } pub fn install_token_wasm(env: &Env) -> BytesN<32> { soroban_sdk::contractimport!( @@ -219,13 +219,13 @@ pub fn deploy_and_initialize_lp( pub struct PhoenixTest<'a> { pub env: Env, pub multihop_client: MultihopClient<'a>, - pub factory_client: PhoenixFactory<'a>, + // pub factory_client: PhoenixFactory<'a>, pub token_0: TokenClient<'a>, pub token_1: TokenClient<'a>, pub token_2: TokenClient<'a>, pub token_3: TokenClient<'a>, pub user: Address, - pub admin: Address + // pub admin: Address } impl<'a> PhoenixTest<'a> { @@ -292,13 +292,13 @@ impl<'a> PhoenixTest<'a> { PhoenixTest { env: env.clone(), multihop_client, - factory_client, + // factory_client, token_0, token_1, token_2, token_3, user, - admin: admin.clone() + // admin: admin.clone() } } } \ No newline at end of file From e6e23a5cc9a9791ee64d4d3d3d7d59c10c74d1bb Mon Sep 17 00:00:00 2001 From: esteblock Date: Thu, 18 Jul 2024 19:37:18 +0200 Subject: [PATCH 06/11] add tests for Phoenix swap_exact_tokens_for_tokens --- .../phoenix/src/protocol_interface.rs | 20 +- contracts/adapters/phoenix/src/test.rs | 10 +- .../phoenix/src/test/phoenix_setup.rs | 14 +- .../src/test/swap_exact_tokens_for_tokens.rs | 151 +++++++--- .../src/test/swap_tokens_for_exact_tokens.rs | 259 ++++++------------ 5 files changed, 213 insertions(+), 241 deletions(-) diff --git a/contracts/adapters/phoenix/src/protocol_interface.rs b/contracts/adapters/phoenix/src/protocol_interface.rs index b9c3c074..5fa6e0a2 100644 --- a/contracts/adapters/phoenix/src/protocol_interface.rs +++ b/contracts/adapters/phoenix/src/protocol_interface.rs @@ -70,16 +70,16 @@ pub fn protocol_swap_exact_tokens_for_tokens( &None, // max_spread_bps: Option. &amount_in); //amout: i128. Amount being sold. Input from the user, - let final_token_out_balance = TokenClient::new(&e, &token_out_address).balance(&to); - - // check if the amount of token_out received is greater than the minimum amount expected - // TODO: Remove this checks if we want to reduce the number of total instructions - // TODO: Do benchmarking - let final_amount_out = final_token_out_balance.checked_sub(initial_token_out_balance).unwrap(); - if final_amount_out < *amount_out_min { - // panic - panic!("Amount of token out received is less than the minimum amount expected"); - } + let final_token_out_balance = TokenClient::new(&e, &token_out_address).balance(&to); + + // check if the amount of token_out received is greater than the minimum amount expected + // TODO: Remove this checks if we want to reduce the number of total instructions + // TODO: Do benchmarking + let final_amount_out = final_token_out_balance.checked_sub(initial_token_out_balance).unwrap(); + if final_amount_out < *amount_out_min { + // panic + panic!("Amount of token out received is less than the minimum amount expected"); + } let mut swap_amounts: Vec = Vec::new(e); swap_amounts.push_back(amount_in.clone()); diff --git a/contracts/adapters/phoenix/src/test.rs b/contracts/adapters/phoenix/src/test.rs index 08524172..c7ba535a 100644 --- a/contracts/adapters/phoenix/src/test.rs +++ b/contracts/adapters/phoenix/src/test.rs @@ -8,7 +8,7 @@ use soroban_sdk::{ }; use crate::{SoroswapAggregatorPhoenixAdapter, SoroswapAggregatorPhoenixAdapterClient}; -use phoenix_setup::{PhoenixTest, MultihopClient, TokenClient}; +use phoenix_setup::{PhoenixTest, MultihopClient, TokenClient, PhoenixFactory}; // use factory::SoroswapFactoryClient; // use router::SoroswapRouterClient; @@ -20,13 +20,14 @@ fn create_soroswap_aggregator_adapter<'a>(e: &Env) -> SoroswapAggregatorPhoenixA pub struct PhoenixAggregatorAdapterTest<'a> { env: Env, adapter_client: SoroswapAggregatorPhoenixAdapterClient<'a>, + factory_client: PhoenixFactory<'a>, multihop_client: MultihopClient<'a>, token_0: TokenClient<'a>, token_1: TokenClient<'a>, token_2: TokenClient<'a>, token_3: TokenClient<'a>, user: Address, - // admin: Address + admin: Address } impl<'a> PhoenixAggregatorAdapterTest<'a> { @@ -38,17 +39,18 @@ impl<'a> PhoenixAggregatorAdapterTest<'a> { PhoenixAggregatorAdapterTest { env: test.env, adapter_client, + factory_client: test.factory_client, multihop_client: test.multihop_client, token_0: test.token_0, token_1: test.token_1, token_2: test.token_2, token_3: test.token_3, user: test.user, - // admin: test.admin + admin: test.admin } } } pub mod initialize; pub mod swap_exact_tokens_for_tokens; -// pub mod swap_tokens_for_exact_tokens; \ No newline at end of file +pub mod swap_tokens_for_exact_tokens; \ No newline at end of file diff --git a/contracts/adapters/phoenix/src/test/phoenix_setup.rs b/contracts/adapters/phoenix/src/test/phoenix_setup.rs index 5c4be5f6..38169cc7 100644 --- a/contracts/adapters/phoenix/src/test/phoenix_setup.rs +++ b/contracts/adapters/phoenix/src/test/phoenix_setup.rs @@ -32,7 +32,7 @@ pub fn deploy_factory_contract(e: &Env, admin: & Address) -> Address { e.deployer().with_address(admin.clone(), salt).deploy(factory_wasm) } -use factory::Client as PhoenixFactory; +pub use factory::Client as PhoenixFactory; /* ************* MULTIHOP ************* */ #[allow(clippy::too_many_arguments)] @@ -219,13 +219,13 @@ pub fn deploy_and_initialize_lp( pub struct PhoenixTest<'a> { pub env: Env, pub multihop_client: MultihopClient<'a>, - // pub factory_client: PhoenixFactory<'a>, + pub factory_client: PhoenixFactory<'a>, pub token_0: TokenClient<'a>, pub token_1: TokenClient<'a>, pub token_2: TokenClient<'a>, pub token_3: TokenClient<'a>, pub user: Address, - // pub admin: Address + pub admin: Address } impl<'a> PhoenixTest<'a> { @@ -280,11 +280,11 @@ impl<'a> PhoenixTest<'a> { // Setup multihop let multihop_client = deploy_multihop_contract(&env, admin.clone(), &factory_client.address); - token_0.mint(&user, &50i128); + token_0.mint(&user, &1000i128); // Check initial user value of every token: - assert_eq!(token_0.balance(&user), 50i128); + assert_eq!(token_0.balance(&user), 1000i128); assert_eq!(token_1.balance(&user), 0i128); assert_eq!(token_2.balance(&user), 0i128); assert_eq!(token_3.balance(&user), 0i128); @@ -292,13 +292,13 @@ impl<'a> PhoenixTest<'a> { PhoenixTest { env: env.clone(), multihop_client, - // factory_client, + factory_client, token_0, token_1, token_2, token_3, user, - // admin: admin.clone() + admin: admin.clone() } } } \ No newline at end of file diff --git a/contracts/adapters/phoenix/src/test/swap_exact_tokens_for_tokens.rs b/contracts/adapters/phoenix/src/test/swap_exact_tokens_for_tokens.rs index 333d5a3d..e4f72d38 100644 --- a/contracts/adapters/phoenix/src/test/swap_exact_tokens_for_tokens.rs +++ b/contracts/adapters/phoenix/src/test/swap_exact_tokens_for_tokens.rs @@ -1,5 +1,5 @@ use soroban_sdk::{Address, vec, Vec, String}; -use crate::test::{PhoenixAggregatorAdapterTest}; +use crate::test::{PhoenixAggregatorAdapterTest, phoenix_setup::deploy_and_initialize_lp}; use soroswap_aggregator_adapter_interface::{AdapterError}; @@ -145,7 +145,8 @@ fn try_swap_exact_tokens_for_tokens_insufficient_input_amount() { #[test] -#[should_panic] // TODO: Test the imported error +// #[should_panic] // TODO: Change to an error object (If we dont delete this check) +#[should_panic(expected = "Amount of token out received is less than the minimum amount expected")] fn swap_exact_tokens_for_tokens_insufficient_output_amount() { let test = PhoenixAggregatorAdapterTest::setup(); test.adapter_client.initialize( @@ -161,10 +162,8 @@ fn swap_exact_tokens_for_tokens_insufficient_output_amount() { path.push_back(test.token_3.address.clone()); let amount_in = 50i128; - - //(1000000×997×4000000000000000000)÷(1000000000000000000×1000+997×1000000) = 3987999,9 - - let expected_amount_out = 50; + // The next taken from phoenix contract tests + let expected_amount_out = 50i128; test.env.budget().reset_unlimited(); test.adapter_client.swap_exact_tokens_for_tokens( @@ -175,57 +174,121 @@ fn swap_exact_tokens_for_tokens_insufficient_output_amount() { &deadline, // deadline ); - // TODO TEST THAT WE GET THE RIGHT ERROR - assert_eq!(test.token_0.balance(&test.user), 0); - assert_eq!(test.token_1.balance(&test.user), 0); - assert_eq!(test.token_2.balance(&test.user), 0); - assert_eq!(test.token_3.balance(&test.user), 50); +} + + + +#[test] +fn swap_exact_tokens_for_tokens_enough_output_amount() { + let test = PhoenixAggregatorAdapterTest::setup(); + test.adapter_client.initialize( + &String::from_str(&test.env, "phoenix"), + &test.multihop_client.address); + + let deadline: u64 = test.env.ledger().timestamp() + 1000; + + let mut path: Vec
= Vec::new(&test.env); + + path.push_back(test.token_0.address.clone()); + path.push_back(test.token_1.address.clone()); + path.push_back(test.token_2.address.clone()); + path.push_back(test.token_3.address.clone()); + + let amount_in = 50i128; + // The next taken from phoenix contract tests + // TODO: Check with future versions of phoenix + let expected_amount_out = 50i128; + + let initial_user_balance_0 = test.token_0.balance(&test.user); + let initial_user_balance_1 = test.token_1.balance(&test.user); + let initial_user_balance_2 = test.token_2.balance(&test.user); + let initial_user_balance_3 = test.token_3.balance(&test.user); + + let token_out_address = path.get(path.len() - 1).expect("Failed to get token out address"); + + assert_eq!(token_out_address, test.token_3.address); + + test.env.budget().reset_unlimited(); + let executed_amounts = test.adapter_client.swap_exact_tokens_for_tokens( + &amount_in, // amount_in + &(expected_amount_out), // amount_out_min + &path, // path + &test.user, // to + &deadline, // deadline + ); + + + assert_eq!(test.token_0.balance(&test.user), initial_user_balance_0 - amount_in); + assert_eq!(test.token_1.balance(&test.user), initial_user_balance_1); + assert_eq!(test.token_2.balance(&test.user), initial_user_balance_2); + assert_eq!(test.token_3.balance(&test.user), initial_user_balance_3 + expected_amount_out); - // assert_eq!( - // result, - // Err(Ok(CombinedRouterError::RouterInsufficientOutputAmount)) - // ); + // WE NEED TO RETURN THE VALUES + assert_eq!(executed_amounts.get(0).unwrap(), amount_in); + assert_eq!(executed_amounts.get(1).unwrap(), expected_amount_out); } -// #[test] -// fn swap_exact_tokens_for_tokens_enough_output_amount() { -// let test = PhoenixAggregatorAdapterTest::setup(); -// test.adapter_client.initialize( -// &String::from_str(&test.env, "phoenix"), -// &test.multihop_client.address); +#[test] +fn swap_exact_tokens_for_tokens_enough_output_amount_with_fees() { + let test = PhoenixAggregatorAdapterTest::setup(); + test.adapter_client.initialize( + &String::from_str(&test.env, "phoenix"), + &test.multihop_client.address); -// let deadline: u64 = test.env.ledger().timestamp() + 1000; + // we will make a pool betwern token 0 and token 2 with fees + deploy_and_initialize_lp( + &test.env, + &test.factory_client, + test.admin.clone(), + test.token_0.address.clone(), + 1_000_000, + test.token_2.address.clone(), + 1_000_000, + Some(2000), + ); -// let mut path: Vec
= Vec::new(&test.env); -// path.push_back(test.token_0.address.clone()); -// path.push_back(test.token_1.address.clone()); -// path.push_back(test.token_0.address.clone()); -// path.push_back(test.token_1.address.clone()); -// path.push_back(test.token_2.address.clone()); -// path.push_back(test.token_3.address.clone()); + let deadline: u64 = test.env.ledger().timestamp() + 1000; -// let amount_in = 50i128; + let mut path: Vec
= Vec::new(&test.env); -// //(1000000×997×4000000000000000000)÷(1000000000000000000×1000+997×1000000) = 3987999,9 + path.push_back(test.token_0.address.clone()); + // path.push_back(test.token_1.address.clone()); + path.push_back(test.token_2.address.clone()); + // path.push_back(test.token_3.address.clone()); + + let amount_in = 300i128; + // The next taken from phoenix contract tests + // TODO: Check with future versions of phoenix + // 1000 tokens initially + // swap 300 from token0 to token1 with 2000 bps (20%) + // tokens1 will be 240 + let expected_amount_out = 240i128; + + let initial_user_balance_0 = test.token_0.balance(&test.user); + // let initial_user_balance_1 = test.token_1.balance(&test.user); + let initial_user_balance_2 = test.token_2.balance(&test.user); + // let initial_user_balance_3 = test.token_3.balance(&test.user); + + test.env.budget().reset_unlimited(); + let executed_amounts = test.adapter_client.swap_exact_tokens_for_tokens( + &amount_in, // amount_in + &(expected_amount_out), // amount_out_min + &path, // path + &test.user, // to + &deadline, // deadline + ); -// let expected_amount_out = 50; -// test.env.budget().reset_unlimited(); -// let executed_amounts = test.adapter_client.swap_exact_tokens_for_tokens( -// &amount_in, // amount_in -// &(expected_amount_out), // amount_out_min -// &path, // path -// &test.user, // to -// &deadline, // deadline -// ); + assert_eq!(test.token_0.balance(&test.user), initial_user_balance_0 - amount_in); + assert_eq!(test.token_2.balance(&test.user), initial_user_balance_2 + expected_amount_out); -// // WE NEED TO RETURN THE VALUES -// assert_eq!(executed_amounts.get(0).unwrap(), amount_in); -// assert_eq!(executed_amounts.get(1).unwrap(), expected_amount_out); -// } + // WE NEED TO RETURN THE VALUES + assert_eq!(executed_amounts.get(0).unwrap(), amount_in); + assert_eq!(executed_amounts.get(1).unwrap(), expected_amount_out); +} // use crate::factory_contract::PoolType; diff --git a/contracts/adapters/phoenix/src/test/swap_tokens_for_exact_tokens.rs b/contracts/adapters/phoenix/src/test/swap_tokens_for_exact_tokens.rs index 6ac963ec..1e2db538 100644 --- a/contracts/adapters/phoenix/src/test/swap_tokens_for_exact_tokens.rs +++ b/contracts/adapters/phoenix/src/test/swap_tokens_for_exact_tokens.rs @@ -1,16 +1,17 @@ use soroban_sdk::{Address, vec, Vec, String}; -use soroban_sdk::testutils::Ledger; -use crate::test::{SoroswapAggregatorAdapterTest}; +use crate::test::{PhoenixAggregatorAdapterTest}; use soroswap_aggregator_adapter_interface::{AdapterError}; +use soroban_sdk::testutils::Ledger; + #[test] fn swap_tokens_for_exact_tokens_not_initialized() { - let test = SoroswapAggregatorAdapterTest::setup(); + let test = PhoenixAggregatorAdapterTest::setup(); test.env.budget().reset_unlimited(); let path: Vec
= Vec::new(&test.env); - let result = test.adapter_contract.try_swap_tokens_for_exact_tokens( + let result = test.adapter_client.try_swap_tokens_for_exact_tokens( &0, // amount_out &0, // amount_in_max &path, // path @@ -24,17 +25,16 @@ fn swap_tokens_for_exact_tokens_not_initialized() { #[test] fn swap_tokens_for_exact_tokens_amount_out_negative() { - let test = SoroswapAggregatorAdapterTest::setup(); + let test = PhoenixAggregatorAdapterTest::setup(); test.env.budget().reset_unlimited(); - test.adapter_contract.initialize( - &String::from_str(&test.env, "soroswap"), - &test.router_contract.address); - + test.adapter_client.initialize( + &String::from_str(&test.env, "phoenix"), + &test.multihop_client.address); let path: Vec
= Vec::new(&test.env); - let result = test.adapter_contract.try_swap_tokens_for_exact_tokens( + let result = test.adapter_client.try_swap_tokens_for_exact_tokens( &-1, // amount_out &0, // amount_in_max &path, // path @@ -50,17 +50,16 @@ fn swap_tokens_for_exact_tokens_amount_out_negative() { #[test] fn swap_tokens_for_exact_tokens_amount_in_max_negative() { - let test = SoroswapAggregatorAdapterTest::setup(); + let test = PhoenixAggregatorAdapterTest::setup(); test.env.budget().reset_unlimited(); - test.adapter_contract.initialize( - &String::from_str(&test.env, "soroswap"), - &test.router_contract.address); - + test.adapter_client.initialize( + &String::from_str(&test.env, "phoenix"), + &test.multihop_client.address); let path: Vec
= Vec::new(&test.env); - let result = test.adapter_contract.try_swap_tokens_for_exact_tokens( + let result = test.adapter_client.try_swap_tokens_for_exact_tokens( &0, // amount_out &-1, // amount_in_max &path, // path @@ -76,16 +75,15 @@ fn swap_tokens_for_exact_tokens_amount_in_max_negative() { #[test] fn swap_tokens_for_exact_tokens_expired() { - let test = SoroswapAggregatorAdapterTest::setup(); - - test.adapter_contract.initialize( - &String::from_str(&test.env, "soroswap"), - &test.router_contract.address); + let test = PhoenixAggregatorAdapterTest::setup(); + test.adapter_client.initialize( + &String::from_str(&test.env, "phoenix"), + &test.multihop_client.address); let path: Vec
= Vec::new(&test.env); - let result = test.adapter_contract.try_swap_tokens_for_exact_tokens( + let result = test.adapter_client.try_swap_tokens_for_exact_tokens( &0, // amount_out &0, // amount_in_max &path, // path @@ -103,18 +101,17 @@ fn swap_tokens_for_exact_tokens_expired() { #[test] #[should_panic] // TODO: Test the imported error fn try_swap_tokens_for_exact_tokens_invalid_path() { - let test = SoroswapAggregatorAdapterTest::setup(); - - test.adapter_contract.initialize( - &String::from_str(&test.env, "soroswap"), - &test.router_contract.address); + let test = PhoenixAggregatorAdapterTest::setup(); + test.adapter_client.initialize( + &String::from_str(&test.env, "phoenix"), + &test.multihop_client.address); let deadline: u64 = test.env.ledger().timestamp() + 1000; let path: Vec
= vec![&test.env, test.token_0.address.clone()]; - let result = test.adapter_contract.swap_tokens_for_exact_tokens( // add try_ to test the error + test.adapter_client.swap_tokens_for_exact_tokens( // add try_ to test the error &0, // amount_out &0, // amount_in_max &path, // path @@ -130,22 +127,21 @@ fn try_swap_tokens_for_exact_tokens_invalid_path() { // Panics because LP does not exist; here panics with a Error(Storage, MissingValue) // We should implement a pair_address.exist() without needing to call the Factory #[should_panic] -fn swap_tokens_for_exact_tokens_pair_does_not_exist() { - let test = SoroswapAggregatorAdapterTest::setup(); - - test.adapter_contract.initialize( - &String::from_str(&test.env, "soroswap"), - &test.router_contract.address); +fn try_swap_tokens_for_exact_tokens_pair_does_not_exist() { + let test = PhoenixAggregatorAdapterTest::setup(); + test.adapter_client.initialize( + &String::from_str(&test.env, "phoenix"), + &test.multihop_client.address); let deadline: u64 = test.env.ledger().timestamp() + 1000; let mut path: Vec
= Vec::new(&test.env); path.push_back(test.token_0.address.clone()); - path.push_back(test.token_1.address.clone()); + path.push_back(test.token_3.address.clone()); - test.adapter_contract.swap_tokens_for_exact_tokens( - &0, //amount_out + test.adapter_client.swap_tokens_for_exact_tokens( + &1, //amount_out &0, // amount_in_max &path, // path &test.user, // to @@ -156,12 +152,11 @@ fn swap_tokens_for_exact_tokens_pair_does_not_exist() { #[test] #[should_panic] // TODO: Test the imported error fn try_swap_tokens_for_exact_tokens_insufficient_output_amount() { - let test = SoroswapAggregatorAdapterTest::setup(); - - test.adapter_contract.initialize( - &String::from_str(&test.env, "soroswap"), - &test.router_contract.address); + let test = PhoenixAggregatorAdapterTest::setup(); + test.adapter_client.initialize( + &String::from_str(&test.env, "phoenix"), + &test.multihop_client.address); let deadline: u64 = test.env.ledger().timestamp() + 1000; @@ -171,7 +166,7 @@ fn try_swap_tokens_for_exact_tokens_insufficient_output_amount() { test.env.budget().reset_unlimited(); - let result = test.adapter_contract.swap_tokens_for_exact_tokens( + test.adapter_client.swap_tokens_for_exact_tokens( &0, // amount_out &0, // amount_in_max &path, // path @@ -182,15 +177,14 @@ fn try_swap_tokens_for_exact_tokens_insufficient_output_amount() { } #[test] -#[should_panic] // TODO: Test the imported error -fn swap_tokens_for_exact_tokens_amount_in_max_not_enough() { - let test = SoroswapAggregatorAdapterTest::setup(); +#[should_panic(expected = "Amount of token in required is greater than the maximum amount expected")] // TODO: Test the imported error +fn try_swap_tokens_for_exact_tokens_amount_in_max_not_enough() { + let test = PhoenixAggregatorAdapterTest::setup(); test.env.budget().reset_unlimited(); - test.adapter_contract.initialize( - &String::from_str(&test.env, "soroswap"), - &test.router_contract.address); - + test.adapter_client.initialize( + &String::from_str(&test.env, "phoenix"), + &test.multihop_client.address); let deadline: u64 = test.env.ledger().timestamp() + 1000; @@ -198,71 +192,34 @@ fn swap_tokens_for_exact_tokens_amount_in_max_not_enough() { path.push_back(test.token_0.address.clone()); path.push_back(test.token_1.address.clone()); - let expected_amount_out = 5_000_000; + let expected_amount_out = 50; + // From Phoenix tests + let amount_in_should = 50; - let result = test.adapter_contract.swap_tokens_for_exact_tokens( + test.adapter_client.swap_tokens_for_exact_tokens( &expected_amount_out, // amount_out - &0, // amount_in_max + &(amount_in_should-1), // amount_in_max &path, // path &test.user, // to &deadline, // deadline ); - // assert_eq!( - // result, - // Err(Ok(CombinedRouterError::RouterExcessiveInputAmount)) - // ); -} - -#[test] -#[should_panic] // TODO: Test the imported error -fn swap_tokens_for_exact_tokens_amount_in_max_not_enough_amount_in_should_minus_1() { - let test = SoroswapAggregatorAdapterTest::setup(); - test.env.budget().reset_unlimited(); - - test.adapter_contract.initialize( - &String::from_str(&test.env, "soroswap"), - &test.router_contract.address); - - - let deadline: u64 = test.env.ledger().timestamp() + 1000; - - let mut path: Vec
= Vec::new(&test.env); - path.push_back(test.token_0.address.clone()); - path.push_back(test.token_1.address.clone()); - - - let expected_amount_out = 5_000_000; - let amount_in_should = test - .router_contract - .router_get_amounts_in(&expected_amount_out, &path) - .get(0) - .unwrap(); - - let result = test.adapter_contract.swap_tokens_for_exact_tokens( - &expected_amount_out, // amount_out - &(amount_in_should - 1), // amount_in_max - &path, // path - &test.user, // to - &deadline, // deadline - ); + // TODO: Evaluate if change panic message with error object (check benchmark) // assert_eq!( // result, // Err(Ok(CombinedRouterError::RouterExcessiveInputAmount)) // ); } - #[test] fn swap_tokens_for_exact_tokens_amount_in_should() { - let test = SoroswapAggregatorAdapterTest::setup(); + let test = PhoenixAggregatorAdapterTest::setup(); test.env.budget().reset_unlimited(); - test.adapter_contract.initialize( - &String::from_str(&test.env, "soroswap"), - &test.router_contract.address); - + test.adapter_client.initialize( + &String::from_str(&test.env, "phoenix"), + &test.multihop_client.address); let deadline: u64 = test.env.ledger().timestamp() + 1000; @@ -270,13 +227,14 @@ fn swap_tokens_for_exact_tokens_amount_in_should() { path.push_back(test.token_0.address.clone()); path.push_back(test.token_1.address.clone()); - let amount_0: i128 = 1_000_000_000_000_000_000; - let amount_1: i128 = 4_000_000_000_000_000_000; + let expected_amount_out = 50; + // From Phoenix tests + let amount_in_should = 50; - let expected_amount_out = 5_000_000; - let amount_in_should = test.router_contract.router_get_amounts_in(&expected_amount_out, &path).get(0).unwrap(); + let initial_user_balance_0 = test.token_0.balance(&test.user); + let initial_user_balance_1 = test.token_1.balance(&test.user); - let amounts = test.adapter_contract.swap_tokens_for_exact_tokens( + let amounts = test.adapter_client.swap_tokens_for_exact_tokens( &expected_amount_out, //amount_out &(amount_in_should), // amount_in_max &path, // path @@ -286,49 +244,21 @@ fn swap_tokens_for_exact_tokens_amount_in_should() { assert_eq!(amounts.get(0).unwrap(), amount_in_should); assert_eq!(amounts.get(1).unwrap(), expected_amount_out); - let initial_user_balance = 20_000_000_000_000_000_000; - - // pub fn get_amount_in(amount_out: i128, reserve_in: i128, reserve_out: i128) -> Result { - // if amount_out <= 0 { - // return Err(SoroswapLibraryError::InsufficientOutputAmount); - // } - // if reserve_in <= 0 || reserve_out <= 0 { - // return Err(SoroswapLibraryError::InsufficientLiquidity); - // } - // let numerator = reserve_in.checked_mul(amount_out).unwrap().checked_mul(1000).unwrap(); - // let denominator = reserve_out.checked_sub(amount_out).unwrap().checked_mul(997).unwrap(); - // Ok(numerator.checked_ceiling_div(denominator).unwrap().checked_add(1).unwrap()) - // } - - // numerator = 1_000_000_000_000_000_000 * 5_000_000 * 1_000 = 5_000_000_000_000_000_000_000_000_000 - // denominator = (4000000000000000000 - 5000000) * 997 = 3999999999995000000 * 997 = 3987999999995015000000 - - // num/den +1 = 5000000000000000000000000000 / 3987999999995015000000 +1 = ceil(1253761.283853122) +1 - // = 1253762 + 1 = 1253763 - - let expected_amount_0_in = 1253763; - assert_eq!(amounts.get(0).unwrap(), expected_amount_0_in); - - assert_eq!(test.token_0.balance(&test.user), initial_user_balance - amount_0 - expected_amount_0_in); - assert_eq!(test.token_1.balance(&test.user), initial_user_balance - amount_1*2 + expected_amount_out); - - let pair_address = test.factory_contract.get_pair(&test.token_0.address, &test.token_1.address); - assert_eq!(test.token_0.balance(&pair_address), amount_0 + expected_amount_0_in); - assert_eq!(test.token_1.balance(&pair_address), amount_1 - expected_amount_out); + assert_eq!(test.token_0.balance(&test.user), initial_user_balance_0 - amount_in_should); + assert_eq!(test.token_1.balance(&test.user), initial_user_balance_1 + expected_amount_out); } #[test] -fn swap_tokens_for_exact_tokens_2_hops() { - let test = SoroswapAggregatorAdapterTest::setup(); +fn swap_tokens_for_exact_tokens_3_hops() { + let test = PhoenixAggregatorAdapterTest::setup(); test.env.budget().reset_unlimited(); - test.adapter_contract.initialize( - &String::from_str(&test.env, "soroswap"), - &test.router_contract.address); - + test.adapter_client.initialize( + &String::from_str(&test.env, "phoenix"), + &test.multihop_client.address); let ledger_timestamp = 100; let desired_deadline = 1000; @@ -337,37 +267,22 @@ fn swap_tokens_for_exact_tokens_2_hops() { li.timestamp = ledger_timestamp; }); - let initial_user_balance = 20_000_000_000_000_000_000; - - let amount_0: i128 = 1_000_000_000_000_000_000; - let amount_1: i128 = 4_000_000_000_000_000_000; - let amount_2: i128 = 8_000_000_000_000_000_000; - let mut path: Vec
= Vec::new(&test.env); path.push_back(test.token_0.address.clone()); path.push_back(test.token_1.address.clone()); path.push_back(test.token_2.address.clone()); + path.push_back(test.token_3.address.clone()); + + let expected_amount_out = 50; + // From Phoenix tests + let amount_in_should =50; + + let initial_user_balance_0 = test.token_0.balance(&test.user); + let initial_user_balance_1 = test.token_1.balance(&test.user); + let initial_user_balance_2 = test.token_2.balance(&test.user); + let initial_user_balance_3 = test.token_3.balance(&test.user); - let expected_amount_out = 123_456_789; - // pair token_1, token_2 - // token_1 is r_in, token_2 is r_out - // (r_in*amount_out)*1000 / (r_out - amount_out)*997 - // (4_000_000_000_000_000_000*123456789)*1000 / ((8_000_000_000_000_000_000 - 123456789)*997) + 1 = - // 493827156000000000000000000000 / (7999999999876543211 * 997) +1 = - // 493827156000000000000000000000 / 7975999999876913581367 +1 = CEIL(61914136.911687662) +1 = 61914137 +1 = 61914138 - // - let middle_amount_in =61914138; - - // pair token_0, token_1 - // token_0 is r_in, token_1 is r_out - // first amount in = - // (1_000_000_000_000_000_000*61914138)*1000 / ((4_000_000_000_000_000_000 - 61914138)*997) + 1 = - // 61914138000000000000000000000 / (3999999999938085862 * 997) + 1 = - // CEIL (61914138000000000000000000000 / 3987999999938271604414) +1 = ceil(15525109.8) +1 = 15525111 - - let amount_in_should =15525111; - - let amounts = test.adapter_contract.swap_tokens_for_exact_tokens( + let amounts = test.adapter_client.swap_tokens_for_exact_tokens( &expected_amount_out, //amount_out &amount_in_should, // amount_in_max &path, // path @@ -376,18 +291,10 @@ fn swap_tokens_for_exact_tokens_2_hops() { assert_eq!(amounts.get(0).unwrap(), amount_in_should); - assert_eq!(amounts.get(1).unwrap(), middle_amount_in); - assert_eq!(amounts.get(2).unwrap(), expected_amount_out); - - assert_eq!(test.token_0.balance(&test.user), initial_user_balance - amount_0 - amount_in_should); - assert_eq!(test.token_1.balance(&test.user), initial_user_balance - amount_1*2); - assert_eq!(test.token_2.balance(&test.user), initial_user_balance - amount_2 + expected_amount_out); - - let pair_address_0_1 = test.factory_contract.get_pair(&test.token_0.address, &test.token_1.address); - assert_eq!(test.token_0.balance(&pair_address_0_1), amount_0 + amount_in_should); - assert_eq!(test.token_1.balance(&pair_address_0_1), amount_1 - middle_amount_in); + assert_eq!(amounts.get(1).unwrap(), expected_amount_out); - let pair_address_1_2 = test.factory_contract.get_pair(&test.token_1.address, &test.token_2.address); - assert_eq!(test.token_1.balance(&pair_address_1_2), amount_1 + middle_amount_in); - assert_eq!(test.token_2.balance(&pair_address_1_2), amount_2 - expected_amount_out); + assert_eq!(test.token_0.balance(&test.user), initial_user_balance_0 - amount_in_should); + assert_eq!(test.token_1.balance(&test.user), initial_user_balance_1); + assert_eq!(test.token_2.balance(&test.user), initial_user_balance_2); + assert_eq!(test.token_3.balance(&test.user), initial_user_balance_3 + expected_amount_out); } From f7ee7f592e3e9d1bbb3e7a177a0f053af4e45935 Mon Sep 17 00:00:00 2001 From: esteblock Date: Thu, 18 Jul 2024 21:12:56 +0200 Subject: [PATCH 07/11] move soroswap setup into specific file --- .../src/test/swap_exact_tokens_for_tokens.rs | 4 +- contracts/aggregator/src/test.rs | 107 ++++-------------- .../aggregator/src/test/soroswap_setup.rs | 55 +++++++++ 3 files changed, 82 insertions(+), 84 deletions(-) create mode 100644 contracts/aggregator/src/test/soroswap_setup.rs diff --git a/contracts/adapters/phoenix/src/test/swap_exact_tokens_for_tokens.rs b/contracts/adapters/phoenix/src/test/swap_exact_tokens_for_tokens.rs index e4f72d38..160e35b7 100644 --- a/contracts/adapters/phoenix/src/test/swap_exact_tokens_for_tokens.rs +++ b/contracts/adapters/phoenix/src/test/swap_exact_tokens_for_tokens.rs @@ -194,10 +194,10 @@ fn swap_exact_tokens_for_tokens_enough_output_amount() { path.push_back(test.token_2.address.clone()); path.push_back(test.token_3.address.clone()); - let amount_in = 50i128; + let amount_in = 500i128; // The next taken from phoenix contract tests // TODO: Check with future versions of phoenix - let expected_amount_out = 50i128; + let expected_amount_out = 500i128; let initial_user_balance_0 = test.token_0.balance(&test.user); let initial_user_balance_1 = test.token_1.balance(&test.user); diff --git a/contracts/aggregator/src/test.rs b/contracts/aggregator/src/test.rs index d4827e1e..93992b00 100644 --- a/contracts/aggregator/src/test.rs +++ b/contracts/aggregator/src/test.rs @@ -7,6 +7,10 @@ use soroban_sdk::{ vec, Address, BytesN, Env, String, Vec, }; +mod soroswap_setup; +use soroswap_setup::{SoroswapAggregatorAdapterForSoroswapClient, create_soroswap_adapter, create_soroswap_factory, create_soroswap_router, + SoroswapRouterClient}; + // Token Contract mod token { soroban_sdk::contractimport!(file = "../adapters/soroswap/soroswap_contracts/soroban_token_contract.wasm"); @@ -18,64 +22,6 @@ pub fn create_token_contract<'a>(e: &Env, admin: &Address) -> TokenClient<'a> { TokenClient::new(&e, &e.register_stellar_asset_contract(admin.clone())) } -// // Pair Contract -// mod pair { -// soroban_sdk::contractimport!(file = "../../protocols/soroswap/contracts/pair/target/wasm32-unknown-unknown/release/soroswap_pair.wasm"); -// pub type SoroswapPairClient<'a> = Client<'a>; -// } -// use pair::SoroswapPairClient; - -fn pair_contract_wasm(e: &Env) -> BytesN<32> { - soroban_sdk::contractimport!( - file = "../adapters/soroswap/soroswap_contracts/soroswap_pair.wasm" - ); - e.deployer().upload_contract_wasm(WASM) -} - -// SoroswapFactory Contract -mod factory { - soroban_sdk::contractimport!(file = "../adapters/soroswap/soroswap_contracts/soroswap_factory.wasm"); - pub type SoroswapFactoryClient<'a> = Client<'a>; -} -use factory::SoroswapFactoryClient; - -fn create_soroswap_factory<'a>(e: &Env, setter: &Address) -> SoroswapFactoryClient<'a> { - let pair_hash = pair_contract_wasm(&e); - let factory_address = &e.register_contract_wasm(None, factory::WASM); - let factory = SoroswapFactoryClient::new(e, factory_address); - factory.initialize(&setter, &pair_hash); - factory -} - -// SoroswapRouter Contract -mod router { - soroban_sdk::contractimport!(file = "../adapters/soroswap/soroswap_contracts/soroswap_router.optimized.wasm"); - pub type SoroswapRouterClient<'a> = Client<'a>; -} -use router::SoroswapRouterClient; - -// SoroswapRouter Contract -pub fn create_soroswap_router<'a>(e: &Env) -> SoroswapRouterClient<'a> { - let router_address = &e.register_contract_wasm(None, router::WASM); - let router = SoroswapRouterClient::new(e, router_address); - router -} -// SoroswapAggregatorAdapter Contract -// For Soroswap -mod soroswap_adapter { - soroban_sdk::contractimport!(file = "../target/wasm32-unknown-unknown/release/soroswap_adapter.optimized.wasm"); - pub type SoroswapAggregatorAdapterForSoroswapClient<'a> = Client<'a>; -} -use soroswap_adapter::SoroswapAggregatorAdapterForSoroswapClient; - -// Adapter for Soroswap -fn create_soroswap_adapter<'a>(e: &Env) -> SoroswapAggregatorAdapterForSoroswapClient<'a> { - let adapter_address = &e.register_contract_wasm(None, soroswap_adapter::WASM); - let adapter = SoroswapAggregatorAdapterForSoroswapClient::new(e, adapter_address); - adapter -} - -// SoroswapAggregatorAdapter Contract // For Phoenix mod phoenix_adapter { soroban_sdk::contractimport!( @@ -158,11 +104,6 @@ impl<'a> SoroswapAggregatorTest<'a> { let env = Env::default(); env.mock_all_auths(); let aggregator_contract = create_soroswap_aggregator(&env); - let router_contract = create_soroswap_router(&env); - let soroswap_adapter_contract = create_soroswap_adapter(&env); - let _phoenix_adapter_contract = create_phoenix_adapter(&env); - - let initial_user_balance = 20_000_000_000_000_000_000; let admin = Address::generate(&env); let user = Address::generate(&env); @@ -172,18 +113,22 @@ impl<'a> SoroswapAggregatorTest<'a> { let token_1 = create_token_contract(&env, &admin); let token_2 = create_token_contract(&env, &admin); + let initial_user_balance = 20_000_000_000_000_000_000; token_0.mint(&user, &initial_user_balance); token_1.mint(&user, &initial_user_balance); token_2.mint(&user, &initial_user_balance); - - let factory_contract = create_soroswap_factory(&env, &admin); + + + + /* INITIALIZE SOROSWAP FACTORY, ROUTER AND LPS */ env.budget().reset_unlimited(); + let router_contract = create_soroswap_router(&env); + let factory_contract = create_soroswap_factory(&env, &admin); + router_contract.initialize(&factory_contract.address); let ledger_timestamp = 100; let desired_deadline = 1000; - assert!(desired_deadline > ledger_timestamp); - env.ledger().with_mut(|li| { li.timestamp = ledger_timestamp; }); @@ -198,7 +143,6 @@ impl<'a> SoroswapAggregatorTest<'a> { assert_eq!(token_1.balance(&user), initial_user_balance); assert_eq!(token_2.balance(&user), initial_user_balance); - router_contract.initialize(&factory_contract.address); assert_eq!( factory_contract.pair_exists(&token_0.address, &token_1.address), @@ -228,25 +172,12 @@ impl<'a> SoroswapAggregatorTest<'a> { &desired_deadline, // deadline: u64, ); - // let (added_token_0_1, added_token_2_1, added_liquidity_0_2) = router_contract.add_liquidity( - // &token_0.address, // token_a: Address, - // &token_2.address, // token_b: Address, - // &amount_0, // amount_a_desired: i128, - // &amount_1, // amount_b_desired: i128, - // &0, // amount_a_min: i128, - // &0 , // amount_b_min: i128, - // &user, // to: Address, - // &desired_deadline// deadline: u64, - // ); - static MINIMUM_LIQUIDITY: i128 = 1000; assert_eq!(added_token_0_0, amount_0); assert_eq!(added_token_1_0, amount_1); assert_eq!(added_token_1_1, amount_1); assert_eq!(added_token_2_0, amount_2); - // assert_eq!(added_token_0_1, amount_0); - // assert_eq!(added_token_2_1, amount_1); assert_eq!( added_liquidity_0_1, @@ -259,12 +190,24 @@ impl<'a> SoroswapAggregatorTest<'a> { assert_eq!(token_1.balance(&user), 12_000_000_000_000_000_000); assert_eq!(token_2.balance(&user), 12_000_000_000_000_000_000); - // Initializing Soroswap Adapter Contract + + /* INITIALIZE PHOENIX FACTORY, LP AND MULTIHOP */ + + + + + + /* CREATE ADAPTERS */ + // Create and Initializing Soroswap Adapter Contract + let soroswap_adapter_contract = create_soroswap_adapter(&env); soroswap_adapter_contract.initialize( &String::from_str(&env, "soroswap"), &router_contract.address, ); + let _phoenix_adapter_contract = create_phoenix_adapter(&env); + + SoroswapAggregatorTest { env, aggregator_contract, diff --git a/contracts/aggregator/src/test/soroswap_setup.rs b/contracts/aggregator/src/test/soroswap_setup.rs new file mode 100644 index 00000000..8be81593 --- /dev/null +++ b/contracts/aggregator/src/test/soroswap_setup.rs @@ -0,0 +1,55 @@ +use soroban_sdk::{ + Env, BytesN, Address, +}; + +fn pair_contract_wasm(e: &Env) -> BytesN<32> { + soroban_sdk::contractimport!( + file = "../adapters/soroswap/soroswap_contracts/soroswap_pair.wasm" + ); + e.deployer().upload_contract_wasm(WASM) +} + +// SoroswapFactory Contract +mod factory { + soroban_sdk::contractimport!(file = "../adapters/soroswap/soroswap_contracts/soroswap_factory.wasm"); + pub type SoroswapFactoryClient<'a> = Client<'a>; +} +use factory::SoroswapFactoryClient; + +pub fn create_soroswap_factory<'a>(e: &Env, setter: &Address) -> SoroswapFactoryClient<'a> { + let pair_hash = pair_contract_wasm(&e); + let factory_address = &e.register_contract_wasm(None, factory::WASM); + let factory = SoroswapFactoryClient::new(e, factory_address); + factory.initialize(&setter, &pair_hash); + factory +} + +// SoroswapRouter Contract +mod router { + soroban_sdk::contractimport!(file = "../adapters/soroswap/soroswap_contracts/soroswap_router.optimized.wasm"); + pub type SoroswapRouterClient<'a> = Client<'a>; +} +pub use router::SoroswapRouterClient; + +// SoroswapRouter Contract +pub fn create_soroswap_router<'a>(e: &Env) -> SoroswapRouterClient<'a> { + let router_address = &e.register_contract_wasm(None, router::WASM); + let router = SoroswapRouterClient::new(e, router_address); + router +} + + +// SoroswapAggregatorAdapter Contract +// For Soroswap +mod soroswap_adapter { + soroban_sdk::contractimport!(file = "../target/wasm32-unknown-unknown/release/soroswap_adapter.optimized.wasm"); + pub type SoroswapAggregatorAdapterForSoroswapClient<'a> = Client<'a>; +} +pub use soroswap_adapter::SoroswapAggregatorAdapterForSoroswapClient; + +// Adapter for Soroswap +pub fn create_soroswap_adapter<'a>(e: &Env) -> SoroswapAggregatorAdapterForSoroswapClient<'a> { + let adapter_address = &e.register_contract_wasm(None, soroswap_adapter::WASM); + let adapter = SoroswapAggregatorAdapterForSoroswapClient::new(e, adapter_address); + adapter +} From 81a93907e950d50d37f2cb1a872fc0188c1e0165 Mon Sep 17 00:00:00 2001 From: esteblock Date: Thu, 18 Jul 2024 21:52:07 +0200 Subject: [PATCH 08/11] setup phoenix functions in phoenix_setup --- contracts/aggregator/src/test.rs | 43 ++++++++++--------- .../aggregator/src/test/soroswap_setup.rs | 1 + 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/contracts/aggregator/src/test.rs b/contracts/aggregator/src/test.rs index 93992b00..b9daea2b 100644 --- a/contracts/aggregator/src/test.rs +++ b/contracts/aggregator/src/test.rs @@ -8,8 +8,21 @@ use soroban_sdk::{ }; mod soroswap_setup; -use soroswap_setup::{SoroswapAggregatorAdapterForSoroswapClient, create_soroswap_adapter, create_soroswap_factory, create_soroswap_router, - SoroswapRouterClient}; +use soroswap_setup::{ + create_soroswap_adapter, + create_soroswap_factory, + create_soroswap_router, + SoroswapAggregatorAdapterForSoroswapClient, + SoroswapRouterClient, +}; + +mod phoenix_setup; + +// SoroswapAggregator Contract [THE MAIN CONTRACT] +fn create_soroswap_aggregator<'a>(e: &Env) -> SoroswapAggregatorClient<'a> { + SoroswapAggregatorClient::new(e, &e.register_contract(None, SoroswapAggregator {})) +} + // Token Contract mod token { @@ -17,32 +30,17 @@ mod token { pub type TokenClient<'a> = Client<'a>; } use token::TokenClient; - pub fn create_token_contract<'a>(e: &Env, admin: &Address) -> TokenClient<'a> { TokenClient::new(&e, &e.register_stellar_asset_contract(admin.clone())) } -// For Phoenix -mod phoenix_adapter { +pub fn install_token_wasm(env: &Env) -> BytesN<32> { soroban_sdk::contractimport!( - file = - "../target/wasm32-unknown-unknown/release/phoenix_adapter.optimized.wasm" + file = "../adapters/soroswap/soroswap_contracts/soroban_token_contract.wasm" ); - pub type SoroswapAggregatorAdapterForPhoenixClient<'a> = Client<'a>; + env.deployer().upload_contract_wasm(WASM) } -use phoenix_adapter::SoroswapAggregatorAdapterForPhoenixClient; -// Adapter for phoenix -fn create_phoenix_adapter<'a>(e: &Env) -> SoroswapAggregatorAdapterForPhoenixClient<'a> { - let adapter_address = &e.register_contract_wasm(None, phoenix_adapter::WASM); - let adapter = SoroswapAggregatorAdapterForPhoenixClient::new(e, adapter_address); - adapter -} - -// SoroswapAggregator Contract -fn create_soroswap_aggregator<'a>(e: &Env) -> SoroswapAggregatorClient<'a> { - SoroswapAggregatorClient::new(e, &e.register_contract(None, SoroswapAggregator {})) -} // Helper function to initialize / update soroswap aggregator protocols pub fn create_protocols_addresses(test: &SoroswapAggregatorTest) -> Vec { @@ -121,6 +119,7 @@ impl<'a> SoroswapAggregatorTest<'a> { /* INITIALIZE SOROSWAP FACTORY, ROUTER AND LPS */ + /************************************************/ env.budget().reset_unlimited(); let router_contract = create_soroswap_router(&env); let factory_contract = create_soroswap_factory(&env, &admin); @@ -192,6 +191,8 @@ impl<'a> SoroswapAggregatorTest<'a> { /* INITIALIZE PHOENIX FACTORY, LP AND MULTIHOP */ + /************************************************/ + @@ -205,7 +206,7 @@ impl<'a> SoroswapAggregatorTest<'a> { &router_contract.address, ); - let _phoenix_adapter_contract = create_phoenix_adapter(&env); + // let _phoenix_adapter_contract = create_phoenix_adapter(&env); SoroswapAggregatorTest { diff --git a/contracts/aggregator/src/test/soroswap_setup.rs b/contracts/aggregator/src/test/soroswap_setup.rs index 8be81593..92e7dabd 100644 --- a/contracts/aggregator/src/test/soroswap_setup.rs +++ b/contracts/aggregator/src/test/soroswap_setup.rs @@ -2,6 +2,7 @@ use soroban_sdk::{ Env, BytesN, Address, }; + fn pair_contract_wasm(e: &Env) -> BytesN<32> { soroban_sdk::contractimport!( file = "../adapters/soroswap/soroswap_contracts/soroswap_pair.wasm" From 50eeae54c88688b1be54add9ce3a98acbf98060f Mon Sep 17 00:00:00 2001 From: esteblock Date: Fri, 19 Jul 2024 10:04:57 +0200 Subject: [PATCH 09/11] phoenix multihop, factory and LP set up for testing --- contracts/adapters/phoenix/src/test.rs | 4 +- contracts/aggregator/src/test.rs | 79 ++++++-- contracts/aggregator/src/test/events.rs | 2 +- .../aggregator/src/test/phoenix_setup.rs | 188 ++++++++++++++++++ .../src/test/swap_tokens_for_exact_tokens.rs | 4 +- 5 files changed, 258 insertions(+), 19 deletions(-) create mode 100644 contracts/aggregator/src/test/phoenix_setup.rs diff --git a/contracts/adapters/phoenix/src/test.rs b/contracts/adapters/phoenix/src/test.rs index c7ba535a..7fcf5ac0 100644 --- a/contracts/adapters/phoenix/src/test.rs +++ b/contracts/adapters/phoenix/src/test.rs @@ -13,7 +13,7 @@ use phoenix_setup::{PhoenixTest, MultihopClient, TokenClient, PhoenixFactory}; // use router::SoroswapRouterClient; // PhoenixAggregatorAdapter Contract -fn create_soroswap_aggregator_adapter<'a>(e: &Env) -> SoroswapAggregatorPhoenixAdapterClient<'a> { +fn create_soroswap_aggregator_phoenix_adapter<'a>(e: &Env) -> SoroswapAggregatorPhoenixAdapterClient<'a> { SoroswapAggregatorPhoenixAdapterClient::new(e, &e.register_contract(None, SoroswapAggregatorPhoenixAdapter {})) } @@ -34,7 +34,7 @@ impl<'a> PhoenixAggregatorAdapterTest<'a> { fn setup() -> Self { let test = PhoenixTest::phoenix_setup(); - let adapter_client = create_soroswap_aggregator_adapter(&test.env); + let adapter_client = create_soroswap_aggregator_phoenix_adapter(&test.env); PhoenixAggregatorAdapterTest { env: test.env, diff --git a/contracts/aggregator/src/test.rs b/contracts/aggregator/src/test.rs index b9daea2b..64bc57bc 100644 --- a/contracts/aggregator/src/test.rs +++ b/contracts/aggregator/src/test.rs @@ -17,6 +17,12 @@ use soroswap_setup::{ }; mod phoenix_setup; +use phoenix_setup::{ + create_phoenix_adapter, + deploy_and_initialize_factory as phoenix_deploy_and_initialize_factory, + deploy_and_initialize_lp as phoenix_deploy_and_initialize_lp, + deploy_multihop_contract as phoenix_deploy_multihop_contract +}; // SoroswapAggregator Contract [THE MAIN CONTRACT] fn create_soroswap_aggregator<'a>(e: &Env) -> SoroswapAggregatorClient<'a> { @@ -59,7 +65,7 @@ pub fn new_update_adapters_addresses(test: &SoroswapAggregatorTest) -> Vec Vec Vec Vec { env: Env, aggregator_contract: SoroswapAggregatorClient<'a>, - router_contract: SoroswapRouterClient<'a>, + soroswap_router_contract: SoroswapRouterClient<'a>, // factory_contract: SoroswapFactoryClient<'a>, soroswap_adapter_contract: SoroswapAggregatorAdapterForSoroswapClient<'a>, // phoenix_adapter_contract: SoroswapAggregatorAdapterForPhoenixClient<'a>, @@ -110,20 +116,27 @@ impl<'a> SoroswapAggregatorTest<'a> { let token_0 = create_token_contract(&env, &admin); let token_1 = create_token_contract(&env, &admin); let token_2 = create_token_contract(&env, &admin); + let token_3 = create_token_contract(&env, &admin); let initial_user_balance = 20_000_000_000_000_000_000; token_0.mint(&user, &initial_user_balance); token_1.mint(&user, &initial_user_balance); token_2.mint(&user, &initial_user_balance); + token_3.mint(&user, &initial_user_balance); + + token_0.mint(&admin, &initial_user_balance); + token_1.mint(&admin, &initial_user_balance); + token_2.mint(&admin, &initial_user_balance); + token_3.mint(&admin, &initial_user_balance); /* INITIALIZE SOROSWAP FACTORY, ROUTER AND LPS */ /************************************************/ env.budget().reset_unlimited(); - let router_contract = create_soroswap_router(&env); + let soroswap_router_contract = create_soroswap_router(&env); let factory_contract = create_soroswap_factory(&env, &admin); - router_contract.initialize(&factory_contract.address); + soroswap_router_contract.initialize(&factory_contract.address); let ledger_timestamp = 100; let desired_deadline = 1000; @@ -147,7 +160,7 @@ impl<'a> SoroswapAggregatorTest<'a> { factory_contract.pair_exists(&token_0.address, &token_1.address), false ); - let (added_token_0_0, added_token_1_0, added_liquidity_0_1) = router_contract + let (added_token_0_0, added_token_1_0, added_liquidity_0_1) = soroswap_router_contract .add_liquidity( &token_0.address, // token_a: Address, &token_1.address, // token_b: Address, @@ -159,7 +172,7 @@ impl<'a> SoroswapAggregatorTest<'a> { &desired_deadline, // deadline: u64, ); - let (added_token_1_1, added_token_2_0, added_liquidity_1_2) = router_contract + let (added_token_1_1, added_token_2_0, added_liquidity_1_2) = soroswap_router_contract .add_liquidity( &token_1.address, // token_a: Address, &token_2.address, // token_b: Address, @@ -192,10 +205,44 @@ impl<'a> SoroswapAggregatorTest<'a> { /* INITIALIZE PHOENIX FACTORY, LP AND MULTIHOP */ /************************************************/ + let phoenix_factory_client = phoenix_deploy_and_initialize_factory(&env.clone(), admin.clone()); + + + phoenix_deploy_and_initialize_lp( + &env, + &phoenix_factory_client, + admin.clone(), + token_0.address.clone(), + 1_000_000, + token_1.address.clone(), + 1_000_000, + None, + ); + phoenix_deploy_and_initialize_lp( + &env, + &phoenix_factory_client, + admin.clone(), + token_1.address.clone(), + 1_000_000, + token_2.address.clone(), + 1_000_000, + None, + ); + phoenix_deploy_and_initialize_lp( + &env, + &phoenix_factory_client, + admin.clone(), + token_2.address.clone(), + 1_000_000, + token_3.address.clone(), + 1_000_000, + None, + ); - - - + let phoenix_multihop_client = phoenix_deploy_multihop_contract( + &env, + admin.clone(), + &phoenix_factory_client.address); /* CREATE ADAPTERS */ @@ -203,16 +250,20 @@ impl<'a> SoroswapAggregatorTest<'a> { let soroswap_adapter_contract = create_soroswap_adapter(&env); soroswap_adapter_contract.initialize( &String::from_str(&env, "soroswap"), - &router_contract.address, + &soroswap_router_contract.address, ); - // let _phoenix_adapter_contract = create_phoenix_adapter(&env); + let phoenix_adapter_contract = create_phoenix_adapter(&env); + phoenix_adapter_contract.initialize( + &String::from_str(&env, "phoenix"), + &phoenix_multihop_client.address + ); SoroswapAggregatorTest { env, aggregator_contract, - router_contract, + soroswap_router_contract, // factory_contract, soroswap_adapter_contract, // phoenix_adapter_contract, diff --git a/contracts/aggregator/src/test/events.rs b/contracts/aggregator/src/test/events.rs index b53b8ce4..1c9faca7 100644 --- a/contracts/aggregator/src/test/events.rs +++ b/contracts/aggregator/src/test/events.rs @@ -381,7 +381,7 @@ fn swap_tokens_for_exact_tokens_event() { let expected_amount_out = 5_000_000; let amount_in_should = test - .router_contract + .soroswap_router_contract .router_get_amounts_in(&expected_amount_out, &path) .get(0) .unwrap(); diff --git a/contracts/aggregator/src/test/phoenix_setup.rs b/contracts/aggregator/src/test/phoenix_setup.rs new file mode 100644 index 00000000..85978016 --- /dev/null +++ b/contracts/aggregator/src/test/phoenix_setup.rs @@ -0,0 +1,188 @@ + +// For Phoenix +mod phoenix_adapter { + soroban_sdk::contractimport!( + file = + "../target/wasm32-unknown-unknown/release/phoenix_adapter.optimized.wasm" + ); + pub type SoroswapAggregatorAdapterForPhoenixClient<'a> = Client<'a>; +} +use phoenix_adapter::SoroswapAggregatorAdapterForPhoenixClient; +use crate::test::install_token_wasm; +// Adapter for phoenix +pub fn create_phoenix_adapter<'a>(e: &Env) -> SoroswapAggregatorAdapterForPhoenixClient<'a> { + let adapter_address = &e.register_contract_wasm(None, phoenix_adapter::WASM); + let adapter = SoroswapAggregatorAdapterForPhoenixClient::new(e, adapter_address); + adapter +} + + +// #![cfg(test)] +// extern crate std; +use soroban_sdk::{ + vec, + // IntoVal, + String, + Env, + Bytes, + BytesN, + Address, + testutils::{ + arbitrary::std, + Address as _, + }, +}; + +/* ************* PHOENIX FACTORY ************* */ + +#[allow(clippy::too_many_arguments)] +pub mod factory { + soroban_sdk::contractimport!( + file = "../adapters/phoenix/phoenix_contracts/phoenix_factory.wasm" + ); +} +use factory::{LiquidityPoolInitInfo, StakeInitInfo, TokenInitInfo}; + +pub fn deploy_factory_contract(e: &Env, admin: & Address) -> Address { + let factory_wasm = e.deployer().upload_contract_wasm(factory::WASM); + let salt = Bytes::new(&e.clone()); + let salt = e.crypto().sha256(&salt); + + e.deployer().with_address(admin.clone(), salt).deploy(factory_wasm) +} + +pub use factory::Client as PhoenixFactory; + +/* ************* MULTIHOP ************* */ +#[allow(clippy::too_many_arguments)] +pub mod multihop { + soroban_sdk::contractimport!(file = "../adapters/phoenix/phoenix_contracts/phoenix_multihop.wasm"); + pub type MultihopClient<'a> = Client<'a>; +} +pub use multihop::MultihopClient; + +pub fn install_multihop_wasm(env: &Env) -> BytesN<32> { + soroban_sdk::contractimport!( + file = "../adapters/phoenix/phoenix_contracts/phoenix_multihop.wasm" + ); + env.deployer().upload_contract_wasm(WASM) +} +pub fn deploy_multihop_contract<'a>( + env: &Env, + admin: impl Into>, + factory: &Address, +) -> MultihopClient<'a> { + let admin = admin.into().unwrap_or(Address::generate(env)); + + let multihop_address = &env.register_contract_wasm(None, multihop::WASM); + let multihop = MultihopClient::new(env, multihop_address); + + multihop.initialize(&admin, factory); + multihop +} + +/* ************* LP CONTRACT ************* */ + +#[allow(clippy::too_many_arguments)] +pub mod lp_contract { + soroban_sdk::contractimport!( + file = "../adapters/phoenix/phoenix_contracts/phoenix_pool.wasm" + ); +} + +pub fn install_lp_contract(env: &Env) -> BytesN<32> { + env.deployer().upload_contract_wasm(lp_contract::WASM) +} + + +/* ************* STAKE ************* */ + +#[allow(clippy::too_many_arguments)] +pub fn install_stake_wasm(env: &Env) -> BytesN<32> { + soroban_sdk::contractimport!( + file = "../adapters/phoenix/phoenix_contracts/phoenix_stake.wasm" + ); + env.deployer().upload_contract_wasm(WASM) +} + + + +pub fn deploy_and_initialize_factory<'a>(env: &Env, admin: Address) -> PhoenixFactory<'a> { + let factory_addr = deploy_factory_contract(&env, &admin.clone()); + let factory_client = PhoenixFactory::new(env, &factory_addr); + let multihop_wasm_hash = install_multihop_wasm(env); + let whitelisted_accounts = vec![env, admin.clone()]; + + let lp_wasm_hash = install_lp_contract(env); + let stake_wasm_hash = install_stake_wasm(env); + let token_wasm_hash = install_token_wasm(env); + + factory_client.initialize( + &admin.clone(), + &multihop_wasm_hash, + &lp_wasm_hash, + &stake_wasm_hash, + &token_wasm_hash, + &whitelisted_accounts, + &10u32, + ); + factory_client +} + +#[allow(clippy::too_many_arguments)] +pub fn deploy_and_initialize_lp( + env: &Env, + factory: &PhoenixFactory, + admin: Address, + mut token_a: Address, + mut token_a_amount: i128, + mut token_b: Address, + mut token_b_amount: i128, + fees: Option, +) { + // 2. create liquidity pool from factory + + if token_b < token_a { + std::mem::swap(&mut token_a, &mut token_b); + std::mem::swap(&mut token_a_amount, &mut token_b_amount); + } + + let token_init_info = TokenInitInfo { + token_a: token_a.clone(), + token_b: token_b.clone(), + }; + let stake_init_info = StakeInitInfo { + min_bond: 10i128, + min_reward: 5i128, + manager: Address::generate(env), + max_complexity: 10u32, + }; + + let lp_init_info = LiquidityPoolInitInfo { + admin: admin.clone(), + fee_recipient: admin.clone(), + max_allowed_slippage_bps: 5000, + max_allowed_spread_bps: 500, + swap_fee_bps: fees.unwrap_or(0i64), + max_referral_bps: 5_000, + token_init_info, + stake_init_info, + }; + + let lp = factory.create_liquidity_pool( + &admin.clone(), + &lp_init_info, + &String::from_str(env, "Pool"), + &String::from_str(env, "PHO/XLM"), + ); + + let lp_client = lp_contract::Client::new(env, &lp); + lp_client.provide_liquidity( + &admin.clone(), + &Some(token_a_amount), + &None, + &Some(token_b_amount), + &None, + &None::, + ); +} diff --git a/contracts/aggregator/src/test/swap_tokens_for_exact_tokens.rs b/contracts/aggregator/src/test/swap_tokens_for_exact_tokens.rs index e2f22d77..611e4f85 100644 --- a/contracts/aggregator/src/test/swap_tokens_for_exact_tokens.rs +++ b/contracts/aggregator/src/test/swap_tokens_for_exact_tokens.rs @@ -258,7 +258,7 @@ fn swap_tokens_for_exact_tokens_excessive_input_amount() { let expected_amount_out = 5_000_000; let amount_in_should = test - .router_contract + .soroswap_router_contract .router_get_amounts_in(&expected_amount_out, &path) .get(0) .unwrap(); @@ -299,7 +299,7 @@ fn swap_tokens_for_exact_tokens_succeed_correctly_one_protocol() { let expected_amount_out = 5_000_000; let amount_in_should = test - .router_contract + .soroswap_router_contract .router_get_amounts_in(&expected_amount_out, &path) .get(0) .unwrap(); From 9a07ebefc00e2dc795f0f3a08e5669919b08e965 Mon Sep 17 00:00:00 2001 From: esteblock Date: Fri, 19 Jul 2024 16:19:07 +0200 Subject: [PATCH 10/11] swap_exact_tokens_for_tokens_succeed_correctly_two_protocols --- contracts/aggregator/src/test.rs | 44 ++++--- .../aggregator/src/test/phoenix_setup.rs | 2 +- .../src/test/swap_exact_tokens_for_tokens.rs | 119 +++++++++++++++++- 3 files changed, 148 insertions(+), 17 deletions(-) diff --git a/contracts/aggregator/src/test.rs b/contracts/aggregator/src/test.rs index 64bc57bc..3468b98a 100644 --- a/contracts/aggregator/src/test.rs +++ b/contracts/aggregator/src/test.rs @@ -21,7 +21,8 @@ use phoenix_setup::{ create_phoenix_adapter, deploy_and_initialize_factory as phoenix_deploy_and_initialize_factory, deploy_and_initialize_lp as phoenix_deploy_and_initialize_lp, - deploy_multihop_contract as phoenix_deploy_multihop_contract + deploy_multihop_contract as phoenix_deploy_multihop_contract, + SoroswapAggregatorAdapterForPhoenixClient }; // SoroswapAggregator Contract [THE MAIN CONTRACT] @@ -56,6 +57,21 @@ pub fn create_protocols_addresses(test: &SoroswapAggregatorTest) -> Vec protocol_id: String::from_str(&test.env, "soroswap"), address: test.soroswap_adapter_contract.address.clone(), paused: false, + } + ] +} +pub fn create_soroswap_phoenix_addresses(test: &SoroswapAggregatorTest) -> Vec { + vec![ + &test.env, + Adapter { + protocol_id: String::from_str(&test.env, "soroswap"), + address: test.soroswap_adapter_contract.address.clone(), + paused: false, + }, + Adapter { + protocol_id: String::from_str(&test.env, "phoenix"), + address: test.phoenix_adapter_contract.address.clone(), + paused: false, }, ] } @@ -93,9 +109,9 @@ pub struct SoroswapAggregatorTest<'a> { env: Env, aggregator_contract: SoroswapAggregatorClient<'a>, soroswap_router_contract: SoroswapRouterClient<'a>, - // factory_contract: SoroswapFactoryClient<'a>, + // soroswap_factory_contract: SoroswapFactoryClient<'a>, soroswap_adapter_contract: SoroswapAggregatorAdapterForSoroswapClient<'a>, - // phoenix_adapter_contract: SoroswapAggregatorAdapterForPhoenixClient<'a>, + phoenix_adapter_contract: SoroswapAggregatorAdapterForPhoenixClient<'a>, token_0: TokenClient<'a>, token_1: TokenClient<'a>, token_2: TokenClient<'a>, @@ -135,8 +151,8 @@ impl<'a> SoroswapAggregatorTest<'a> { /************************************************/ env.budget().reset_unlimited(); let soroswap_router_contract = create_soroswap_router(&env); - let factory_contract = create_soroswap_factory(&env, &admin); - soroswap_router_contract.initialize(&factory_contract.address); + let soroswap_factory_contract = create_soroswap_factory(&env, &admin); + soroswap_router_contract.initialize(&soroswap_factory_contract.address); let ledger_timestamp = 100; let desired_deadline = 1000; @@ -157,7 +173,7 @@ impl<'a> SoroswapAggregatorTest<'a> { assert_eq!( - factory_contract.pair_exists(&token_0.address, &token_1.address), + soroswap_factory_contract.pair_exists(&token_0.address, &token_1.address), false ); let (added_token_0_0, added_token_1_0, added_liquidity_0_1) = soroswap_router_contract @@ -213,9 +229,9 @@ impl<'a> SoroswapAggregatorTest<'a> { &phoenix_factory_client, admin.clone(), token_0.address.clone(), - 1_000_000, + 1_000_000_000_000_000_000, token_1.address.clone(), - 1_000_000, + 1_000_000_000_000_000_000, None, ); phoenix_deploy_and_initialize_lp( @@ -223,9 +239,9 @@ impl<'a> SoroswapAggregatorTest<'a> { &phoenix_factory_client, admin.clone(), token_1.address.clone(), - 1_000_000, + 1_000_000_000_000_000_000, token_2.address.clone(), - 1_000_000, + 1_000_000_000_000_000_000, None, ); phoenix_deploy_and_initialize_lp( @@ -233,9 +249,9 @@ impl<'a> SoroswapAggregatorTest<'a> { &phoenix_factory_client, admin.clone(), token_2.address.clone(), - 1_000_000, + 1_000_000_000_000_000_000, token_3.address.clone(), - 1_000_000, + 1_000_000_000_000_000_000, None, ); @@ -264,9 +280,9 @@ impl<'a> SoroswapAggregatorTest<'a> { env, aggregator_contract, soroswap_router_contract, - // factory_contract, + // soroswap_factory_contract, soroswap_adapter_contract, - // phoenix_adapter_contract, + phoenix_adapter_contract, token_0, token_1, token_2, diff --git a/contracts/aggregator/src/test/phoenix_setup.rs b/contracts/aggregator/src/test/phoenix_setup.rs index 85978016..92581d00 100644 --- a/contracts/aggregator/src/test/phoenix_setup.rs +++ b/contracts/aggregator/src/test/phoenix_setup.rs @@ -7,7 +7,7 @@ mod phoenix_adapter { ); pub type SoroswapAggregatorAdapterForPhoenixClient<'a> = Client<'a>; } -use phoenix_adapter::SoroswapAggregatorAdapterForPhoenixClient; +pub use phoenix_adapter::SoroswapAggregatorAdapterForPhoenixClient; use crate::test::install_token_wasm; // Adapter for phoenix pub fn create_phoenix_adapter<'a>(e: &Env) -> SoroswapAggregatorAdapterForPhoenixClient<'a> { diff --git a/contracts/aggregator/src/test/swap_exact_tokens_for_tokens.rs b/contracts/aggregator/src/test/swap_exact_tokens_for_tokens.rs index 32a98a60..a5c85cd3 100644 --- a/contracts/aggregator/src/test/swap_exact_tokens_for_tokens.rs +++ b/contracts/aggregator/src/test/swap_exact_tokens_for_tokens.rs @@ -1,6 +1,6 @@ extern crate std; use crate::error::AggregatorError; -use crate::test::{create_protocols_addresses, SoroswapAggregatorTest}; +use crate::test::{create_protocols_addresses, SoroswapAggregatorTest, create_soroswap_phoenix_addresses}; use crate::DexDistribution; use soroban_sdk::{Address, String, Vec}; // use soroban_sdk::{ @@ -599,5 +599,120 @@ fn swap_exact_tokens_for_tokens_succeed_correctly_same_protocol_twice() { } #[test] fn swap_exact_tokens_for_tokens_succeed_correctly_two_protocols() { - todo!(); + let test = SoroswapAggregatorTest::setup(); + let deadline: u64 = test.env.ledger().timestamp() + 1000; + // Initialize aggregator + let initialize_aggregator_addresses = create_soroswap_phoenix_addresses(&test); + + test.aggregator_contract + .initialize(&test.admin, &initialize_aggregator_addresses); + + // call the function + // add one with part 1 and other with part 0 + let mut path: Vec
= Vec::new(&test.env); + path.push_back(test.token_0.address.clone()); + path.push_back(test.token_1.address.clone()); + let mut distribution_vec = Vec::new(&test.env); + + let distribution_0 = DexDistribution { + protocol_id: String::from_str(&test.env, "soroswap"), + path: path.clone(), + parts: 1, + }; + let distribution_1 = DexDistribution { + protocol_id: String::from_str(&test.env, "phoenix"), + path: path.clone(), + parts: 3, + }; + distribution_vec.push_back(distribution_0); + distribution_vec.push_back(distribution_1); + + let total_expected_amount_in = 123_456_789; + + // The total expected amount will come from 2 different trades: + // 123_456_789_i128 + // .checked_div(4) + // .unwrap() + // .checked_mul(1) + // .unwrap(); + let expected_amount_in_0 = 30864197; + let expected_amount_in_1 = 92592592;// total_expected_amount_in - expected_amount_in_0; + + // FOR SOROSWAP: + // reserve_0 = 1_000_000_000_000_000_000; + // reserve_1 = 4_000_000_000_000_000_000; + + // expected_amount_in_0 = 30864197 + // expected_amount_in_1 = 92592592 + + // swap 0 + // fee = ceil(30864197 * 3 /1000) = 92592.591 = 92593 // USE CEILING + // amount_in less fee = 30864197- 92593 = 30771604 + // out = (amount_in_less_fees*reserve_1)/(reserve_0 + amount_in_less_fees) = + // First out = (30771604*4000000000000000000)/(1000000000000000000 + 30771604) = + // 123086416000000000000000000 / 1000000000030771604 = 123086415.996212434 = 123086415 // no ceiling div + let expected_amount_out_0 = 123086415; + + // FOR PHOENIX WE EXPECT OUT THE SAME AS IN + let expected_amount_out_1 = 92592592; + + let total_expected_amount_out = expected_amount_out_0 + expected_amount_out_1; + + // if we just expect one unit more of the expected amount out, the function should fail with expected error + let result = test.aggregator_contract.try_swap_exact_tokens_for_tokens( + &test.token_0.address.clone(), + &test.token_1.address.clone(), + &total_expected_amount_in, + &(total_expected_amount_out + 1), + &distribution_vec, + &test.user.clone(), + &deadline, + ); + // compare the error + assert_eq!(result, Err(Ok(AggregatorError::InsufficientOutputAmount))); + + // check balance before + let user_balance_before_0 = test.token_0.balance(&test.user); + let user_balance_before_1 = test.token_1.balance(&test.user); + + // if we expect the exact amount out, the function should succeed + let success_result = test.aggregator_contract.swap_exact_tokens_for_tokens( + &test.token_0.address.clone(), + &test.token_1.address.clone(), + &total_expected_amount_in, + &total_expected_amount_out, + &distribution_vec, + &test.user.clone(), + &deadline, + ); + + // check balance after + let user_balance_after_0 = test.token_0.balance(&test.user); + let user_balance_after_1 = test.token_1.balance(&test.user); + + // compare + assert_eq!( + user_balance_after_0, + user_balance_before_0 - total_expected_amount_in + ); + assert_eq!( + user_balance_after_1, + user_balance_before_1 + total_expected_amount_out + ); + + // check the result vec + // the result vec in this case is a vec of 2 vecs with two elements, the amount 0 and amount 1 + let mut expected_soroswap_result: Vec = Vec::new(&test.env); + expected_soroswap_result.push_back(expected_amount_in_0); + expected_soroswap_result.push_back(expected_amount_out_0); + + let mut expected_phoenix_result: Vec = Vec::new(&test.env); + expected_phoenix_result.push_back(expected_amount_in_1); + expected_phoenix_result.push_back(expected_amount_out_1); + + let mut expected_result = Vec::new(&test.env); + expected_result.push_back(expected_soroswap_result); + expected_result.push_back(expected_phoenix_result); + + assert_eq!(success_result, expected_result); } From 735f88b48fd5433f859819d54b597bbb0846e146 Mon Sep 17 00:00:00 2001 From: esteblock Date: Fri, 19 Jul 2024 16:24:35 +0200 Subject: [PATCH 11/11] swap_tokens_for_exact_tokens_succeed_correctly_two_protocols --- .../src/test/swap_tokens_for_exact_tokens.rs | 122 ++++++++++++++++-- 1 file changed, 109 insertions(+), 13 deletions(-) diff --git a/contracts/aggregator/src/test/swap_tokens_for_exact_tokens.rs b/contracts/aggregator/src/test/swap_tokens_for_exact_tokens.rs index 611e4f85..2d218a4a 100644 --- a/contracts/aggregator/src/test/swap_tokens_for_exact_tokens.rs +++ b/contracts/aggregator/src/test/swap_tokens_for_exact_tokens.rs @@ -1,19 +1,8 @@ extern crate std; use crate::error::AggregatorError; -use crate::test::{create_protocols_addresses, SoroswapAggregatorTest}; +use crate::test::{create_protocols_addresses, SoroswapAggregatorTest, create_soroswap_phoenix_addresses}; use crate::DexDistribution; use soroban_sdk::{Address, String, Vec}; -// use soroban_sdk::{ -// vec, -// IntoVal, -// testutils::{ -// MockAuth, -// MockAuthInvoke, -// AuthorizedInvocation, -// AuthorizedFunction -// }, -// Symbol -// }; #[test] fn swap_tokens_for_exact_tokens_not_initialized() { @@ -556,5 +545,112 @@ fn swap_tokens_for_exact_tokens_succeed_correctly_same_protocol_twice() { #[test] fn swap_tokens_for_exact_tokens_succeed_correctly_two_protocols() { - todo!(); + let test = SoroswapAggregatorTest::setup(); + let deadline: u64 = test.env.ledger().timestamp() + 1000; + // Initialize aggregator + let initialize_aggregator_addresses = create_soroswap_phoenix_addresses(&test); + + test.aggregator_contract + .initialize(&test.admin, &initialize_aggregator_addresses); + + let mut path: Vec
= Vec::new(&test.env); + path.push_back(test.token_0.address.clone()); + path.push_back(test.token_1.address.clone()); + let mut distribution_vec = Vec::new(&test.env); + + let distribution_0 = DexDistribution { + protocol_id: String::from_str(&test.env, "soroswap"), + path: path.clone(), + parts: 1, + }; + let distribution_1 = DexDistribution { + protocol_id: String::from_str(&test.env, "phoenix"), + path: path.clone(), + parts: 3, + }; + distribution_vec.push_back(distribution_0); + distribution_vec.push_back(distribution_1); + + let total_expected_amount_out = 30_000_000; + + // The total expected amount will come from 2 different trades: + let expected_amount_out_0 = 7500000;//30_000_000_i128 + // .checked_div(4) + // .unwrap() + // .checked_mul(1) + // .unwrap(); + let expected_amount_out_1 = 22500000;//total_expected_amount_out - expected_amount_out_0; + + // swap 0 occurs with original reserves + // R0 = 1_000_000_000_000_000_000; + // R1 = 4_000_000_000_000_000_000; + // expected_amount_out_0 = 7500000 + // ceil((r_in*amount_out)*1000 / (r_out - amount_out))*997 + 1 + // (1_000_000_000_000_000_000*7500000)*1000 / ((4_000_000_000_000_000_000 - 7500000)*997) + 1 = + // (1000000000000000000*7500000)*1000 / ((4000000000000000000 - 7500000)*997) + 1 = + // CEIL(7500000000000000000000000000 / 3987999999992522500000 ) + 1 = + // CEIL (1880641.925780858) + 1 = 1880642 + 1 = 1880643 + let amount_in_should_0 = 1880643; + + // PHOENIX RETURNS THE SAME + let amount_in_should_1 = 22500000; + let total_amount_in_should = amount_in_should_0 + amount_in_should_1; + + // with just one unit less of total_amount_in_should, this will fail with expected error + // ExcessiveInputAmount + let result = test.aggregator_contract.try_swap_tokens_for_exact_tokens( + &test.token_0.address.clone(), + &test.token_1.address.clone(), + &total_expected_amount_out, + &(total_amount_in_should - 1), + &distribution_vec, + &test.user.clone(), + &deadline, + ); + + assert_eq!(result, Err(Ok(AggregatorError::ExcessiveInputAmount))); + + // however with the correct amount it should succeed + + let user_balance_before_0 = test.token_0.balance(&test.user); + let user_balance_before_1 = test.token_1.balance(&test.user); + + let success_result = test.aggregator_contract.swap_tokens_for_exact_tokens( + &test.token_0.address.clone(), + &test.token_1.address.clone(), + &total_expected_amount_out, + &total_amount_in_should, + &distribution_vec, + &test.user.clone(), + &deadline, + ); + // check new balances and compare with result + let user_balance_after_0 = test.token_0.balance(&test.user); + let user_balance_after_1 = test.token_1.balance(&test.user); + + assert_eq!( + user_balance_after_0, + user_balance_before_0 - total_amount_in_should + ); + assert_eq!( + user_balance_after_1, + user_balance_before_1 + total_expected_amount_out + ); + + let mut expected_soroswap_result_vec: Vec = Vec::new(&test.env); + let mut expected_phoenix_result_vec: Vec = Vec::new(&test.env); + + // first swap + expected_soroswap_result_vec.push_back(amount_in_should_0); + expected_soroswap_result_vec.push_back(expected_amount_out_0); + + // second swap + expected_phoenix_result_vec.push_back(amount_in_should_1); + expected_phoenix_result_vec.push_back(expected_amount_out_1); + + let mut expected_result = Vec::new(&test.env); + expected_result.push_back(expected_soroswap_result_vec); + expected_result.push_back(expected_phoenix_result_vec); + + assert_eq!(success_result, expected_result); }