From c496c9a46b419415dc4b67a06e0afeaaed5b7b9a Mon Sep 17 00:00:00 2001 From: coderipper Date: Mon, 20 Jan 2025 11:44:17 -0300 Subject: [PATCH 1/9] added limit tests, found limit for n strategies hodl and fixed --- apps/contracts/integration-test/src/setup.rs | 2 +- apps/contracts/integration-test/src/test.rs | 1 + .../src/test/limits/asset_n_strategies.rs | 243 ++++++++++++++++++ .../integration-test/src/test/limits/mod.rs | 16 ++ 4 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs create mode 100644 apps/contracts/integration-test/src/test/limits/mod.rs diff --git a/apps/contracts/integration-test/src/setup.rs b/apps/contracts/integration-test/src/setup.rs index e27aa17a..e35d7dce 100644 --- a/apps/contracts/integration-test/src/setup.rs +++ b/apps/contracts/integration-test/src/setup.rs @@ -3,7 +3,7 @@ use soroban_sdk::{ }; mod soroswap_setup; -use soroswap_setup::{ +pub use soroswap_setup::{ create_soroswap_factory, create_soroswap_router }; use crate::factory::{AssetStrategySet, Strategy}; diff --git a/apps/contracts/integration-test/src/test.rs b/apps/contracts/integration-test/src/test.rs index 778a5d97..8cfdb357 100644 --- a/apps/contracts/integration-test/src/test.rs +++ b/apps/contracts/integration-test/src/test.rs @@ -100,3 +100,4 @@ impl<'a> IntegrationTest<'a> { // #[cfg(test)] mod vault_one_fixed_strategy; mod vault_one_hodl_strategy; +mod limits; \ No newline at end of file diff --git a/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs b/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs new file mode 100644 index 00000000..dae4ad79 --- /dev/null +++ b/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs @@ -0,0 +1,243 @@ +use soroban_sdk::{testutils::{Address as _, Ledger, MockAuth, MockAuthInvoke}, vec as svec, xdr::ContractCostType, Address, BytesN, IntoVal, Map, String, Vec}; + +use crate::{factory::{AssetStrategySet, Strategy}, fixed_strategy::{create_fixed_strategy_contract, FixedStrategyClient}, hodl_strategy::create_hodl_strategy_contract, setup::{create_soroswap_factory, create_soroswap_router, create_vault_one_asset_hodl_strategy, mock_mint, VAULT_FEE}, test::{limits::{check_limits, CPU_LIMIT, MEM_LIMIT}, EnvTestUtils, IntegrationTest, DAY_IN_LEDGERS, ONE_YEAR_IN_SECONDS}, token::create_token, vault::{defindex_vault_contract::{Instruction, VaultContractClient}, MINIMUM_LIQUIDITY}}; + +// 26 strategies is the maximum number of strategies that can be added to a vault before exceeding the instructions limit IN RUST TESTS +// With 26 strategies withdrawals are not possible due to the instruction limit +// 13 strategies is the maximum including withdrawals +#[test] +fn asset_n_strategies_hodl() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + setup.env.budget().reset_unlimited(); + + let token_admin = Address::generate(&setup.env); + let (token, token_admin_client) = create_token(&setup.env, &token_admin); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let manager = Address::generate(&setup.env); + + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "MultiStrategyVault"); + let vault_symbol = String::from_str(&setup.env, "MSVLT"); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let mut strategies = svec![&setup.env]; + let num_strategies = 13; // CHANGE THIS IF U NEED TO TEST OTHER NUMBER OF STRATEGIES + + for i in 0..num_strategies { + let strategy_name = format!("Strategy_{}", i); + let strategy_contract = create_hodl_strategy_contract(&setup.env, &token.address); + strategies.push_back(Strategy { + address: strategy_contract.address.clone(), + name: String::from_str(&setup.env, &strategy_name), + paused: false, + }); + } + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: token.address.clone(), + strategies: strategies.clone(), + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + setup.env.budget().reset_unlimited(); + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true, + ); + check_limits(&setup.env, "Create Vault"); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + // User deposit + let user_starting_balance = 10000000_0_000_000i128; + let users = IntegrationTest::generate_random_users(&setup.env, 1); + let user = &users[0]; + token_admin_client.mint(user, &user_starting_balance); + + let deposit_amount = 100000_0_000_000i128; + setup.env.budget().reset_unlimited(); + vault_contract.deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); + check_limits(&setup.env, "Deposit"); + + // Prepare rebalance instructions for all strategies + let mut invest_instructions = svec![&setup.env]; + for i in 0..num_strategies { + invest_instructions.push_back(Instruction::Invest( + strategies.get(i).unwrap().address.clone(), + deposit_amount / num_strategies as i128, + )); + } + + let invest_instructions = invest_instructions; + + // Rebalance + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &invest_instructions); + check_limits(&setup.env, "Invest"); + + setup.env.jump(DAY_IN_LEDGERS * 7); + + // Simulate a user withdrawal touching all strategies + setup.env.budget().reset_unlimited(); + let balance = vault_contract.balance(&user); + vault_contract.withdraw(&balance, &user); + check_limits(&setup.env, "Withdraw"); +} + +// FIXED Strategy limit is 10 including withdrawals in RUST +#[test] +fn asset_n_strategies_fixed() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + setup.env.budget().reset_unlimited(); + + let token_admin = Address::generate(&setup.env); + let (token, token_admin_client) = create_token(&setup.env, &token_admin); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let manager = Address::generate(&setup.env); + + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "MultiStrategyVault"); + let vault_symbol = String::from_str(&setup.env, "MSVLT"); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let mut strategies = svec![&setup.env]; + let num_strategies = 11; // CHANGE THIS IF U NEED TO TEST OTHER NUMBER OF STRATEGIES + + for i in 0..num_strategies { + let strategy_name = format!("Strategy_{}", i); + let strategy_contract = create_fixed_strategy_contract(&setup.env, &token.address, 1000u32, &token_admin_client); + strategies.push_back(Strategy { + address: strategy_contract.address.clone(), + name: String::from_str(&setup.env, &strategy_name), + paused: false, + }); + } + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: token.address.clone(), + strategies: strategies.clone(), + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + setup.env.budget().reset_unlimited(); + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true, + ); + check_limits(&setup.env, "Create Vault"); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + // User deposit + let user_starting_balance = 10000000_0_000_000i128; + let users = IntegrationTest::generate_random_users(&setup.env, 1); + let user = &users[0]; + token_admin_client.mint(user, &user_starting_balance); + + let deposit_amount = 100000_0_000_000i128; + setup.env.budget().reset_unlimited(); + vault_contract.deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); + check_limits(&setup.env, "Deposit"); + + // Prepare rebalance instructions for all strategies + let mut invest_instructions = svec![&setup.env]; + for i in 0..num_strategies { + invest_instructions.push_back(Instruction::Invest( + strategies.get(i).unwrap().address.clone(), + deposit_amount / num_strategies as i128, + )); + } + + let invest_instructions = invest_instructions; + + // Rebalance + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &invest_instructions); + check_limits(&setup.env, "Invest"); + + setup.env.jump(DAY_IN_LEDGERS * 7); + + // harvest on all strategies + for i in 0..num_strategies { + setup.env.budget().reset_unlimited(); + let temp_strategy_address = strategies.get(i).unwrap().address.clone(); + let temp_client = FixedStrategyClient::new(&setup.env, &temp_strategy_address); + + temp_client.harvest(&manager); + check_limits(&setup.env, "Harvest"); + } + + setup.env.budget().reset_unlimited(); + vault_contract.distribute_fees(); + check_limits(&setup.env, "Distribute Fees"); + + // Simulate a user withdrawal touching all strategies + setup.env.budget().reset_unlimited(); + let balance = vault_contract.balance(&user); + vault_contract.withdraw(&balance, &user); + check_limits(&setup.env, "Withdraw"); +} \ No newline at end of file diff --git a/apps/contracts/integration-test/src/test/limits/mod.rs b/apps/contracts/integration-test/src/test/limits/mod.rs new file mode 100644 index 00000000..88401abc --- /dev/null +++ b/apps/contracts/integration-test/src/test/limits/mod.rs @@ -0,0 +1,16 @@ +use soroban_sdk::Env; + +mod asset_n_strategies; + +pub const CPU_LIMIT: u64 = 100000000; +pub const MEM_LIMIT: u64 = 41943040; + +pub fn check_limits(e: &Env, name: &str) { + let cpu_used = e.budget().cpu_instruction_cost(); + let mem_used = e.budget().memory_bytes_cost(); + println!("{} CPU Instructions: {:?}", name, cpu_used); + println!("{} MEMORY: {:?}", name, mem_used); + println!("==========================================="); + assert!(cpu_used <= CPU_LIMIT, "CPU instructions exceeded limit"); + assert!(mem_used <= MEM_LIMIT, "Memory usage exceeded limit"); +} \ No newline at end of file From c526384605febf05a4b75779bd0da5d374707979 Mon Sep 17 00:00:00 2001 From: coderipper Date: Mon, 20 Jan 2025 12:40:07 -0300 Subject: [PATCH 2/9] added blend test --- .../src/test/limits/asset_n_strategies.rs | 242 +++++++++++++++++- 1 file changed, 241 insertions(+), 1 deletion(-) diff --git a/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs b/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs index dae4ad79..080d9b8b 100644 --- a/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs +++ b/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs @@ -1,6 +1,6 @@ use soroban_sdk::{testutils::{Address as _, Ledger, MockAuth, MockAuthInvoke}, vec as svec, xdr::ContractCostType, Address, BytesN, IntoVal, Map, String, Vec}; -use crate::{factory::{AssetStrategySet, Strategy}, fixed_strategy::{create_fixed_strategy_contract, FixedStrategyClient}, hodl_strategy::create_hodl_strategy_contract, setup::{create_soroswap_factory, create_soroswap_router, create_vault_one_asset_hodl_strategy, mock_mint, VAULT_FEE}, test::{limits::{check_limits, CPU_LIMIT, MEM_LIMIT}, EnvTestUtils, IntegrationTest, DAY_IN_LEDGERS, ONE_YEAR_IN_SECONDS}, token::create_token, vault::{defindex_vault_contract::{Instruction, VaultContractClient}, MINIMUM_LIQUIDITY}}; +use crate::{blend_strategy::{create_blend_strategy_contract, BlendStrategyClient}, factory::{AssetStrategySet, Strategy}, fixed_strategy::{create_fixed_strategy_contract, FixedStrategyClient}, hodl_strategy::create_hodl_strategy_contract, setup::{blend_setup::{create_blend_pool, BlendFixture, BlendPoolClient, Request}, create_soroswap_factory, create_soroswap_pool, create_soroswap_router, create_vault_one_asset_hodl_strategy, mock_mint, VAULT_FEE}, test::{limits::{check_limits, CPU_LIMIT, MEM_LIMIT}, EnvTestUtils, IntegrationTest, DAY_IN_LEDGERS, ONE_YEAR_IN_SECONDS}, token::create_token, vault::{defindex_vault_contract::{Instruction, VaultContractClient}, MINIMUM_LIQUIDITY}}; // 26 strategies is the maximum number of strategies that can be added to a vault before exceeding the instructions limit IN RUST TESTS // With 26 strategies withdrawals are not possible due to the instruction limit @@ -240,4 +240,244 @@ fn asset_n_strategies_fixed() { let balance = vault_contract.balance(&user); vault_contract.withdraw(&balance, &user); check_limits(&setup.env, "Withdraw"); +} + +#[test] +fn asset_n_strategies_blend() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let admin = Address::generate(&setup.env); + + let (blnd, blnd_client) = create_token(&setup.env, &admin); + let (usdc, usdc_client) = create_token(&setup.env, &admin); + let (xlm, xlm_client) = create_token(&setup.env, &admin); + + // Setting up soroswap pool + let pool_admin = Address::generate(&setup.env); + let amount_a = 100000000_0_000_000; + let amount_b = 50000000_0_000_000; + blnd_client.mint(&pool_admin, &amount_a); + usdc_client.mint(&pool_admin, &amount_b); + create_soroswap_pool( + &setup.env, + &soroswap_router, + &pool_admin, + &blnd.address, + &usdc.address, + &amount_a, + &amount_b, + ); + // End of setting up soroswap pool + + let blend_fixture = BlendFixture::deploy(&setup.env, &admin, &blnd.address, &usdc.address); + + let pool = create_blend_pool(&setup.env, &blend_fixture, &admin, &usdc_client, &xlm_client); + let pool_client = BlendPoolClient::new(&setup.env, &pool); + + let mut strategies = svec![&setup.env]; + let num_strategies = 3; // CHANGE THIS IF U NEED TO TEST OTHER NUMBER OF STRATEGIES + + for i in 0..num_strategies { + let strategy_name = format!("Blend_{}", i); + let strategy = create_blend_strategy_contract( + &setup.env, + &usdc.address, + &pool, + &0u32, + &blnd.address, + &soroswap_router.address, + ); + let strategy_contract = BlendStrategyClient::new(&setup.env, &strategy); + + strategies.push_back(Strategy { + address: strategy_contract.address.clone(), + name: String::from_str(&setup.env, &strategy_name), + paused: false, + }); + } + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "BlendVault"); + let vault_symbol = String::from_str(&setup.env, "BLNDVLT"); + let manager = Address::generate(&setup.env); + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: usdc.address.clone(), + strategies: strategies.clone(), + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + setup.env.budget().reset_unlimited(); + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true + ); + check_limits(&setup.env, "Create Vault"); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + let users = IntegrationTest::generate_random_users(&setup.env, 3); + + let starting_balance = 300_0000000; + usdc_client.mint(&users[0], &starting_balance); + usdc_client.mint(&users[1], &starting_balance); + + setup.env.budget().reset_unlimited(); + vault_contract.deposit( + &svec!(&setup.env, starting_balance.clone()), + &svec!(&setup.env, starting_balance.clone()), + &users[0], + &false + ); + check_limits(&setup.env, "Deposit"); + + setup.env.budget().reset_unlimited(); + vault_contract.deposit( + &svec!(&setup.env, starting_balance.clone()), + &svec!(&setup.env, starting_balance.clone()), + &users[1], + &false + ); + check_limits(&setup.env, "Deposit"); + + let mut invest_instructions = svec![&setup.env]; + for i in 0..num_strategies { + invest_instructions.push_back(Instruction::Invest( + strategies.get(i).unwrap().address.clone(), + starting_balance * 2 / num_strategies as i128, + )); + } + + let invest_instructions = invest_instructions; + + let report = vault_contract.report(); + println!("report = {:?}", report); + + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &invest_instructions); + check_limits(&setup.env, "Invest"); + + let report = vault_contract.report(); + println!("report = {:?}", report); + + // user_2 deposit directly into pool + let user_2_starting_balance = 200_0000000; + usdc_client.mint(&users[2], &user_2_starting_balance); + pool_client.submit( + &users[2], + &users[2], + &users[2], + &svec![ + &setup.env, + Request { + request_type: 0, + address: usdc.address.clone(), + amount: user_2_starting_balance, + }, + ], + ); + + + // admin borrow back to 50% util rate + let borrow_amount = (user_2_starting_balance + starting_balance * 2) / 2; + pool_client.submit( + &admin, + &admin, + &admin, + &svec![ + &setup.env, + Request { + request_type: 4, + address: usdc.address.clone(), + amount: borrow_amount, + }, + ], + ); + + let report = vault_contract.report(); + println!("report = {:?}", report); + /* + * Allow 1 week to pass + */ + setup.env.jump(DAY_IN_LEDGERS * 7); + + // pool_client.submit( + // &users[2], + // &users[2], + // &users[2], + // &svec![ + // &setup.env, + // Request { + // request_type: 1, + // address: usdc.address.clone(), + // amount: user_2_starting_balance * 2, + // }, + // ], + // ); + // let user_2_final_balance = usdc.balance(&users[2]); + // let user_2_profit = user_2_final_balance - user_2_starting_balance; + + // let expected_user_2_profit = user_2_profit / 2; + // let withdraw_amount = starting_balance + expected_user_2_profit; + + // std::println!("-- Harvesting --"); + // // harvest on all strategies + // for i in 0..num_strategies { + // setup.env.budget().reset_unlimited(); + // let temp_strategy_address = strategies.get(i).unwrap().address.clone(); + // let temp_client = FixedStrategyClient::new(&setup.env, &temp_strategy_address); + + // temp_client.harvest(&manager); + // check_limits(&setup.env, "Harvest"); + // } + + // let report = vault_contract.report(); + // println!("report = {:?}", report); + + // let lock_fees = vault_contract.lock_fees(&None); + // println!("locked_fees = {:?}", lock_fees); + + // println!("-- Distributing Fees --"); + // setup.env.budget().reset_unlimited(); + // vault_contract.distribute_fees(); + // check_limits(&setup.env, "Distribute Fees"); + + // setup.env.budget().reset_unlimited(); + // let balance = vault_contract.balance(&users[0]); + // vault_contract.withdraw(&balance, &users[0]); + // check_limits(&setup.env, "Withdraw"); + + // setup.env.budget().reset_unlimited(); + // let balance = vault_contract.balance(&users[1]); + // vault_contract.withdraw(&balance, &users[1]); + // check_limits(&setup.env, "Withdraw"); } \ No newline at end of file From 74f6adcec1ad51df02f0e3a0aaa2477e52e6d284 Mon Sep 17 00:00:00 2001 From: coderipper Date: Mon, 20 Jan 2025 12:52:04 -0300 Subject: [PATCH 3/9] Added blend strategy limit tests --- .../src/test/limits/asset_n_strategies.rs | 107 +++++++++--------- 1 file changed, 51 insertions(+), 56 deletions(-) diff --git a/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs b/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs index 080d9b8b..d52afed7 100644 --- a/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs +++ b/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs @@ -242,6 +242,7 @@ fn asset_n_strategies_fixed() { check_limits(&setup.env, "Withdraw"); } +// 2 Strategies is the limit for 1 asset and 2 Blend strategies #[test] fn asset_n_strategies_blend() { let setup = IntegrationTest::setup(); @@ -282,7 +283,7 @@ fn asset_n_strategies_blend() { let pool_client = BlendPoolClient::new(&setup.env, &pool); let mut strategies = svec![&setup.env]; - let num_strategies = 3; // CHANGE THIS IF U NEED TO TEST OTHER NUMBER OF STRATEGIES + let num_strategies = 2; // CHANGE THIS IF U NEED TO TEST OTHER NUMBER OF STRATEGIES for i in 0..num_strategies { let strategy_name = format!("Blend_{}", i); @@ -293,6 +294,7 @@ fn asset_n_strategies_blend() { &0u32, &blnd.address, &soroswap_router.address, + svec![&setup.env, 0u32, 1u32, 2u32, 3u32] ); let strategy_contract = BlendStrategyClient::new(&setup.env, &strategy); @@ -379,16 +381,10 @@ fn asset_n_strategies_blend() { let invest_instructions = invest_instructions; - let report = vault_contract.report(); - println!("report = {:?}", report); - setup.env.budget().reset_unlimited(); vault_contract.rebalance(&manager, &invest_instructions); check_limits(&setup.env, "Invest"); - let report = vault_contract.report(); - println!("report = {:?}", report); - // user_2 deposit directly into pool let user_2_starting_balance = 200_0000000; usdc_client.mint(&users[2], &user_2_starting_balance); @@ -430,54 +426,53 @@ fn asset_n_strategies_blend() { */ setup.env.jump(DAY_IN_LEDGERS * 7); - // pool_client.submit( - // &users[2], - // &users[2], - // &users[2], - // &svec![ - // &setup.env, - // Request { - // request_type: 1, - // address: usdc.address.clone(), - // amount: user_2_starting_balance * 2, - // }, - // ], - // ); - // let user_2_final_balance = usdc.balance(&users[2]); - // let user_2_profit = user_2_final_balance - user_2_starting_balance; - - // let expected_user_2_profit = user_2_profit / 2; - // let withdraw_amount = starting_balance + expected_user_2_profit; - - // std::println!("-- Harvesting --"); - // // harvest on all strategies - // for i in 0..num_strategies { - // setup.env.budget().reset_unlimited(); - // let temp_strategy_address = strategies.get(i).unwrap().address.clone(); - // let temp_client = FixedStrategyClient::new(&setup.env, &temp_strategy_address); + pool_client.submit( + &users[2], + &users[2], + &users[2], + &svec![ + &setup.env, + Request { + request_type: 1, + address: usdc.address.clone(), + amount: user_2_starting_balance * 2, + }, + ], + ); + let user_2_final_balance = usdc.balance(&users[2]); + let user_2_profit = user_2_final_balance - user_2_starting_balance; + + let expected_user_2_profit = user_2_profit / 2; + + std::println!("-- Harvesting --"); + // harvest on all strategies + for i in 0..num_strategies { + setup.env.budget().reset_unlimited(); + let temp_strategy_address = strategies.get(i).unwrap().address.clone(); + let temp_client = FixedStrategyClient::new(&setup.env, &temp_strategy_address); - // temp_client.harvest(&manager); - // check_limits(&setup.env, "Harvest"); - // } - - // let report = vault_contract.report(); - // println!("report = {:?}", report); - - // let lock_fees = vault_contract.lock_fees(&None); - // println!("locked_fees = {:?}", lock_fees); - - // println!("-- Distributing Fees --"); - // setup.env.budget().reset_unlimited(); - // vault_contract.distribute_fees(); - // check_limits(&setup.env, "Distribute Fees"); - - // setup.env.budget().reset_unlimited(); - // let balance = vault_contract.balance(&users[0]); - // vault_contract.withdraw(&balance, &users[0]); - // check_limits(&setup.env, "Withdraw"); - - // setup.env.budget().reset_unlimited(); - // let balance = vault_contract.balance(&users[1]); - // vault_contract.withdraw(&balance, &users[1]); - // check_limits(&setup.env, "Withdraw"); + temp_client.harvest(&manager); + check_limits(&setup.env, "Harvest"); + } + + let report = vault_contract.report(); + println!("report = {:?}", report); + + let lock_fees = vault_contract.lock_fees(&None); + println!("locked_fees = {:?}", lock_fees); + + println!("-- Distributing Fees --"); + setup.env.budget().reset_unlimited(); + vault_contract.distribute_fees(); + check_limits(&setup.env, "Distribute Fees"); + + setup.env.budget().reset_unlimited(); + let balance = vault_contract.balance(&users[0]); + vault_contract.withdraw(&balance, &users[0]); + check_limits(&setup.env, "Withdraw"); + + setup.env.budget().reset_unlimited(); + let balance = vault_contract.balance(&users[1]); + vault_contract.withdraw(&balance, &users[1]); + check_limits(&setup.env, "Withdraw"); } \ No newline at end of file From c0344eb7a1abccaebab606954c8dda5d1c9de28b Mon Sep 17 00:00:00 2001 From: coderipper Date: Tue, 21 Jan 2025 18:09:14 -0300 Subject: [PATCH 4/9] added rebalance limit tests --- .../src/test/limits/asset_n_strategies.rs | 471 +++++- .../integration-test/src/test/limits/mod.rs | 8 +- .../src/test/limits/n_asset_one_strategy.rs | 0 .../src/test/limits/rebalance.rs | 1492 +++++++++++++++++ 4 files changed, 1963 insertions(+), 8 deletions(-) create mode 100644 apps/contracts/integration-test/src/test/limits/n_asset_one_strategy.rs create mode 100644 apps/contracts/integration-test/src/test/limits/rebalance.rs diff --git a/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs b/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs index d52afed7..3cc10137 100644 --- a/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs +++ b/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs @@ -1,6 +1,6 @@ use soroban_sdk::{testutils::{Address as _, Ledger, MockAuth, MockAuthInvoke}, vec as svec, xdr::ContractCostType, Address, BytesN, IntoVal, Map, String, Vec}; -use crate::{blend_strategy::{create_blend_strategy_contract, BlendStrategyClient}, factory::{AssetStrategySet, Strategy}, fixed_strategy::{create_fixed_strategy_contract, FixedStrategyClient}, hodl_strategy::create_hodl_strategy_contract, setup::{blend_setup::{create_blend_pool, BlendFixture, BlendPoolClient, Request}, create_soroswap_factory, create_soroswap_pool, create_soroswap_router, create_vault_one_asset_hodl_strategy, mock_mint, VAULT_FEE}, test::{limits::{check_limits, CPU_LIMIT, MEM_LIMIT}, EnvTestUtils, IntegrationTest, DAY_IN_LEDGERS, ONE_YEAR_IN_SECONDS}, token::create_token, vault::{defindex_vault_contract::{Instruction, VaultContractClient}, MINIMUM_LIQUIDITY}}; +use crate::{blend_strategy::{create_blend_strategy_contract, BlendStrategyClient}, factory::{AssetStrategySet, Strategy}, fixed_strategy::{create_fixed_strategy_contract, FixedStrategyClient}, hodl_strategy::create_hodl_strategy_contract, setup::{blend_setup::{create_blend_pool, BlendFixture, BlendPoolClient, Request}, create_soroswap_factory, create_soroswap_pool, create_soroswap_router, create_vault_one_asset_hodl_strategy, mock_mint, VAULT_FEE}, test::{limits::check_limits, EnvTestUtils, IntegrationTest, DAY_IN_LEDGERS, ONE_YEAR_IN_SECONDS}, token::create_token, vault::{defindex_vault_contract::{Instruction, VaultContractClient}, MINIMUM_LIQUIDITY}}; // 26 strategies is the maximum number of strategies that can be added to a vault before exceeding the instructions limit IN RUST TESTS // With 26 strategies withdrawals are not possible due to the instruction limit @@ -100,7 +100,115 @@ fn asset_n_strategies_hodl() { )); } - let invest_instructions = invest_instructions; + // Rebalance + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &invest_instructions); + check_limits(&setup.env, "Invest"); + + setup.env.jump(DAY_IN_LEDGERS * 7); + + // Simulate a user withdrawal touching all strategies + setup.env.budget().reset_unlimited(); + let balance = vault_contract.balance(&user); + vault_contract.withdraw(&balance, &user); + check_limits(&setup.env, "Withdraw"); +} + +#[test] +#[should_panic(expected = "Memory usage exceeded limit")] +fn asset_n_strategies_hodl_panic() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + setup.env.budget().reset_unlimited(); + + let token_admin = Address::generate(&setup.env); + let (token, token_admin_client) = create_token(&setup.env, &token_admin); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let manager = Address::generate(&setup.env); + + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "MultiStrategyVault"); + let vault_symbol = String::from_str(&setup.env, "MSVLT"); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let mut strategies = svec![&setup.env]; + let num_strategies = 14; // CHANGE THIS IF U NEED TO TEST OTHER NUMBER OF STRATEGIES + + for i in 0..num_strategies { + let strategy_name = format!("Strategy_{}", i); + let strategy_contract = create_hodl_strategy_contract(&setup.env, &token.address); + strategies.push_back(Strategy { + address: strategy_contract.address.clone(), + name: String::from_str(&setup.env, &strategy_name), + paused: false, + }); + } + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: token.address.clone(), + strategies: strategies.clone(), + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + setup.env.budget().reset_unlimited(); + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true, + ); + check_limits(&setup.env, "Create Vault"); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + // User deposit + let user_starting_balance = 10000000_0_000_000i128; + let users = IntegrationTest::generate_random_users(&setup.env, 1); + let user = &users[0]; + token_admin_client.mint(user, &user_starting_balance); + + let deposit_amount = 100000_0_000_000i128; + setup.env.budget().reset_unlimited(); + vault_contract.deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); + check_limits(&setup.env, "Deposit"); + + // Prepare rebalance instructions for all strategies + let mut invest_instructions = svec![&setup.env]; + for i in 0..num_strategies { + invest_instructions.push_back(Instruction::Invest( + strategies.get(i).unwrap().address.clone(), + deposit_amount / num_strategies as i128, + )); + } // Rebalance setup.env.budget().reset_unlimited(); @@ -151,7 +259,7 @@ fn asset_n_strategies_fixed() { name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); let mut strategies = svec![&setup.env]; - let num_strategies = 11; // CHANGE THIS IF U NEED TO TEST OTHER NUMBER OF STRATEGIES + let num_strategies = 10; // CHANGE THIS IF U NEED TO TEST OTHER NUMBER OF STRATEGIES for i in 0..num_strategies { let strategy_name = format!("Strategy_{}", i); @@ -212,7 +320,129 @@ fn asset_n_strategies_fixed() { )); } - let invest_instructions = invest_instructions; + // Rebalance + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &invest_instructions); + check_limits(&setup.env, "Invest"); + + setup.env.jump(DAY_IN_LEDGERS * 7); + + // harvest on all strategies + for i in 0..num_strategies { + setup.env.budget().reset_unlimited(); + let temp_strategy_address = strategies.get(i).unwrap().address.clone(); + let temp_client = FixedStrategyClient::new(&setup.env, &temp_strategy_address); + + temp_client.harvest(&manager); + check_limits(&setup.env, "Harvest"); + } + + setup.env.budget().reset_unlimited(); + vault_contract.distribute_fees(); + check_limits(&setup.env, "Distribute Fees"); + + // Simulate a user withdrawal touching all strategies + setup.env.budget().reset_unlimited(); + let balance = vault_contract.balance(&user); + vault_contract.withdraw(&balance, &user); + check_limits(&setup.env, "Withdraw"); +} + +#[test] +#[should_panic(expected = "Memory usage exceeded limit")] +fn asset_n_strategies_fixed_panic() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + setup.env.budget().reset_unlimited(); + + let token_admin = Address::generate(&setup.env); + let (token, token_admin_client) = create_token(&setup.env, &token_admin); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let manager = Address::generate(&setup.env); + + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "MultiStrategyVault"); + let vault_symbol = String::from_str(&setup.env, "MSVLT"); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let mut strategies = svec![&setup.env]; + let num_strategies = 11; // CHANGE THIS IF U NEED TO TEST OTHER NUMBER OF STRATEGIES + + for i in 0..num_strategies { + let strategy_name = format!("Strategy_{}", i); + let strategy_contract = create_fixed_strategy_contract(&setup.env, &token.address, 1000u32, &token_admin_client); + strategies.push_back(Strategy { + address: strategy_contract.address.clone(), + name: String::from_str(&setup.env, &strategy_name), + paused: false, + }); + } + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: token.address.clone(), + strategies: strategies.clone(), + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + setup.env.budget().reset_unlimited(); + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true, + ); + check_limits(&setup.env, "Create Vault"); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + // User deposit + let user_starting_balance = 10000000_0_000_000i128; + let users = IntegrationTest::generate_random_users(&setup.env, 1); + let user = &users[0]; + token_admin_client.mint(user, &user_starting_balance); + + let deposit_amount = 100000_0_000_000i128; + setup.env.budget().reset_unlimited(); + vault_contract.deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); + check_limits(&setup.env, "Deposit"); + + // Prepare rebalance instructions for all strategies + let mut invest_instructions = svec![&setup.env]; + for i in 0..num_strategies { + invest_instructions.push_back(Instruction::Invest( + strategies.get(i).unwrap().address.clone(), + deposit_amount / num_strategies as i128, + )); + } // Rebalance setup.env.budget().reset_unlimited(); @@ -379,7 +609,238 @@ fn asset_n_strategies_blend() { )); } - let invest_instructions = invest_instructions; + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &invest_instructions); + check_limits(&setup.env, "Invest"); + + // user_2 deposit directly into pool + let user_2_starting_balance = 200_0000000; + usdc_client.mint(&users[2], &user_2_starting_balance); + pool_client.submit( + &users[2], + &users[2], + &users[2], + &svec![ + &setup.env, + Request { + request_type: 0, + address: usdc.address.clone(), + amount: user_2_starting_balance, + }, + ], + ); + + + // admin borrow back to 50% util rate + let borrow_amount = (user_2_starting_balance + starting_balance * 2) / 2; + pool_client.submit( + &admin, + &admin, + &admin, + &svec![ + &setup.env, + Request { + request_type: 4, + address: usdc.address.clone(), + amount: borrow_amount, + }, + ], + ); + + let report = vault_contract.report(); + println!("report = {:?}", report); + /* + * Allow 1 week to pass + */ + setup.env.jump(DAY_IN_LEDGERS * 7); + + pool_client.submit( + &users[2], + &users[2], + &users[2], + &svec![ + &setup.env, + Request { + request_type: 1, + address: usdc.address.clone(), + amount: user_2_starting_balance * 2, + }, + ], + ); + let user_2_final_balance = usdc.balance(&users[2]); + let user_2_profit = user_2_final_balance - user_2_starting_balance; + + let expected_user_2_profit = user_2_profit / 2; + + std::println!("-- Harvesting --"); + // harvest on all strategies + for i in 0..num_strategies { + setup.env.budget().reset_unlimited(); + let temp_strategy_address = strategies.get(i).unwrap().address.clone(); + let temp_client = FixedStrategyClient::new(&setup.env, &temp_strategy_address); + + temp_client.harvest(&manager); + check_limits(&setup.env, "Harvest"); + } + + let report = vault_contract.report(); + println!("report = {:?}", report); + + let lock_fees = vault_contract.lock_fees(&None); + println!("locked_fees = {:?}", lock_fees); + + println!("-- Distributing Fees --"); + setup.env.budget().reset_unlimited(); + vault_contract.distribute_fees(); + check_limits(&setup.env, "Distribute Fees"); + + setup.env.budget().reset_unlimited(); + let balance = vault_contract.balance(&users[0]); + vault_contract.withdraw(&balance, &users[0]); + check_limits(&setup.env, "Withdraw"); + + setup.env.budget().reset_unlimited(); + let balance = vault_contract.balance(&users[1]); + vault_contract.withdraw(&balance, &users[1]); + check_limits(&setup.env, "Withdraw"); +} + +#[test] +#[should_panic(expected = "CPU instructions exceeded limit")] +fn asset_n_strategies_blend_panic() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let admin = Address::generate(&setup.env); + + let (blnd, blnd_client) = create_token(&setup.env, &admin); + let (usdc, usdc_client) = create_token(&setup.env, &admin); + let (xlm, xlm_client) = create_token(&setup.env, &admin); + + // Setting up soroswap pool + let pool_admin = Address::generate(&setup.env); + let amount_a = 100000000_0_000_000; + let amount_b = 50000000_0_000_000; + blnd_client.mint(&pool_admin, &amount_a); + usdc_client.mint(&pool_admin, &amount_b); + create_soroswap_pool( + &setup.env, + &soroswap_router, + &pool_admin, + &blnd.address, + &usdc.address, + &amount_a, + &amount_b, + ); + // End of setting up soroswap pool + + let blend_fixture = BlendFixture::deploy(&setup.env, &admin, &blnd.address, &usdc.address); + + let pool = create_blend_pool(&setup.env, &blend_fixture, &admin, &usdc_client, &xlm_client); + let pool_client = BlendPoolClient::new(&setup.env, &pool); + + let mut strategies = svec![&setup.env]; + let num_strategies = 3; // CHANGE THIS IF U NEED TO TEST OTHER NUMBER OF STRATEGIES + + for i in 0..num_strategies { + let strategy_name = format!("Blend_{}", i); + let strategy = create_blend_strategy_contract( + &setup.env, + &usdc.address, + &pool, + &0u32, + &blnd.address, + &soroswap_router.address, + svec![&setup.env, 0u32, 1u32, 2u32, 3u32] + ); + let strategy_contract = BlendStrategyClient::new(&setup.env, &strategy); + + strategies.push_back(Strategy { + address: strategy_contract.address.clone(), + name: String::from_str(&setup.env, &strategy_name), + paused: false, + }); + } + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "BlendVault"); + let vault_symbol = String::from_str(&setup.env, "BLNDVLT"); + let manager = Address::generate(&setup.env); + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: usdc.address.clone(), + strategies: strategies.clone(), + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + setup.env.budget().reset_unlimited(); + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true + ); + check_limits(&setup.env, "Create Vault"); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + let users = IntegrationTest::generate_random_users(&setup.env, 3); + + let starting_balance = 300_0000000; + usdc_client.mint(&users[0], &starting_balance); + usdc_client.mint(&users[1], &starting_balance); + + setup.env.budget().reset_unlimited(); + vault_contract.deposit( + &svec!(&setup.env, starting_balance.clone()), + &svec!(&setup.env, starting_balance.clone()), + &users[0], + &false + ); + check_limits(&setup.env, "Deposit"); + + setup.env.budget().reset_unlimited(); + vault_contract.deposit( + &svec!(&setup.env, starting_balance.clone()), + &svec!(&setup.env, starting_balance.clone()), + &users[1], + &false + ); + check_limits(&setup.env, "Deposit"); + + let mut invest_instructions = svec![&setup.env]; + for i in 0..num_strategies { + invest_instructions.push_back(Instruction::Invest( + strategies.get(i).unwrap().address.clone(), + starting_balance * 2 / num_strategies as i128, + )); + } setup.env.budget().reset_unlimited(); vault_contract.rebalance(&manager, &invest_instructions); diff --git a/apps/contracts/integration-test/src/test/limits/mod.rs b/apps/contracts/integration-test/src/test/limits/mod.rs index 88401abc..d92f9fa6 100644 --- a/apps/contracts/integration-test/src/test/limits/mod.rs +++ b/apps/contracts/integration-test/src/test/limits/mod.rs @@ -1,15 +1,17 @@ use soroban_sdk::Env; mod asset_n_strategies; +mod rebalance; +mod n_asset_one_strategy; pub const CPU_LIMIT: u64 = 100000000; pub const MEM_LIMIT: u64 = 41943040; -pub fn check_limits(e: &Env, name: &str) { +pub fn check_limits(e: &Env, message: &str) { let cpu_used = e.budget().cpu_instruction_cost(); let mem_used = e.budget().memory_bytes_cost(); - println!("{} CPU Instructions: {:?}", name, cpu_used); - println!("{} MEMORY: {:?}", name, mem_used); + println!("{} CPU Instructions: {:?}", message, cpu_used); + println!("{} MEMORY: {:?}", message, mem_used); println!("==========================================="); assert!(cpu_used <= CPU_LIMIT, "CPU instructions exceeded limit"); assert!(mem_used <= MEM_LIMIT, "Memory usage exceeded limit"); diff --git a/apps/contracts/integration-test/src/test/limits/n_asset_one_strategy.rs b/apps/contracts/integration-test/src/test/limits/n_asset_one_strategy.rs new file mode 100644 index 00000000..e69de29b diff --git a/apps/contracts/integration-test/src/test/limits/rebalance.rs b/apps/contracts/integration-test/src/test/limits/rebalance.rs new file mode 100644 index 00000000..c6c5f7a3 --- /dev/null +++ b/apps/contracts/integration-test/src/test/limits/rebalance.rs @@ -0,0 +1,1492 @@ +use soroban_sdk::{testutils::Address as _, vec as svec, Address, BytesN, Map, String}; + +use crate::{blend_strategy::{create_blend_strategy_contract, BlendStrategyClient}, factory::{AssetStrategySet, Strategy}, fixed_strategy::create_fixed_strategy_contract, hodl_strategy::create_hodl_strategy_contract, setup::{blend_setup::{create_blend_pool, BlendFixture, BlendPoolClient}, create_soroswap_factory, create_soroswap_pool, create_soroswap_router, VAULT_FEE}, test::{EnvTestUtils, IntegrationTest, DAY_IN_LEDGERS}, token::create_token, vault::defindex_vault_contract::{Instruction, VaultContractClient}}; + +use super::check_limits; + +#[test] +fn asset_one_strategy_hodl_rebalance() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + setup.env.budget().reset_unlimited(); + + let token_admin = Address::generate(&setup.env); + let (token, token_admin_client) = create_token(&setup.env, &token_admin); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let manager = Address::generate(&setup.env); + + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "MultiStrategyVault"); + let vault_symbol = String::from_str(&setup.env, "MSVLT"); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let mut strategies = svec![&setup.env]; + + let strategy_contract = create_hodl_strategy_contract(&setup.env, &token.address); + strategies.push_back(Strategy { + address: strategy_contract.address.clone(), + name: String::from_str(&setup.env, "strategy_name"), + paused: false, + }); + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: token.address.clone(), + strategies: strategies.clone(), + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true, + ); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + // User deposit + let user_starting_balance = 10000000_0_000_000i128; + let users = IntegrationTest::generate_random_users(&setup.env, 1); + let user = &users[0]; + token_admin_client.mint(user, &user_starting_balance); + + let deposit_amount = 100000_0_000_000i128; + + vault_contract.deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); + + let num_investments = 29; + + // Prepare rebalance instructions for all strategies + let mut invest_instructions = svec![&setup.env]; + for _ in 0..num_investments { + invest_instructions.push_back(Instruction::Invest( + strategies.first().unwrap().address.clone(), + (deposit_amount - 1000) / num_investments as i128, + )); + } + + // Rebalance + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &invest_instructions); + check_limits(&setup.env, "Invest"); + + // Checking unwind limit + let balance_on_strategy = strategy_contract.balance(&vault_contract.address); + let num_unwinds = 29; + + let mut unwind_instructions = svec![&setup.env]; + for _ in 0..num_unwinds { + unwind_instructions.push_back(Instruction::Unwind( + strategies.first().unwrap().address.clone(), + (balance_on_strategy - 1000) / num_unwinds as i128, + )); + } + + // Rebalance + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &unwind_instructions); + check_limits(&setup.env, "Unwind"); +} + +#[test] +#[should_panic(expected = "Memory usage exceeded limit")] +fn asset_one_strategy_hodl_rebalance_panic_invest() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + setup.env.budget().reset_unlimited(); + + let token_admin = Address::generate(&setup.env); + let (token, token_admin_client) = create_token(&setup.env, &token_admin); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let manager = Address::generate(&setup.env); + + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "MultiStrategyVault"); + let vault_symbol = String::from_str(&setup.env, "MSVLT"); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let mut strategies = svec![&setup.env]; + + let strategy_contract = create_hodl_strategy_contract(&setup.env, &token.address); + strategies.push_back(Strategy { + address: strategy_contract.address.clone(), + name: String::from_str(&setup.env, "strategy_name"), + paused: false, + }); + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: token.address.clone(), + strategies: strategies.clone(), + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true, + ); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + // User deposit + let user_starting_balance = 10000000_0_000_000i128; + let users = IntegrationTest::generate_random_users(&setup.env, 1); + let user = &users[0]; + token_admin_client.mint(user, &user_starting_balance); + + let deposit_amount = 100000_0_000_000i128; + + vault_contract.deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); + + let num_investments = 30; + + // Prepare rebalance instructions for all strategies + let mut invest_instructions = svec![&setup.env]; + for _ in 0..num_investments { + invest_instructions.push_back(Instruction::Invest( + strategies.first().unwrap().address.clone(), + (deposit_amount - 1000) / num_investments as i128, + )); + } + + // Rebalance + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &invest_instructions); + check_limits(&setup.env, "Invest"); +} + +#[test] +#[should_panic(expected = "Memory usage exceeded limit")] +fn asset_one_strategy_hodl_rebalance_panic_unwind() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + setup.env.budget().reset_unlimited(); + + let token_admin = Address::generate(&setup.env); + let (token, token_admin_client) = create_token(&setup.env, &token_admin); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let manager = Address::generate(&setup.env); + + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "MultiStrategyVault"); + let vault_symbol = String::from_str(&setup.env, "MSVLT"); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let mut strategies = svec![&setup.env]; + + let strategy_contract = create_hodl_strategy_contract(&setup.env, &token.address); + strategies.push_back(Strategy { + address: strategy_contract.address.clone(), + name: String::from_str(&setup.env, "strategy_name"), + paused: false, + }); + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: token.address.clone(), + strategies: strategies.clone(), + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true, + ); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + // User deposit + let user_starting_balance = 10000000_0_000_000i128; + let users = IntegrationTest::generate_random_users(&setup.env, 1); + let user = &users[0]; + token_admin_client.mint(user, &user_starting_balance); + + let deposit_amount = 100000_0_000_000i128; + + vault_contract.deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); + + let num_investments = 30; + + // Prepare rebalance instructions for all strategies + let mut invest_instructions = svec![&setup.env]; + for _ in 0..num_investments { + invest_instructions.push_back(Instruction::Invest( + strategies.first().unwrap().address.clone(), + (deposit_amount - 1000) / num_investments as i128, + )); + } + + // Rebalance + vault_contract.rebalance(&manager, &invest_instructions); + + // Checking unwind limit + let balance_on_strategy = strategy_contract.balance(&vault_contract.address); + let num_unwinds = 30; + + let mut unwind_instructions = svec![&setup.env]; + for _ in 0..num_unwinds { + unwind_instructions.push_back(Instruction::Unwind( + strategies.first().unwrap().address.clone(), + (balance_on_strategy - 1000) / num_unwinds as i128, + )); + } + + // Rebalance + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &unwind_instructions); + check_limits(&setup.env, "Unwind"); +} + +#[test] +fn asset_one_strategy_fixed_rebalance() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + setup.env.budget().reset_unlimited(); + + let token_admin = Address::generate(&setup.env); + let (token, token_admin_client) = create_token(&setup.env, &token_admin); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let manager = Address::generate(&setup.env); + + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "MultiStrategyVault"); + let vault_symbol = String::from_str(&setup.env, "MSVLT"); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let mut strategies = svec![&setup.env]; + + let strategy_contract = create_fixed_strategy_contract(&setup.env, &token.address, 1000u32, &token_admin_client); + strategies.push_back(Strategy { + address: strategy_contract.address.clone(), + name: String::from_str(&setup.env, "strategy_name"), + paused: false, + }); + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: token.address.clone(), + strategies: strategies.clone(), + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true, + ); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + // User deposit + let user_starting_balance = 10000000_0_000_000i128; + let users = IntegrationTest::generate_random_users(&setup.env, 1); + let user = &users[0]; + token_admin_client.mint(user, &user_starting_balance); + + let deposit_amount = 100000_0_000_000i128; + vault_contract.deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); + + let num_investments = 24; + + // Prepare rebalance instructions for all strategies + let mut invest_instructions = svec![&setup.env]; + for _ in 0..num_investments { + invest_instructions.push_back(Instruction::Invest( + strategies.first().unwrap().address.clone(), + (deposit_amount - 1000) / num_investments as i128, + )); + } + + // Rebalance + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &invest_instructions); + check_limits(&setup.env, "Invest"); + + setup.env.jump(DAY_IN_LEDGERS * 7); + + // harvest on strategy + strategy_contract.harvest(&manager); + + vault_contract.report(); + vault_contract.lock_fees(&None); + vault_contract.distribute_fees(); + + let balance_on_strategy = strategy_contract.balance(&vault_contract.address); + let num_unwinds = 25; + + // Prepare rebalance instructions for all strategies + let mut unwind_instructions = svec![&setup.env]; + for _ in 0..num_unwinds { + unwind_instructions.push_back(Instruction::Unwind( + strategies.first().unwrap().address.clone(), + (balance_on_strategy - 1000) / num_unwinds as i128, + )); + } + + // Rebalance + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &unwind_instructions); + check_limits(&setup.env, "Unwind"); +} + +#[test] +#[should_panic(expected = "Memory usage exceeded limit")] +fn asset_one_strategy_fixed_rebalance_panic_invest() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + setup.env.budget().reset_unlimited(); + + let token_admin = Address::generate(&setup.env); + let (token, token_admin_client) = create_token(&setup.env, &token_admin); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let manager = Address::generate(&setup.env); + + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "MultiStrategyVault"); + let vault_symbol = String::from_str(&setup.env, "MSVLT"); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let mut strategies = svec![&setup.env]; + + let strategy_contract = create_fixed_strategy_contract(&setup.env, &token.address, 1000u32, &token_admin_client); + strategies.push_back(Strategy { + address: strategy_contract.address.clone(), + name: String::from_str(&setup.env, "strategy_name"), + paused: false, + }); + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: token.address.clone(), + strategies: strategies.clone(), + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true, + ); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + // User deposit + let user_starting_balance = 10000000_0_000_000i128; + let users = IntegrationTest::generate_random_users(&setup.env, 1); + let user = &users[0]; + token_admin_client.mint(user, &user_starting_balance); + + let deposit_amount = 100000_0_000_000i128; + vault_contract.deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); + + let num_investments = 25; + + // Prepare rebalance instructions for all strategies + let mut invest_instructions = svec![&setup.env]; + for _ in 0..num_investments { + invest_instructions.push_back(Instruction::Invest( + strategies.first().unwrap().address.clone(), + (deposit_amount - 1000) / num_investments as i128, + )); + } + + // Rebalance + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &invest_instructions); + check_limits(&setup.env, "Invest"); +} + +#[test] +#[should_panic(expected = "Memory usage exceeded limit")] +fn asset_one_strategy_fixed_rebalance_panic_unwind() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + setup.env.budget().reset_unlimited(); + + let token_admin = Address::generate(&setup.env); + let (token, token_admin_client) = create_token(&setup.env, &token_admin); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let manager = Address::generate(&setup.env); + + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "MultiStrategyVault"); + let vault_symbol = String::from_str(&setup.env, "MSVLT"); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let mut strategies = svec![&setup.env]; + + let strategy_contract = create_fixed_strategy_contract(&setup.env, &token.address, 1000u32, &token_admin_client); + strategies.push_back(Strategy { + address: strategy_contract.address.clone(), + name: String::from_str(&setup.env, "strategy_name"), + paused: false, + }); + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: token.address.clone(), + strategies: strategies.clone(), + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true, + ); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + // User deposit + let user_starting_balance = 10000000_0_000_000i128; + let users = IntegrationTest::generate_random_users(&setup.env, 1); + let user = &users[0]; + token_admin_client.mint(user, &user_starting_balance); + + let deposit_amount = 100000_0_000_000i128; + vault_contract.deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); + + let num_investments = 24; + + // Prepare rebalance instructions for all strategies + let mut invest_instructions = svec![&setup.env]; + for _ in 0..num_investments { + invest_instructions.push_back(Instruction::Invest( + strategies.first().unwrap().address.clone(), + (deposit_amount - 1000) / num_investments as i128, + )); + } + + // Rebalance + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &invest_instructions); + check_limits(&setup.env, "Invest"); + + setup.env.jump(DAY_IN_LEDGERS * 7); + + // harvest on strategy + strategy_contract.harvest(&manager); + + vault_contract.report(); + vault_contract.lock_fees(&None); + vault_contract.distribute_fees(); + + let balance_on_strategy = strategy_contract.balance(&vault_contract.address); + let num_unwinds = 26; + + // Prepare rebalance instructions for all strategies + let mut unwind_instructions = svec![&setup.env]; + for _ in 0..num_unwinds { + unwind_instructions.push_back(Instruction::Unwind( + strategies.first().unwrap().address.clone(), + (balance_on_strategy - 1000) / num_unwinds as i128, + )); + } + + // Rebalance + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &unwind_instructions); + check_limits(&setup.env, "Unwind"); +} + +#[test] +fn asset_one_strategy_blend_rebalance() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let admin = Address::generate(&setup.env); + + let (blnd, blnd_client) = create_token(&setup.env, &admin); + let (usdc, usdc_client) = create_token(&setup.env, &admin); + let (_, xlm_client) = create_token(&setup.env, &admin); + + // Setting up soroswap pool + let pool_admin = Address::generate(&setup.env); + let amount_a = 100000000_0_000_000; + let amount_b = 50000000_0_000_000; + blnd_client.mint(&pool_admin, &amount_a); + usdc_client.mint(&pool_admin, &amount_b); + create_soroswap_pool( + &setup.env, + &soroswap_router, + &pool_admin, + &blnd.address, + &usdc.address, + &amount_a, + &amount_b, + ); + // End of setting up soroswap pool + + let blend_fixture = BlendFixture::deploy(&setup.env, &admin, &blnd.address, &usdc.address); + + let pool = create_blend_pool(&setup.env, &blend_fixture, &admin, &usdc_client, &xlm_client); + + let mut strategies = svec![&setup.env]; + + let strategy = create_blend_strategy_contract( + &setup.env, + &usdc.address, + &pool, + &0u32, + &blnd.address, + &soroswap_router.address, + svec![&setup.env, 0u32, 1u32, 2u32, 3u32] + ); + let strategy_contract = BlendStrategyClient::new(&setup.env, &strategy); + + strategies.push_back(Strategy { + address: strategy_contract.address.clone(), + name: String::from_str(&setup.env, "strategy_name"), + paused: false, + }); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "BlendVault"); + let vault_symbol = String::from_str(&setup.env, "BLNDVLT"); + let manager = Address::generate(&setup.env); + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: usdc.address.clone(), + strategies: strategies.clone(), + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true + ); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + let users = IntegrationTest::generate_random_users(&setup.env, 3); + + let starting_balance = 300_0000000; + usdc_client.mint(&users[0], &starting_balance); + usdc_client.mint(&users[1], &starting_balance); + + vault_contract.deposit( + &svec!(&setup.env, starting_balance.clone()), + &svec!(&setup.env, starting_balance.clone()), + &users[0], + &false + ); + + vault_contract.deposit( + &svec!(&setup.env, starting_balance.clone()), + &svec!(&setup.env, starting_balance.clone()), + &users[1], + &false + ); + + let num_investments = 4; + + let mut invest_instructions = svec![&setup.env]; + for _ in 0..num_investments { + invest_instructions.push_back(Instruction::Invest( + strategies.first().unwrap().address.clone(), + (starting_balance * 2 - 1000) / num_investments as i128, + )); + } + + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &invest_instructions); + check_limits(&setup.env, "Invest"); + + let balance_on_strategy = strategy_contract.balance(&vault_contract.address); + let num_unwinds = 5; + + let mut unwinds_instructions = svec![&setup.env]; + for _ in 0..num_unwinds { + unwinds_instructions.push_back(Instruction::Unwind( + strategies.first().unwrap().address.clone(), + (balance_on_strategy - 1000) / num_unwinds as i128, + )); + } + + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &unwinds_instructions); + check_limits(&setup.env, "Unwind"); +} + +#[test] +#[should_panic(expected = "CPU instructions exceeded limit")] +fn asset_one_strategy_blend_rebalance_panic_invest() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let admin = Address::generate(&setup.env); + + let (blnd, blnd_client) = create_token(&setup.env, &admin); + let (usdc, usdc_client) = create_token(&setup.env, &admin); + let (_, xlm_client) = create_token(&setup.env, &admin); + + // Setting up soroswap pool + let pool_admin = Address::generate(&setup.env); + let amount_a = 100000000_0_000_000; + let amount_b = 50000000_0_000_000; + blnd_client.mint(&pool_admin, &amount_a); + usdc_client.mint(&pool_admin, &amount_b); + create_soroswap_pool( + &setup.env, + &soroswap_router, + &pool_admin, + &blnd.address, + &usdc.address, + &amount_a, + &amount_b, + ); + // End of setting up soroswap pool + + let blend_fixture = BlendFixture::deploy(&setup.env, &admin, &blnd.address, &usdc.address); + + let pool = create_blend_pool(&setup.env, &blend_fixture, &admin, &usdc_client, &xlm_client); + + let mut strategies = svec![&setup.env]; + + let strategy = create_blend_strategy_contract( + &setup.env, + &usdc.address, + &pool, + &0u32, + &blnd.address, + &soroswap_router.address, + svec![&setup.env, 0u32, 1u32, 2u32, 3u32] + ); + let strategy_contract = BlendStrategyClient::new(&setup.env, &strategy); + + strategies.push_back(Strategy { + address: strategy_contract.address.clone(), + name: String::from_str(&setup.env, "strategy_name"), + paused: false, + }); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "BlendVault"); + let vault_symbol = String::from_str(&setup.env, "BLNDVLT"); + let manager = Address::generate(&setup.env); + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: usdc.address.clone(), + strategies: strategies.clone(), + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true + ); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + let users = IntegrationTest::generate_random_users(&setup.env, 3); + + let starting_balance = 300_0000000; + usdc_client.mint(&users[0], &starting_balance); + usdc_client.mint(&users[1], &starting_balance); + + vault_contract.deposit( + &svec!(&setup.env, starting_balance.clone()), + &svec!(&setup.env, starting_balance.clone()), + &users[0], + &false + ); + + vault_contract.deposit( + &svec!(&setup.env, starting_balance.clone()), + &svec!(&setup.env, starting_balance.clone()), + &users[1], + &false + ); + + let num_investments = 5; + + let mut invest_instructions = svec![&setup.env]; + for _ in 0..num_investments { + invest_instructions.push_back(Instruction::Invest( + strategies.first().unwrap().address.clone(), + (starting_balance * 2 - 1000) / num_investments as i128, + )); + } + + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &invest_instructions); + check_limits(&setup.env, "Invest"); +} + +#[test] +#[should_panic(expected = "CPU instructions exceeded limit")] +fn asset_one_strategy_blend_rebalance_panic_unwind() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let admin = Address::generate(&setup.env); + + let (blnd, blnd_client) = create_token(&setup.env, &admin); + let (usdc, usdc_client) = create_token(&setup.env, &admin); + let (_, xlm_client) = create_token(&setup.env, &admin); + + // Setting up soroswap pool + let pool_admin = Address::generate(&setup.env); + let amount_a = 100000000_0_000_000; + let amount_b = 50000000_0_000_000; + blnd_client.mint(&pool_admin, &amount_a); + usdc_client.mint(&pool_admin, &amount_b); + create_soroswap_pool( + &setup.env, + &soroswap_router, + &pool_admin, + &blnd.address, + &usdc.address, + &amount_a, + &amount_b, + ); + // End of setting up soroswap pool + + let blend_fixture = BlendFixture::deploy(&setup.env, &admin, &blnd.address, &usdc.address); + + let pool = create_blend_pool(&setup.env, &blend_fixture, &admin, &usdc_client, &xlm_client); + + let mut strategies = svec![&setup.env]; + + let strategy = create_blend_strategy_contract( + &setup.env, + &usdc.address, + &pool, + &0u32, + &blnd.address, + &soroswap_router.address, + svec![&setup.env, 0u32, 1u32, 2u32, 3u32] + ); + let strategy_contract = BlendStrategyClient::new(&setup.env, &strategy); + + strategies.push_back(Strategy { + address: strategy_contract.address.clone(), + name: String::from_str(&setup.env, "strategy_name"), + paused: false, + }); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "BlendVault"); + let vault_symbol = String::from_str(&setup.env, "BLNDVLT"); + let manager = Address::generate(&setup.env); + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: usdc.address.clone(), + strategies: strategies.clone(), + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true + ); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + let users = IntegrationTest::generate_random_users(&setup.env, 3); + + let starting_balance = 300_0000000; + usdc_client.mint(&users[0], &starting_balance); + usdc_client.mint(&users[1], &starting_balance); + + vault_contract.deposit( + &svec!(&setup.env, starting_balance.clone()), + &svec!(&setup.env, starting_balance.clone()), + &users[0], + &false + ); + + vault_contract.deposit( + &svec!(&setup.env, starting_balance.clone()), + &svec!(&setup.env, starting_balance.clone()), + &users[1], + &false + ); + + let num_investments = 4; + + let mut invest_instructions = svec![&setup.env]; + for _ in 0..num_investments { + invest_instructions.push_back(Instruction::Invest( + strategies.first().unwrap().address.clone(), + (starting_balance * 2 - 1000) / num_investments as i128, + )); + } + + vault_contract.rebalance(&manager, &invest_instructions); + + let balance_on_strategy = strategy_contract.balance(&vault_contract.address); + let num_unwinds = 6; + + let mut unwinds_instructions = svec![&setup.env]; + for _ in 0..num_unwinds { + unwinds_instructions.push_back(Instruction::Unwind( + strategies.first().unwrap().address.clone(), + (balance_on_strategy - 1000) / num_unwinds as i128, + )); + } + + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &unwinds_instructions); + check_limits(&setup.env, "Unwind"); +} + +#[test] +fn two_assets_swap_limits_rebalance() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + setup.env.budget().reset_unlimited(); + + let token_admin = Address::generate(&setup.env); + let (xlm, xlm_client) = create_token(&setup.env, &token_admin); + let (usdc, usdc_client) = create_token(&setup.env, &token_admin); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + // Setting up soroswap pool + let pool_admin = Address::generate(&setup.env); + let amount_a = 100000000000_0_000_000; + let amount_b = 50000000000_0_000_000; + xlm_client.mint(&pool_admin, &amount_a); + usdc_client.mint(&pool_admin, &amount_b); + create_soroswap_pool( + &setup.env, + &soroswap_router, + &pool_admin, + &xlm.address, + &usdc.address, + &amount_a, + &amount_b, + ); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let manager = Address::generate(&setup.env); + + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "MultiStrategyVault"); + let vault_symbol = String::from_str(&setup.env, "MSVLT"); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let xlm_strategy_contract = create_hodl_strategy_contract(&setup.env, &xlm.address); + let usdc_strategy_contract = create_hodl_strategy_contract(&setup.env, &usdc.address); + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: xlm.address.clone(), + strategies: svec![&setup.env, Strategy { + address: xlm_strategy_contract.address.clone(), + name: String::from_str(&setup.env, "xlmStrat"), + paused: false, + }], + }, + AssetStrategySet { + address: usdc.address.clone(), + strategies: svec![&setup.env, Strategy { + address: usdc_strategy_contract.address.clone(), + name: String::from_str(&setup.env, "usdcStrat"), + paused: false, + }], + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true, + ); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + // User deposit + let xlm_starting_balance = 10000000_0_000_000i128; + let usdc_starting_balance = 5000000_0_000_000i128; + let users = IntegrationTest::generate_random_users(&setup.env, 1); + let user = &users[0]; + xlm_client.mint(user, &xlm_starting_balance); + usdc_client.mint(user, &usdc_starting_balance); + + vault_contract.deposit( + &svec![&setup.env, xlm_starting_balance, usdc_starting_balance], + &svec![&setup.env, xlm_starting_balance, usdc_starting_balance], + &user, + &false, + ); + + // Checking SWAP Limits + let usdc_balance_on_vault = usdc.balance(&vault_contract.address); + let num_exact_in = 5; + + let mut exact_in_instructions = svec![&setup.env]; + for _ in 0..num_exact_in { + exact_in_instructions.push_back(Instruction::SwapExactIn( + usdc.address.clone(), + xlm.address.clone(), + usdc_balance_on_vault / num_exact_in as i128, + 0, + setup.env.ledger().timestamp() + 3600u64, + )); + } + + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &exact_in_instructions); + check_limits(&setup.env, "SwapExactIn"); + + let num_exact_out = 5; + + let mut exact_out_instructions = svec![&setup.env]; + for _ in 0..num_exact_out { + exact_out_instructions.push_back(Instruction::SwapExactIn( + xlm.address.clone(), + usdc.address.clone(), + usdc_balance_on_vault / num_exact_out as i128, + 0, + setup.env.ledger().timestamp() + 3600u64, + )); + } + + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &exact_out_instructions); + check_limits(&setup.env, "SwapExactOut"); +} + +#[test] +#[should_panic(expected = "Memory usage exceeded limit")] +fn two_assets_swap_limits_rebalance_panic_exact_in() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + setup.env.budget().reset_unlimited(); + + let token_admin = Address::generate(&setup.env); + let (xlm, xlm_client) = create_token(&setup.env, &token_admin); + let (usdc, usdc_client) = create_token(&setup.env, &token_admin); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + // Setting up soroswap pool + let pool_admin = Address::generate(&setup.env); + let amount_a = 100000000000_0_000_000; + let amount_b = 50000000000_0_000_000; + xlm_client.mint(&pool_admin, &amount_a); + usdc_client.mint(&pool_admin, &amount_b); + create_soroswap_pool( + &setup.env, + &soroswap_router, + &pool_admin, + &xlm.address, + &usdc.address, + &amount_a, + &amount_b, + ); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let manager = Address::generate(&setup.env); + + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "MultiStrategyVault"); + let vault_symbol = String::from_str(&setup.env, "MSVLT"); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let xlm_strategy_contract = create_hodl_strategy_contract(&setup.env, &xlm.address); + let usdc_strategy_contract = create_hodl_strategy_contract(&setup.env, &usdc.address); + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: xlm.address.clone(), + strategies: svec![&setup.env, Strategy { + address: xlm_strategy_contract.address.clone(), + name: String::from_str(&setup.env, "xlmStrat"), + paused: false, + }], + }, + AssetStrategySet { + address: usdc.address.clone(), + strategies: svec![&setup.env, Strategy { + address: usdc_strategy_contract.address.clone(), + name: String::from_str(&setup.env, "usdcStrat"), + paused: false, + }], + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true, + ); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + // User deposit + let xlm_starting_balance = 10000000_0_000_000i128; + let usdc_starting_balance = 5000000_0_000_000i128; + let users = IntegrationTest::generate_random_users(&setup.env, 1); + let user = &users[0]; + xlm_client.mint(user, &xlm_starting_balance); + usdc_client.mint(user, &usdc_starting_balance); + + vault_contract.deposit( + &svec![&setup.env, xlm_starting_balance, usdc_starting_balance], + &svec![&setup.env, xlm_starting_balance, usdc_starting_balance], + &user, + &false, + ); + + // Checking SWAP Limits + let usdc_balance_on_vault = usdc.balance(&vault_contract.address); + let num_exact_in = 6; + + let mut exact_in_instructions = svec![&setup.env]; + for _ in 0..num_exact_in { + exact_in_instructions.push_back(Instruction::SwapExactIn( + usdc.address.clone(), + xlm.address.clone(), + usdc_balance_on_vault / num_exact_in as i128, + 0, + setup.env.ledger().timestamp() + 3600u64, + )); + } + + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &exact_in_instructions); + check_limits(&setup.env, "SwapExactIn"); +} + +#[test] +#[should_panic(expected = "Memory usage exceeded limit")] +fn two_assets_swap_limits_rebalance_panic_exact_out() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + setup.env.budget().reset_unlimited(); + + let token_admin = Address::generate(&setup.env); + let (xlm, xlm_client) = create_token(&setup.env, &token_admin); + let (usdc, usdc_client) = create_token(&setup.env, &token_admin); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + // Setting up soroswap pool + let pool_admin = Address::generate(&setup.env); + let amount_a = 100000000000_0_000_000; + let amount_b = 50000000000_0_000_000; + xlm_client.mint(&pool_admin, &amount_a); + usdc_client.mint(&pool_admin, &amount_b); + create_soroswap_pool( + &setup.env, + &soroswap_router, + &pool_admin, + &xlm.address, + &usdc.address, + &amount_a, + &amount_b, + ); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let manager = Address::generate(&setup.env); + + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "MultiStrategyVault"); + let vault_symbol = String::from_str(&setup.env, "MSVLT"); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let xlm_strategy_contract = create_hodl_strategy_contract(&setup.env, &xlm.address); + let usdc_strategy_contract = create_hodl_strategy_contract(&setup.env, &usdc.address); + + let assets = svec![ + &setup.env, + AssetStrategySet { + address: xlm.address.clone(), + strategies: svec![&setup.env, Strategy { + address: xlm_strategy_contract.address.clone(), + name: String::from_str(&setup.env, "xlmStrat"), + paused: false, + }], + }, + AssetStrategySet { + address: usdc.address.clone(), + strategies: svec![&setup.env, Strategy { + address: usdc_strategy_contract.address.clone(), + name: String::from_str(&setup.env, "usdcStrat"), + paused: false, + }], + } + ]; + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true, + ); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + // User deposit + let xlm_starting_balance = 10000000_0_000_000i128; + let usdc_starting_balance = 5000000_0_000_000i128; + let users = IntegrationTest::generate_random_users(&setup.env, 1); + let user = &users[0]; + xlm_client.mint(user, &xlm_starting_balance); + usdc_client.mint(user, &usdc_starting_balance); + + vault_contract.deposit( + &svec![&setup.env, xlm_starting_balance, usdc_starting_balance], + &svec![&setup.env, xlm_starting_balance, usdc_starting_balance], + &user, + &false, + ); + + // Checking SWAP Limits + let usdc_balance_on_vault = usdc.balance(&vault_contract.address); + let num_exact_in = 5; + + let mut exact_in_instructions = svec![&setup.env]; + for _ in 0..num_exact_in { + exact_in_instructions.push_back(Instruction::SwapExactIn( + usdc.address.clone(), + xlm.address.clone(), + usdc_balance_on_vault / num_exact_in as i128, + 0, + setup.env.ledger().timestamp() + 3600u64, + )); + } + + vault_contract.rebalance(&manager, &exact_in_instructions); + + let num_exact_out = 6; + + let mut exact_out_instructions = svec![&setup.env]; + for _ in 0..num_exact_out { + exact_out_instructions.push_back(Instruction::SwapExactIn( + xlm.address.clone(), + usdc.address.clone(), + usdc_balance_on_vault / num_exact_out as i128, + 0, + setup.env.ledger().timestamp() + 3600u64, + )); + } + + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &exact_out_instructions); + check_limits(&setup.env, "SwapExactOut"); +} \ No newline at end of file From 04a9d317c9d3fcb8dd62839340e0d43bf6c96704 Mon Sep 17 00:00:00 2001 From: coderipper Date: Tue, 21 Jan 2025 20:51:12 -0300 Subject: [PATCH 5/9] added n_asset_one strategy hodl tests --- .../src/test/limits/n_asset_one_strategy.rs | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/apps/contracts/integration-test/src/test/limits/n_asset_one_strategy.rs b/apps/contracts/integration-test/src/test/limits/n_asset_one_strategy.rs index e69de29b..d68d1cf5 100644 --- a/apps/contracts/integration-test/src/test/limits/n_asset_one_strategy.rs +++ b/apps/contracts/integration-test/src/test/limits/n_asset_one_strategy.rs @@ -0,0 +1,185 @@ +use soroban_sdk::{testutils::Address as _, vec as svec, Address, BytesN, Map, String}; +use crate::{blend_strategy::{create_blend_strategy_contract, BlendStrategyClient}, factory::{AssetStrategySet, Strategy}, fixed_strategy::{create_fixed_strategy_contract, FixedStrategyClient}, hodl_strategy::create_hodl_strategy_contract, setup::{blend_setup::{create_blend_pool, BlendFixture, BlendPoolClient}, create_soroswap_factory, create_soroswap_router, VAULT_FEE}, test::{limits::check_limits, EnvTestUtils, IntegrationTest, DAY_IN_LEDGERS}, token::create_token, vault::defindex_vault_contract::{Instruction, VaultContractClient}}; + +#[test] +fn n_assets_one_strategy_hodl() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + setup.env.budget().reset_unlimited(); + + let mut tokens = Vec::new(); + let mut token_clients = Vec::new(); + + let num_tokens = 12; + + for _ in 0..num_tokens { + let token_admin = Address::generate(&setup.env); + let (token, token_admin_client) = create_token(&setup.env, &token_admin); + tokens.push(token); + token_clients.push(token_admin_client); + } + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let manager = Address::generate(&setup.env); + + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "MultiStrategyVault"); + let vault_symbol = String::from_str(&setup.env, "MSVLT"); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let mut strategies = svec![&setup.env]; + + for i in 0..num_tokens { + let strategy_contract = create_hodl_strategy_contract(&setup.env, &tokens.get(i).unwrap().address); + strategies.push_back(Strategy { + address: strategy_contract.address.clone(), + name: String::from_str(&setup.env, "HodlStrategy"), + paused: false, + }); + } + + let mut assets = svec![&setup.env]; + for i in 0..num_tokens { + let token = tokens.get(i).unwrap(); + let strategy = strategies.get(i.try_into().unwrap()).unwrap(); + assets.push_back(AssetStrategySet { + address: token.address.clone(), + strategies: svec![&setup.env, strategy], + }); + } + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + setup.env.budget().reset_unlimited(); + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true, + ); + check_limits(&setup.env, "Create Vault"); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + // User deposit + let user_starting_balance = 10000000_0_000_000i128; + let users = IntegrationTest::generate_random_users(&setup.env, 1); + let user = &users[0]; + + let mut amounts_desired = svec![&setup.env]; + let mut amounts_min = svec![&setup.env]; + + for i in 0..num_tokens { + let token_admin_client = token_clients.get(i).unwrap(); + token_admin_client.mint(user, &user_starting_balance); + + let desired_amount = 10000000_0_000_000i128; + + amounts_desired.push_back(desired_amount); + amounts_min.push_back(desired_amount); + } + + setup.env.budget().reset_unlimited(); + vault_contract.deposit(&amounts_desired, &amounts_min, user, &false); + check_limits(&setup.env, "Deposit"); + + + // Prepare rebalance instructions for all strategies + let mut invest_instructions = svec![&setup.env]; + let batch_size = num_tokens / 2; + + for i in 0..batch_size { + invest_instructions.push_back(Instruction::Invest( + strategies.get(i.try_into().unwrap()).unwrap().address.clone(), + user_starting_balance, + )); + } + + // Rebalance first batch + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &invest_instructions); + check_limits(&setup.env, "Invest Batch 1"); + + let mut invest_instructions = svec![&setup.env]; + + for i in batch_size..num_tokens { + invest_instructions.push_back(Instruction::Invest( + strategies.get(i.try_into().unwrap()).unwrap().address.clone(), + user_starting_balance, + )); + } + + // Rebalance second batch + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &invest_instructions); + check_limits(&setup.env, "Invest Batch 2"); + + for i in 0..num_tokens { + let token = tokens.get(i).unwrap(); + let strategy = strategies.get(i.try_into().unwrap()).unwrap(); + let balance = token.balance(&strategy.address); + println!("Strategy {} balance: {}", i, balance); + assert!(balance > 0, "Strategy {} has zero balance", i); + } + + // Deposit and Invest + let mut amounts_desired = svec![&setup.env]; + let mut amounts_min = svec![&setup.env]; + + for i in 0..num_tokens { + let token_admin_client = token_clients.get(i).unwrap(); + token_admin_client.mint(user, &user_starting_balance); + + let desired_amount = 10000000_0_000_000i128; + + amounts_desired.push_back(desired_amount); + amounts_min.push_back(desired_amount); + } + + setup.env.budget().reset_unlimited(); + vault_contract.deposit(&amounts_desired, &amounts_min, user, &true); + check_limits(&setup.env, "Deposit and Invest"); + + for i in 0..num_tokens { + let token = tokens.get(i).unwrap(); + let strategy = strategies.get(i.try_into().unwrap()).unwrap(); + let balance = token.balance(&strategy.address); + println!("Strategy {} balance: {}", i, balance); + assert!(balance > user_starting_balance, "Strategy {} has zero balance", i); + } + + setup.env.jump(DAY_IN_LEDGERS * 7); + + // Simulate a user withdrawal touching all strategies + setup.env.budget().reset_unlimited(); + let balance = vault_contract.balance(&user); + vault_contract.withdraw(&balance, &user); + check_limits(&setup.env, "Withdraw"); + + for i in 0..num_tokens { + let token = tokens.get(i).unwrap(); + let strategy = strategies.get(i.try_into().unwrap()).unwrap(); + let balance = token.balance(&strategy.address); + println!("Strategy {} balance after withdrawal: {}", i, balance); + assert!(balance < user_starting_balance, "Strategy {} balance did not decrease", i); + } +} \ No newline at end of file From 097de25379e89b9bfd248b7f770ab9a51fd7423b Mon Sep 17 00:00:00 2001 From: coderipper Date: Thu, 23 Jan 2025 11:14:08 -0300 Subject: [PATCH 6/9] n assets blend strategy --- .../src/test/limits/n_asset_one_strategy.rs | 358 +++++++++++++++++- 1 file changed, 357 insertions(+), 1 deletion(-) diff --git a/apps/contracts/integration-test/src/test/limits/n_asset_one_strategy.rs b/apps/contracts/integration-test/src/test/limits/n_asset_one_strategy.rs index d68d1cf5..e055cfc8 100644 --- a/apps/contracts/integration-test/src/test/limits/n_asset_one_strategy.rs +++ b/apps/contracts/integration-test/src/test/limits/n_asset_one_strategy.rs @@ -1,5 +1,5 @@ use soroban_sdk::{testutils::Address as _, vec as svec, Address, BytesN, Map, String}; -use crate::{blend_strategy::{create_blend_strategy_contract, BlendStrategyClient}, factory::{AssetStrategySet, Strategy}, fixed_strategy::{create_fixed_strategy_contract, FixedStrategyClient}, hodl_strategy::create_hodl_strategy_contract, setup::{blend_setup::{create_blend_pool, BlendFixture, BlendPoolClient}, create_soroswap_factory, create_soroswap_router, VAULT_FEE}, test::{limits::check_limits, EnvTestUtils, IntegrationTest, DAY_IN_LEDGERS}, token::create_token, vault::defindex_vault_contract::{Instruction, VaultContractClient}}; +use crate::{blend_strategy::{create_blend_strategy_contract, BlendStrategyClient}, factory::{AssetStrategySet, Strategy}, fixed_strategy::{create_fixed_strategy_contract, FixedStrategyClient}, hodl_strategy::create_hodl_strategy_contract, setup::{blend_setup::{create_blend_pool, BlendFixture, BlendPoolClient}, create_soroswap_factory, create_soroswap_pool, create_soroswap_router, VAULT_FEE}, test::{limits::check_limits, EnvTestUtils, IntegrationTest, DAY_IN_LEDGERS}, token::create_token, vault::defindex_vault_contract::{Instruction, VaultContractClient}}; #[test] fn n_assets_one_strategy_hodl() { @@ -182,4 +182,360 @@ fn n_assets_one_strategy_hodl() { println!("Strategy {} balance after withdrawal: {}", i, balance); assert!(balance < user_starting_balance, "Strategy {} balance did not decrease", i); } +} + +#[test] +fn n_assets_one_strategy_fixed() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + setup.env.budget().reset_unlimited(); + + let mut tokens = Vec::new(); + let mut token_clients = Vec::new(); + + let num_tokens = 10; // CHANGE THIS TO CHECK THE LIMITS + + for _ in 0..num_tokens { + let token_admin = Address::generate(&setup.env); + let (token, token_admin_client) = create_token(&setup.env, &token_admin); + tokens.push(token); + token_clients.push(token_admin_client); + } + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let manager = Address::generate(&setup.env); + + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "MultiStrategyVault"); + let vault_symbol = String::from_str(&setup.env, "MSVLT"); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let mut strategies = svec![&setup.env]; + + for i in 0..num_tokens { + let token_admin_client = token_clients.get(i).unwrap(); + let strategy_contract = create_fixed_strategy_contract(&setup.env, &tokens.get(i).unwrap().address, 1000u32, &token_admin_client); + strategies.push_back(Strategy { + address: strategy_contract.address.clone(), + name: String::from_str(&setup.env, "FixedStrategy"), + paused: false, + }); + } + + let mut assets = svec![&setup.env]; + for i in 0..num_tokens { + let token = tokens.get(i).unwrap(); + let strategy = strategies.get(i.try_into().unwrap()).unwrap(); + assets.push_back(AssetStrategySet { + address: token.address.clone(), + strategies: svec![&setup.env, strategy], + }); + } + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + setup.env.budget().reset_unlimited(); + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true, + ); + check_limits(&setup.env, "Create Vault"); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + // User deposit + let user_starting_balance = 10000000_0_000_000i128; + let users = IntegrationTest::generate_random_users(&setup.env, 1); + let user = &users[0]; + + let mut amounts_desired = svec![&setup.env]; + let mut amounts_min = svec![&setup.env]; + + for i in 0..num_tokens { + let token_admin_client = token_clients.get(i).unwrap(); + token_admin_client.mint(user, &user_starting_balance); + + let desired_amount = 10000000_0_000_000i128; + + amounts_desired.push_back(desired_amount); + amounts_min.push_back(desired_amount); + } + + setup.env.budget().reset_unlimited(); + vault_contract.deposit(&amounts_desired, &amounts_min, user, &false); + check_limits(&setup.env, "Deposit"); + + // Prepare rebalance instructions for all strategies + let mut invest_instructions = svec![&setup.env]; + + for i in 0..num_tokens { + invest_instructions.push_back(Instruction::Invest( + strategies.get(i.try_into().unwrap()).unwrap().address.clone(), + user_starting_balance, + )); + } + + // Rebalance first batch + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &invest_instructions); + check_limits(&setup.env, "Invest"); + + for i in 0..num_tokens { + let token = tokens.get(i).unwrap(); + let strategy = strategies.get(i.try_into().unwrap()).unwrap(); + let balance = token.balance(&strategy.address); + println!("Strategy {} balance: {}", i, balance); + assert!(balance > 0, "Strategy {} has zero balance", i); + } + + // Deposit and Invest + let mut amounts_desired = svec![&setup.env]; + let mut amounts_min = svec![&setup.env]; + + for i in 0..num_tokens { + let token_admin_client = token_clients.get(i).unwrap(); + token_admin_client.mint(user, &user_starting_balance); + + let desired_amount = 10000000_0_000_000i128; + + amounts_desired.push_back(desired_amount); + amounts_min.push_back(desired_amount); + } + + setup.env.budget().reset_unlimited(); + vault_contract.deposit(&amounts_desired, &amounts_min, user, &true); + check_limits(&setup.env, "Deposit and Invest"); + + for i in 0..num_tokens { + let token = tokens.get(i).unwrap(); + let strategy = strategies.get(i.try_into().unwrap()).unwrap(); + let balance = token.balance(&strategy.address); + println!("Strategy {} balance: {}", i, balance); + assert!(balance > user_starting_balance, "Strategy {} has zero balance", i); + } + + setup.env.jump(DAY_IN_LEDGERS * 7); + + // Simulate a user withdrawal touching all strategies + setup.env.budget().reset_unlimited(); + let balance = vault_contract.balance(&user); + vault_contract.withdraw(&balance, &user); + check_limits(&setup.env, "Withdraw"); +} + +#[test] +fn n_assets_one_strategy_blend() { + let setup = IntegrationTest::setup(); + setup.env.mock_all_auths(); + setup.env.budget().reset_unlimited(); + + // Soroswap Setup + let soroswap_admin = Address::generate(&setup.env); + let soroswap_factory = create_soroswap_factory(&setup.env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&setup.env, &soroswap_factory.address); + + let admin = Address::generate(&setup.env); + + let (blnd, blnd_client) = create_token(&setup.env, &admin); + let (usdc, usdc_client) = create_token(&setup.env, &admin); + let (xlm, xlm_client) = create_token(&setup.env, &admin); + + // Setting up soroswap pool + let pool_admin = Address::generate(&setup.env); + let amount_a = 100000000_0_000_000; + let amount_b = 50000000_0_000_000; + blnd_client.mint(&pool_admin, &amount_a); + usdc_client.mint(&pool_admin, &amount_b); + create_soroswap_pool( + &setup.env, + &soroswap_router, + &pool_admin, + &blnd.address, + &usdc.address, + &amount_a, + &amount_b, + ); + + let blend_fixture = BlendFixture::deploy(&setup.env, &admin, &blnd.address, &usdc.address); + + let pool = create_blend_pool(&setup.env, &blend_fixture, &admin, &usdc_client, &xlm_client); + let pool_client = BlendPoolClient::new(&setup.env, &pool); + + let emergency_manager = Address::generate(&setup.env); + let rebalance_manager = Address::generate(&setup.env); + let fee_receiver = Address::generate(&setup.env); + let manager = Address::generate(&setup.env); + + let vault_fee = VAULT_FEE; + let vault_name = String::from_str(&setup.env, "BlendVault"); + let vault_symbol = String::from_str(&setup.env, "BLNDVLT"); + + let mut roles: Map = Map::new(&setup.env); + roles.set(0u32, emergency_manager.clone()); // EmergencyManager enum = 0 + roles.set(1u32, fee_receiver.clone()); // VaultFeeReceiver enum = 1 + roles.set(2u32, manager.clone()); // Manager enum = 2 + roles.set(3u32, rebalance_manager.clone()); // RebalanceManager enum = 3 + + let mut name_symbol: Map = Map::new(&setup.env); + name_symbol.set(String::from_str(&setup.env, "name"), vault_name); + name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); + + let usdc_strategy = create_blend_strategy_contract( + &setup.env, + &usdc.address, + &pool, + &0u32, + &blnd.address, + &soroswap_router.address, + svec![&setup.env, 0u32, 1u32, 2u32, 3u32] + ); + let usdc_strategy_contract = BlendStrategyClient::new(&setup.env, &usdc_strategy); + + let xlm_strategy = create_blend_strategy_contract( + &setup.env, + &xlm.address, + &pool, + &1u32, + &blnd.address, + &soroswap_router.address, + svec![&setup.env, 0u32, 1u32, 2u32, 3u32] + ); + let xlm_strategy_contract = BlendStrategyClient::new(&setup.env, &xlm_strategy); + + let num_tokens = 2; + + let mut assets = svec![&setup.env]; + + assets.push_back(AssetStrategySet { + address: usdc.address.clone(), + strategies: svec![&setup.env, Strategy { + address: usdc_strategy_contract.address.clone(), + name: String::from_str(&setup.env, "BlendUSDC"), + paused: false, + }], + }); + assets.push_back(AssetStrategySet { + address: xlm.address.clone(), + strategies: svec![&setup.env, Strategy { + address: xlm_strategy_contract.address.clone(), + name: String::from_str(&setup.env, "BlendXLM"), + paused: false, + }], + }); + + let salt = BytesN::from_array(&setup.env, &[0; 32]); + + setup.env.budget().reset_unlimited(); + let vault_contract_address = setup.factory_contract.create_defindex_vault( + &roles, + &vault_fee, + &assets, + &salt, + &soroswap_router.address, + &name_symbol, + &true, + ); + check_limits(&setup.env, "Create Vault"); + + let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); + + // User deposit + let user_starting_balance = 10000000_0_000_000i128; + let users = IntegrationTest::generate_random_users(&setup.env, 1); + let user = &users[0]; + + let mut amounts_desired = svec![&setup.env]; + let mut amounts_min = svec![&setup.env]; + + for _ in 0..num_tokens { + usdc_client.mint(user, &user_starting_balance); + xlm_client.mint(user, &user_starting_balance); + + let desired_amount = 10000000_0_000_000i128; + + amounts_desired.push_back(desired_amount); + amounts_min.push_back(desired_amount); + } + + setup.env.budget().reset_unlimited(); + vault_contract.deposit(&amounts_desired, &amounts_min, user, &false); + check_limits(&setup.env, "Deposit"); + + // Prepare rebalance instructions for all strategies + let mut invest_instructions = svec![&setup.env]; + let batch_size = num_tokens; + + for i in 0..batch_size { + let asset = assets.get(i.try_into().unwrap()).unwrap(); + let strategy = asset.strategies.get(0).unwrap(); + invest_instructions.push_back(Instruction::Invest( + strategy.address.clone(), + user_starting_balance, + )); + } + + // Rebalance first batch + setup.env.budget().reset_unlimited(); + vault_contract.rebalance(&manager, &invest_instructions); + check_limits(&setup.env, "Invest"); + + // let mut invest_instructions = svec![&setup.env]; + + // for i in batch_size..num_tokens { + // invest_instructions.push_back(Instruction::Invest( + // strategies.get(i.try_into().unwrap()).unwrap().address.clone(), + // user_starting_balance, + // )); + // } + + // // Rebalance second batch + // setup.env.budget().reset_unlimited(); + // vault_contract.rebalance(&manager, &invest_instructions); + // check_limits(&setup.env, "Invest Batch 2"); + + let mut amounts_desired = svec![&setup.env]; + let mut amounts_min = svec![&setup.env]; + + for _ in 0..num_tokens { + usdc_client.mint(user, &user_starting_balance); + xlm_client.mint(user, &user_starting_balance); + + let desired_amount = 10000000_0_000_000i128; + + amounts_desired.push_back(desired_amount); + amounts_min.push_back(desired_amount); + } + + setup.env.budget().reset_unlimited(); + vault_contract.deposit(&amounts_desired, &amounts_min, user, &true); + check_limits(&setup.env, "Deposit and Invest"); + + setup.env.jump(DAY_IN_LEDGERS * 7); + + // Simulate a user withdrawal touching all strategies + setup.env.budget().reset_unlimited(); + let balance = vault_contract.balance(&user); + vault_contract.withdraw(&(balance/2), &user); + check_limits(&setup.env, "Withdraw"); } \ No newline at end of file From 6d460ddaf988bfc6625ca03040f4073a73c02ee1 Mon Sep 17 00:00:00 2001 From: coderipper Date: Thu, 23 Jan 2025 11:30:54 -0300 Subject: [PATCH 7/9] removed warnings --- .../src/test/limits/asset_n_strategies.rs | 14 +++----------- .../src/test/limits/n_asset_one_strategy.rs | 1 - 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs b/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs index 3cc10137..bfb6ed7a 100644 --- a/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs +++ b/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs @@ -383,7 +383,7 @@ fn asset_n_strategies_fixed_panic() { name_symbol.set(String::from_str(&setup.env, "symbol"), vault_symbol); let mut strategies = svec![&setup.env]; - let num_strategies = 11; // CHANGE THIS IF U NEED TO TEST OTHER NUMBER OF STRATEGIES + let num_strategies = 12; // CHANGE THIS IF U NEED TO TEST OTHER NUMBER OF STRATEGIES for i in 0..num_strategies { let strategy_name = format!("Strategy_{}", i); @@ -488,7 +488,7 @@ fn asset_n_strategies_blend() { let (blnd, blnd_client) = create_token(&setup.env, &admin); let (usdc, usdc_client) = create_token(&setup.env, &admin); - let (xlm, xlm_client) = create_token(&setup.env, &admin); + let (_, xlm_client) = create_token(&setup.env, &admin); // Setting up soroswap pool let pool_admin = Address::generate(&setup.env); @@ -667,10 +667,6 @@ fn asset_n_strategies_blend() { }, ], ); - let user_2_final_balance = usdc.balance(&users[2]); - let user_2_profit = user_2_final_balance - user_2_starting_balance; - - let expected_user_2_profit = user_2_profit / 2; std::println!("-- Harvesting --"); // harvest on all strategies @@ -721,7 +717,7 @@ fn asset_n_strategies_blend_panic() { let (blnd, blnd_client) = create_token(&setup.env, &admin); let (usdc, usdc_client) = create_token(&setup.env, &admin); - let (xlm, xlm_client) = create_token(&setup.env, &admin); + let (_, xlm_client) = create_token(&setup.env, &admin); // Setting up soroswap pool let pool_admin = Address::generate(&setup.env); @@ -900,10 +896,6 @@ fn asset_n_strategies_blend_panic() { }, ], ); - let user_2_final_balance = usdc.balance(&users[2]); - let user_2_profit = user_2_final_balance - user_2_starting_balance; - - let expected_user_2_profit = user_2_profit / 2; std::println!("-- Harvesting --"); // harvest on all strategies diff --git a/apps/contracts/integration-test/src/test/limits/n_asset_one_strategy.rs b/apps/contracts/integration-test/src/test/limits/n_asset_one_strategy.rs index e055cfc8..51aa4493 100644 --- a/apps/contracts/integration-test/src/test/limits/n_asset_one_strategy.rs +++ b/apps/contracts/integration-test/src/test/limits/n_asset_one_strategy.rs @@ -380,7 +380,6 @@ fn n_assets_one_strategy_blend() { let blend_fixture = BlendFixture::deploy(&setup.env, &admin, &blnd.address, &usdc.address); let pool = create_blend_pool(&setup.env, &blend_fixture, &admin, &usdc_client, &xlm_client); - let pool_client = BlendPoolClient::new(&setup.env, &pool); let emergency_manager = Address::generate(&setup.env); let rebalance_manager = Address::generate(&setup.env); From 4f9c0f453c35e79b2d53a2251793e038bcdba2d5 Mon Sep 17 00:00:00 2001 From: coderipper Date: Fri, 24 Jan 2025 13:16:26 -0300 Subject: [PATCH 8/9] added caller to distribute fees --- .../src/test/limits/asset_n_strategies.rs | 8 ++++---- .../integration-test/src/test/limits/rebalance.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs b/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs index bfb6ed7a..faa0754c 100644 --- a/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs +++ b/apps/contracts/integration-test/src/test/limits/asset_n_strategies.rs @@ -338,7 +338,7 @@ fn asset_n_strategies_fixed() { } setup.env.budget().reset_unlimited(); - vault_contract.distribute_fees(); + vault_contract.distribute_fees(&manager); check_limits(&setup.env, "Distribute Fees"); // Simulate a user withdrawal touching all strategies @@ -462,7 +462,7 @@ fn asset_n_strategies_fixed_panic() { } setup.env.budget().reset_unlimited(); - vault_contract.distribute_fees(); + vault_contract.distribute_fees(&manager); check_limits(&setup.env, "Distribute Fees"); // Simulate a user withdrawal touching all strategies @@ -687,7 +687,7 @@ fn asset_n_strategies_blend() { println!("-- Distributing Fees --"); setup.env.budget().reset_unlimited(); - vault_contract.distribute_fees(); + vault_contract.distribute_fees(&manager); check_limits(&setup.env, "Distribute Fees"); setup.env.budget().reset_unlimited(); @@ -916,7 +916,7 @@ fn asset_n_strategies_blend_panic() { println!("-- Distributing Fees --"); setup.env.budget().reset_unlimited(); - vault_contract.distribute_fees(); + vault_contract.distribute_fees(&manager); check_limits(&setup.env, "Distribute Fees"); setup.env.budget().reset_unlimited(); diff --git a/apps/contracts/integration-test/src/test/limits/rebalance.rs b/apps/contracts/integration-test/src/test/limits/rebalance.rs index c6c5f7a3..dab0462e 100644 --- a/apps/contracts/integration-test/src/test/limits/rebalance.rs +++ b/apps/contracts/integration-test/src/test/limits/rebalance.rs @@ -427,7 +427,7 @@ fn asset_one_strategy_fixed_rebalance() { vault_contract.report(); vault_contract.lock_fees(&None); - vault_contract.distribute_fees(); + vault_contract.distribute_fees(&manager); let balance_on_strategy = strategy_contract.balance(&vault_contract.address); let num_unwinds = 25; @@ -645,7 +645,7 @@ fn asset_one_strategy_fixed_rebalance_panic_unwind() { vault_contract.report(); vault_contract.lock_fees(&None); - vault_contract.distribute_fees(); + vault_contract.distribute_fees(&manager); let balance_on_strategy = strategy_contract.balance(&vault_contract.address); let num_unwinds = 26; From 133aa1faad98222c5ba0e620d8cd896321366abe Mon Sep 17 00:00:00 2001 From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com> Date: Fri, 24 Jan 2025 16:25:22 -0300 Subject: [PATCH 9/9] =?UTF-8?q?=E2=9A=97=EF=B8=8F=20add=20no=20capture=20f?= =?UTF-8?q?lag=20to=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/test-contracts.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-contracts.yml b/.github/workflows/test-contracts.yml index 1ea9d90b..1a171c05 100644 --- a/.github/workflows/test-contracts.yml +++ b/.github/workflows/test-contracts.yml @@ -50,5 +50,5 @@ jobs: run: | set -e cd apps/contracts && - cargo test --release || exit 1 + cargo test --release -- --nocapture|| exit 1 continue-on-error: false \ No newline at end of file