diff --git a/apps/contracts/vault/src/test/vault/deposit_and_invest.rs b/apps/contracts/vault/src/test/vault/deposit_and_invest.rs index a800f1ea..5ef3e601 100644 --- a/apps/contracts/vault/src/test/vault/deposit_and_invest.rs +++ b/apps/contracts/vault/src/test/vault/deposit_and_invest.rs @@ -1,14 +1,12 @@ use soroban_sdk::{vec as sorobanvec, vec, Map, String, Vec}; use crate::test::defindex_vault::{ - AssetInvestmentAllocation, AssetStrategySet, CurrentAssetInvestmentAllocation, - StrategyAllocation, + AssetInvestmentAllocation, AssetStrategySet, CurrentAssetInvestmentAllocation, StrategyAllocation, Strategy, }; use crate::test::{ create_defindex_vault, create_strategy_params_token_0, create_strategy_params_token_1, - DeFindexVaultTest, + create_hodl_strategy, DeFindexVaultTest, }; - // with no previous investment, there should not be any investment #[test] fn one_asset_no_previous_investment() { @@ -866,7 +864,136 @@ fn one_asset_several_strategies() { What happens when no previous investment has been done? */ - todo!(); + let test = DeFindexVaultTest::setup(); + test.env.mock_all_auths(); + let strategy_client_1 = create_hodl_strategy(&test.env, &test.token_0.address.clone()); + let strategy_client_2 = create_hodl_strategy(&test.env, &test.token_0.address.clone()); + let strategy_client_3 = create_hodl_strategy(&test.env, &test.token_0.address.clone()); + + let strategy_params = sorobanvec![ + &test.env, + Strategy { + name: String::from_str(&test.env, "strategy1"), + address: test.strategy_client_token_0.address.clone(), + paused: false, + }, + Strategy { + name: String::from_str(&test.env, "strategy2"), + address: strategy_client_1.address.clone(), + paused: false, + }, + Strategy { + name: String::from_str(&test.env, "strategy3"), + address: strategy_client_2.address.clone(), + paused: false, + }, + Strategy { + name: String::from_str(&test.env, "strategy4"), + address: strategy_client_3.address.clone(), + paused: false, + }, + ]; + + // initialize with 1 asset, 3 strategies + let assets: Vec = sorobanvec![ + &test.env, + AssetStrategySet { + address: test.token_0.address.clone(), + strategies: strategy_params.clone(), + } + ]; + let defindex_contract = create_defindex_vault( + &test.env, + assets, + test.manager.clone(), + test.emergency_manager.clone(), + test.vault_fee_receiver.clone(), + 2000u32, + test.defindex_protocol_receiver.clone(), + 2500u32, + test.defindex_factory.clone(), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], + ); + let assets = defindex_contract.get_assets(); + assert_eq!(assets.len(), 1); + let asset = assets.get(0).unwrap(); + assert_eq!(asset.strategies.len(), strategy_params.len()); + + let amount0 = 10_0_000_000i128; + + let users = DeFindexVaultTest::generate_random_users(&test.env, 2); + + // Balances before deposit + test.token_0_admin_client.mint(&users[0], &amount0); + + let deposit_amount = 5_0_000_000i128; + // deposit with no previous investment + let _deposit0 = defindex_contract.deposit( + &sorobanvec![&test.env, deposit_amount], + &sorobanvec![&test.env, deposit_amount], + &users[0], + &true, + ); + let invested_funds = defindex_contract.fetch_current_invested_funds().get(test.token_0.address.clone()).unwrap(); + let idle_funds = defindex_contract.fetch_current_idle_funds().get(test.token_0.address.clone()).unwrap(); + + assert_eq!(invested_funds, 0i128); + assert_eq!(idle_funds, deposit_amount); + + + // Invest + let amount_to_invest = 1_0_000_000i128; + let asset_investments = vec![ + &test.env, + Some(AssetInvestmentAllocation { + asset: test.token_0.address.clone(), + strategy_allocations: vec![ + &test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: amount_to_invest, + }), + Some(StrategyAllocation { + strategy_address: strategy_client_1.address.clone(), + amount: amount_to_invest, + }), + Some(StrategyAllocation { + strategy_address: strategy_client_2.address.clone(), + amount: amount_to_invest, + }), + Some(StrategyAllocation { + strategy_address: strategy_client_3.address.clone(), + amount: amount_to_invest, + }), + ], + })]; + let _investment = defindex_contract.invest( + &asset_investments, + ); + let invested_funds = defindex_contract.fetch_current_invested_funds().get(test.token_0.address.clone()).unwrap(); + let idle_funds = defindex_contract.fetch_current_idle_funds().get(test.token_0.address.clone()).unwrap(); + assert_eq!(invested_funds, (amount_to_invest * 4)); + assert_eq!(idle_funds, deposit_amount - (amount_to_invest * 4)); + + // deposit with invest + let deposit_amount_2 = 1_000_000i128; + let _deposit1 = defindex_contract.deposit( + &sorobanvec![&test.env, deposit_amount_2], + &sorobanvec![&test.env, deposit_amount_2], + &users[0], + &true, + ); + let invested_funds = defindex_contract.fetch_current_invested_funds().get(test.token_0.address.clone()).unwrap(); + let idle_funds = defindex_contract.fetch_current_idle_funds().get(test.token_0.address.clone()).unwrap(); + + assert_eq!(invested_funds, (amount_to_invest * 4) + deposit_amount_2); + assert_eq!(idle_funds, (deposit_amount + deposit_amount_2) - (amount_to_invest * 4) - deposit_amount_2); + } #[test] @@ -874,7 +1001,152 @@ fn deposit_simple_then_deposit_and_invest() { /* Here we will check that everything works ok if the user first do a simple deposit without invest, and then does the deposit and invest and if then does the deposit again without invest? - */ - todo!(); + let test = DeFindexVaultTest::setup(); + test.env.mock_all_auths(); + + let strategy_params = create_strategy_params_token_0(&test); + + // initialize with 1 asset, 3 strategies + let assets: Vec = sorobanvec![ + &test.env, + AssetStrategySet { + address: test.token_0.address.clone(), + strategies: strategy_params.clone(), + } + ]; + let defindex_contract = create_defindex_vault( + &test.env, + assets, + test.manager.clone(), + test.emergency_manager.clone(), + test.vault_fee_receiver.clone(), + 2000u32, + test.defindex_protocol_receiver.clone(), + 2500u32, + test.defindex_factory.clone(), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], + + ); + let assets = defindex_contract.get_assets(); + assert_eq!(assets.len(), 1); + let asset = assets.get(0).unwrap(); + assert_eq!(asset.strategies.len(), 1); + + let amount0 = 12_3_456_789i128; + + let users = DeFindexVaultTest::generate_random_users(&test.env, 2); + + // Balances before deposit + test.token_0_admin_client.mint(&users[0], &amount0); + + let deposit_amount = 6_0_000_000i128; + // deposit with no previous investment + + let mut total_deposit = deposit_amount; + let _ = defindex_contract.deposit( + &sorobanvec![&test.env, deposit_amount], + &sorobanvec![&test.env, deposit_amount], + &users[0], + &false, + ); + let invested_funds = defindex_contract.fetch_current_invested_funds().get(test.token_0.address.clone()).unwrap(); + let idle_funds = defindex_contract.fetch_current_idle_funds().get(test.token_0.address.clone()).unwrap(); + + assert_eq!(invested_funds, 0i128); + assert_eq!(idle_funds, total_deposit); + + let deposit_and_invest_amount = 2_0_000_000i128; + let _ = defindex_contract.deposit( + &sorobanvec![&test.env, deposit_and_invest_amount], + &sorobanvec![&test.env, deposit_and_invest_amount], + &users[0], + &true, + ); + + let invested_funds = defindex_contract.fetch_current_invested_funds().get(test.token_0.address.clone()).unwrap(); + let idle_funds = defindex_contract.fetch_current_idle_funds().get(test.token_0.address.clone()).unwrap(); + + total_deposit += deposit_and_invest_amount; + assert_eq!(invested_funds, 0i128); + assert_eq!(idle_funds, total_deposit); + + let deposit_amount_1 = 2_0_000_000i128; + let _ = defindex_contract.deposit( + &sorobanvec![&test.env, deposit_amount_1], + &sorobanvec![&test.env, deposit_amount_1], + &users[0], + &false, + ); + + let invested_funds = defindex_contract.fetch_current_invested_funds().get(test.token_0.address.clone()).unwrap(); + let idle_funds = defindex_contract.fetch_current_idle_funds().get(test.token_0.address.clone()).unwrap(); + + total_deposit += deposit_amount_1; + assert_eq!(invested_funds, 0i128); + assert_eq!(idle_funds, total_deposit); + + let amount_to_invest = 4_0_000_000i128; + let mut total_invested = amount_to_invest; + let asset_investments = vec![ + &test.env, + Some(AssetInvestmentAllocation { + asset: test.token_0.address.clone(), + strategy_allocations: vec![ + &test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: amount_to_invest, + }) + ], + })]; + let _ = defindex_contract.invest( + &asset_investments, + ); + + let invested_funds = defindex_contract.fetch_current_invested_funds().get(test.token_0.address.clone()).unwrap(); + let idle_funds = defindex_contract.fetch_current_idle_funds().get(test.token_0.address.clone()).unwrap(); + + assert_eq!(invested_funds, total_invested); + assert_eq!(idle_funds, total_deposit - total_invested); + + let deposit_amount_2 = 1_0_000_000i128; + + let _ = defindex_contract.deposit( + &sorobanvec![&test.env, deposit_amount_2], + &sorobanvec![&test.env, deposit_amount_2], + &users[0], + &true, + ); + total_deposit += deposit_amount_2; + total_invested += deposit_amount_2; + + let invested_funds = defindex_contract.fetch_current_invested_funds().get(test.token_0.address.clone()).unwrap(); + let idle_funds = defindex_contract.fetch_current_idle_funds().get(test.token_0.address.clone()).unwrap(); + + assert_eq!(invested_funds, total_invested); + assert_eq!(idle_funds, total_deposit - total_invested); + let deposit_amount_3 = 1_000_000i128; + + let _ = defindex_contract.deposit( + &sorobanvec![&test.env, deposit_amount_3], + &sorobanvec![&test.env, deposit_amount_3], + &users[0], + &false, + ); + total_deposit += deposit_amount_3; + let expected_idle_funds = idle_funds + deposit_amount_3; + + + let invested_funds = defindex_contract.fetch_current_invested_funds().get(test.token_0.address.clone()).unwrap(); + let idle_funds = defindex_contract.fetch_current_idle_funds().get(test.token_0.address.clone()).unwrap(); + + assert_eq!(invested_funds, total_invested); + assert_eq!(idle_funds, total_deposit - total_invested); + } diff --git a/apps/contracts/vault/src/test/vault/get_asset_amounts_per_shares.rs b/apps/contracts/vault/src/test/vault/get_asset_amounts_per_shares.rs index 2a4bcfcd..2022bf79 100644 --- a/apps/contracts/vault/src/test/vault/get_asset_amounts_per_shares.rs +++ b/apps/contracts/vault/src/test/vault/get_asset_amounts_per_shares.rs @@ -1,6 +1,6 @@ use soroban_sdk::{vec as sorobanvec, Map, String, Vec}; -use crate::test::defindex_vault::{AssetStrategySet, ContractError}; +use crate::test::defindex_vault::{AssetInvestmentAllocation, AssetStrategySet, ContractError, StrategyAllocation}; use crate::test::{ create_defindex_vault, create_strategy_params_token_0, create_strategy_params_token_1, DeFindexVaultTest, @@ -171,5 +171,202 @@ fn deposit_several_assets_get_asset_amounts_per_shares() { #[test] fn deposit_and_invest_several_assets_get_asset_amounts_per_shares() { - todo!(); + let test = DeFindexVaultTest::setup(); + test.env.mock_all_auths(); + let strategy_params_token_0 = create_strategy_params_token_0(&test); + let strategy_params_token_1 = create_strategy_params_token_1(&test); + + + // initialize with 2 assets + let assets: Vec = sorobanvec![ + &test.env, + AssetStrategySet { + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() + }, + AssetStrategySet { + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() + } + ]; + let name_symbol = sorobanvec!(&test.env, String::from_str(&test.env, "dfToken"), String::from_str(&test.env, "DFT"),); + + let defindex_contract = create_defindex_vault( + &test.env, + assets, + test.manager.clone(), + test.emergency_manager.clone(), + test.vault_fee_receiver.clone(), + 2000u32, + test.defindex_protocol_receiver.clone(), + 2500u32, + test.defindex_factory.clone(), + test.soroswap_router.address.clone(), + name_symbol, + + + ); + + let amount0 = 123456789i128; + let amount1 = 987654321i128; + + let users = DeFindexVaultTest::generate_random_users(&test.env, 2); + + // Balances before deposit + test.token_0_admin_client.mint(&users[0], &amount0); + test.token_1_admin_client.mint(&users[0], &amount1); + + let deposit_amount_0 = 12_3_456_789i128; + let deposit_amount_1 = 98_7_654_321i128; + let user_balance0 = test.token_0.balance(&users[0]); + assert_eq!(user_balance0, amount0); + let user_balance1 = test.token_1.balance(&users[0]); + assert_eq!(user_balance1, amount1); + + let df_balance = defindex_contract.balance(&users[0]); + assert_eq!(df_balance, 0i128); + + // deposit + defindex_contract.deposit( + &sorobanvec![&test.env, deposit_amount_0, deposit_amount_1], + &sorobanvec![&test.env, deposit_amount_0, deposit_amount_1], + &users[0], + &true, + ); + + // Invest + let amount_to_invest = 1_0_000_000i128; + let asset_investments = sorobanvec![ + &test.env, + Some(AssetInvestmentAllocation { + asset: test.token_0.address.clone(), + strategy_allocations: sorobanvec![ + &test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: amount_to_invest, + }), + ], + }), + Some(AssetInvestmentAllocation { + asset: test.token_1.address.clone(), + strategy_allocations: sorobanvec![ + &test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: amount_to_invest, + }), + ], + }), + ]; + let _investment = defindex_contract.invest( + &asset_investments, + ); + let token_0_invested_funds = defindex_contract.fetch_current_invested_funds().get(test.token_0.address.clone()).unwrap(); + let token_1_invested_funds = defindex_contract.fetch_current_invested_funds().get(test.token_1.address.clone()).unwrap(); + let token_0_idle_funds = defindex_contract.fetch_current_idle_funds().get(test.token_0.address.clone()).unwrap(); + let token_1_idle_funds = defindex_contract.fetch_current_idle_funds().get(test.token_1.address.clone()).unwrap(); + + assert_eq!(token_0_invested_funds, amount_to_invest); + assert_eq!(token_1_invested_funds, amount_to_invest); + assert_eq!(token_0_idle_funds, (deposit_amount_0 - amount_to_invest)); + assert_eq!(token_1_idle_funds, (deposit_amount_1 - amount_to_invest)); + + // function is fn get_asset_amounts_per_shares(e: Env, vault_shares: i128) -> Map + // get several results of the function using different vault_shares + let result1 = defindex_contract.get_asset_amounts_per_shares(&0i128); + let result2 = defindex_contract.get_asset_amounts_per_shares(&1000i128); + let result3 = defindex_contract.get_asset_amounts_per_shares(&2000i128); + let result4 = defindex_contract.get_asset_amounts_per_shares(&3000i128); + let result5 = defindex_contract.get_asset_amounts_per_shares(&4000i128); + let result6 = defindex_contract.get_asset_amounts_per_shares(&5000i128); + + // calculate result1_should by hand (put aritmentic as a comment) and check that results are ok + // result1_should = {token_0: 0, token_1: 0} + let mut result1_should = Map::new(&test.env); + result1_should.set(test.token_0.address.clone(), 0i128); + result1_should.set(test.token_1.address.clone(), 0i128); + assert_eq!(result1, result1_should); + + // next we will consider that total shares are amount0 + amount1 = 123456789 + 987654321 = 1111111110 + // and we will calculate the shares for each asset + // amount should 1 for token_0: + // amount0 * shares 0 = 123456789 * 1000 = 123456789000 + // amount 0 * shares 0 / total supply = 123456789000 / 1111111110 = 111.111110211 + // because truncating, amount should be 111 + + // amount should 1 for token_1: + // amount1 * shares 0 = 987654321 * 1000 = 987654321000 + // amount 1 * shares 0 / total supply = 987654321000 / 1111111110 = 888.888889789 + // because truncating, amount should be 888 + // result2_should = {token_0: 111, token_1: 888} + let mut result2_should = Map::new(&test.env); + result2_should.set(test.token_0.address.clone(), 111i128); + result2_should.set(test.token_1.address.clone(), 888i128); + assert_eq!(result2, result2_should); + + // amount should 2 for token_0: + // amount0 * shares 0 = 123456789 * 2000 = 246913578000 + // amount 0 * shares 0 / total supply = 246913578000 / 1111111110 = 222.222220422 + // because truncating, amount should be 222 + + // amount should 2 for token_1: + // amount1 * shares 0 = 987654321 * 2000 = 1975308642000 + // amount 1 * shares 0 / total supply = 1975308642000 / 1111111110 = 1777.777779578 + // because truncating, amount should be 1777 + // result3_should = {token_0: 222, token_1: 1777} + let mut result3_should = Map::new(&test.env); + result3_should.set(test.token_0.address.clone(), 222i128); + result3_should.set(test.token_1.address.clone(), 1777i128); + assert_eq!(result3, result3_should); + + // amount should 3 for token_0: + // amount0 * shares 0 = 123456789 * 3000 = 370370367000 + // amount 0 * shares 0 / total supply = 370370367000 / 1111111110 = 333.333330633 + // because truncating, amount should be 333 + + // amount should 3 for token_1: + // amount1 * shares 0 = 987654321 * 3000 = 2962962963000 + // amount 1 * shares 0 / total supply = 2962962963000 / 1111111110 = 2666.666670633 + // because truncating, amount should be 2666 + // result4_should = {token_0: 333, token_1: 2666} + let mut result4_should = Map::new(&test.env); + result4_should.set(test.token_0.address.clone(), 333i128); + result4_should.set(test.token_1.address.clone(), 2666i128); + assert_eq!(result4, result4_should); + + // amount should 4 for token_0: + // amount0 * shares 0 = 123456789 * 4000 = 493827156000 + // amount 0 * shares 0 / total supply = 493827156000 / 1111111110 = 444.444440844 + // because truncating, amount should be 444 + + // amount should 4 for token_1: + // amount1 * shares 0 = 987654321 * 4000 = 3950617284000 + // amount 1 * shares 0 / total supply = 3950617284000 / 1111111110 = 3555.555561844 + // because truncating, amount should be 3555 + // result5_should = {token_0: 444, token_1: 3555} + let mut result5_should = Map::new(&test.env); + result5_should.set(test.token_0.address.clone(), 444i128); + result5_should.set(test.token_1.address.clone(), 3555i128); + assert_eq!(result5, result5_should); + + // amount should 5 for token_0: + // amount0 * shares 0 = 123456789 * 5000 = 617283945000 + // amount 0 * shares 0 / total supply = 617283945000 / 1111111110 = 555.555550055 + // because truncating, amount should be 555 + + // amount should 5 for token_1: + // amount1 * shares 0 = 987654321 * 5000 = 4938271605000 + // amount 1 * shares 0 / total supply = 4938271605000 / 1111111110 = 4444.444450055 + // because truncating, amount should be 4444 + // result6_should = {token_0: 555, token_1: 4444} + let mut result6_should = Map::new(&test.env); + result6_should.set(test.token_0.address.clone(), 555i128); + result6_should.set(test.token_1.address.clone(), 4444i128); + assert_eq!(result6, result6_should); + + // ************************************************* + // now we will consider an amount over total supply , we should get error AmountOverTotalSupply + let result7 = defindex_contract.try_get_asset_amounts_per_shares(&1111111111i128); + assert_eq!(result7, Err(Ok(ContractError::AmountOverTotalSupply))); } diff --git a/apps/contracts/vault/src/test/vault/initialize.rs b/apps/contracts/vault/src/test/vault/initialize.rs index 15e12078..cf376542 100644 --- a/apps/contracts/vault/src/test/vault/initialize.rs +++ b/apps/contracts/vault/src/test/vault/initialize.rs @@ -1,7 +1,8 @@ use soroban_sdk::{vec as sorobanvec, Address, IntoVal, Map, String, Vec}; use crate::test::{ - create_defindex_vault, create_hodl_strategy, create_strategy_params_token_0, create_strategy_params_token_1, defindex_vault::{AssetStrategySet, CurrentAssetInvestmentAllocation, Strategy, StrategyAllocation}, vault::withdraw, DeFindexVaultTest + create_defindex_vault, create_hodl_strategy, create_strategy_params_token_0, create_strategy_params_token_1, + defindex_vault::{{AssetStrategySet, Strategy}, CurrentAssetInvestmentAllocation, StrategyAllocation}, DeFindexVaultTest, }; fn _create_expected_current_invested_funds(test: &DeFindexVaultTest) -> Map { let mut expected_current_invested_funds: Map = Map::new(&test.env); diff --git a/apps/contracts/vault/src/test/vault/invest.rs b/apps/contracts/vault/src/test/vault/invest.rs index 4b7dff51..0889958b 100644 --- a/apps/contracts/vault/src/test/vault/invest.rs +++ b/apps/contracts/vault/src/test/vault/invest.rs @@ -1,18 +1,18 @@ use soroban_sdk::{ testutils::{MockAuth, MockAuthInvoke}, - IntoVal, + vec as sorobanvec, vec, InvokeError, Map, String, Vec, IntoVal, }; -use soroban_sdk::{vec as sorobanvec, vec, Map, String, Vec}; use crate::test::defindex_vault::{ AssetInvestmentAllocation, AssetStrategySet, ContractError, CurrentAssetInvestmentAllocation, Strategy, StrategyAllocation, }; use crate::test::{ - create_defindex_vault, create_strategy_params_token_0, create_strategy_params_token_1, + create_defindex_vault, create_hodl_strategy, create_strategy_params_token_0, create_strategy_params_token_1, DeFindexVaultTest, }; + // try to invest with a wrong AssetInvestmentAllocation length #[test] fn wrong_asset_investment_length() { @@ -923,4 +923,218 @@ fn without_mock_all_auths() { } #[test] -fn one_asset_several_strategies() {} +fn one_asset_several_strategies() { + let test = DeFindexVaultTest::setup(); + test.env.mock_all_auths(); + let strategy_client_1 = create_hodl_strategy(&test.env, &test.token_0.address.clone()); + let strategy_client_2 = create_hodl_strategy(&test.env, &test.token_0.address.clone()); + let strategy_client_3 = create_hodl_strategy(&test.env, &test.token_0.address.clone()); + + let strategy_params = sorobanvec![ + &test.env, + Strategy { + name: String::from_str(&test.env, "strategy1"), + address: test.strategy_client_token_0.address.clone(), + paused: false, + }, + Strategy { + name: String::from_str(&test.env, "strategy2"), + address: strategy_client_1.address.clone(), + paused: false, + }, + Strategy { + name: String::from_str(&test.env, "strategy3"), + address: strategy_client_2.address.clone(), + paused: false, + }, + Strategy { + name: String::from_str(&test.env, "strategy4"), + address: strategy_client_3.address.clone(), + paused: false, + }, + ]; + + // initialize with 1 asset, 3 strategies + let assets: Vec = sorobanvec![ + &test.env, + AssetStrategySet { + address: test.token_0.address.clone(), + strategies: strategy_params.clone(), + } + ]; + let defindex_contract = create_defindex_vault( + &test.env, + assets, + test.manager.clone(), + test.emergency_manager.clone(), + test.vault_fee_receiver.clone(), + 2000u32, + test.defindex_protocol_receiver.clone(), + 2500u32, + test.defindex_factory.clone(), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], + ); + let assets = defindex_contract.get_assets(); + assert_eq!(assets.len(), 1); + let asset = assets.get(0).unwrap(); + assert_eq!(asset.strategies.len(), strategy_params.len()); + + let amount0 = 100_0_000_000i128; + + let users = DeFindexVaultTest::generate_random_users(&test.env, 2); + + // Balances before deposit + test.token_0_admin_client.mint(&users[0], &amount0); + + let deposit_amount = 10_0_000_000i128; + // deposit with no previous investment + let _deposit0 = defindex_contract.deposit( + &sorobanvec![&test.env, deposit_amount], + &sorobanvec![&test.env, deposit_amount], + &users[0], + &true, + ); + let invested_funds = defindex_contract.fetch_current_invested_funds().get(test.token_0.address.clone()).unwrap(); + let idle_funds = defindex_contract.fetch_current_idle_funds().get(test.token_0.address.clone()).unwrap(); + + assert_eq!(invested_funds, 0); + assert_eq!(idle_funds, deposit_amount); + + //Wrong strategy_allocation length + let asset_investments = &sorobanvec![ + &test.env, + Some( + AssetInvestmentAllocation { + asset: test.token_0.address.clone(), + strategy_allocations: sorobanvec![&test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 1_0_000_000, + }), + Some(StrategyAllocation { + strategy_address: strategy_client_1.address.clone(), + amount: 1_0_000_000, + }), + Some(StrategyAllocation { + strategy_address: strategy_client_2.address.clone(), + amount: 1_0_000_000, + }), + ] + } + ), + ]; + + let invest_result = defindex_contract.try_invest(asset_investments); + assert_eq!(invested_funds, 0); + assert_eq!(idle_funds, deposit_amount); + assert_eq!(invest_result, Err(Ok(ContractError::WrongStrategiesLength))); + + //Wrong asset_allocation length + let asset_investments = &sorobanvec![ + &test.env, + Some( + AssetInvestmentAllocation { + asset: test.token_0.address.clone(), + strategy_allocations: sorobanvec![&test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 1_0_000_000, + }), + ] + } + ), + Some( + AssetInvestmentAllocation { + asset: test.token_0.address.clone(), + strategy_allocations: sorobanvec![&test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 1_0_000_000, + }), + ] + } + ), + ]; + + let invest_result = defindex_contract.try_invest(asset_investments); + assert_eq!(invested_funds, 0); + assert_eq!(idle_funds, deposit_amount); + assert_eq!(invest_result, Err(Ok(ContractError::WrongInvestmentLength))); + + //More than idle funds + let asset_investments = &sorobanvec![ + &test.env, + Some( + AssetInvestmentAllocation { + asset: test.token_0.address.clone(), + strategy_allocations: sorobanvec![&test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: deposit_amount, + }), + Some(StrategyAllocation { + strategy_address: strategy_client_1.address.clone(), + amount: deposit_amount, + }), + Some(StrategyAllocation { + strategy_address: strategy_client_2.address.clone(), + amount: deposit_amount, + }), + Some(StrategyAllocation { + strategy_address: strategy_client_3.address.clone(), + amount: deposit_amount, + }), + ] + } + ), + ]; + + let invest_result = defindex_contract.try_invest(asset_investments); + + assert_eq!(invest_result, Err(Err(InvokeError::Contract(10)))); + + //success invest + let asset_investments = &sorobanvec![ + &test.env, + Some( + AssetInvestmentAllocation { + asset: test.token_0.address.clone(), + strategy_allocations: sorobanvec![&test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 1_0_000_000, + }), + Some(StrategyAllocation { + strategy_address: strategy_client_1.address.clone(), + amount: 1_0_000_000, + }), + Some(StrategyAllocation { + strategy_address: strategy_client_2.address.clone(), + amount: 1_0_000_000, + }), + Some(StrategyAllocation { + strategy_address: strategy_client_3.address.clone(), + amount: 1_0_000_000, + }), + ] + } + ), + ]; + + defindex_contract.invest(asset_investments); + let invested_funds = defindex_contract.fetch_current_invested_funds().get(test.token_0.address.clone()).unwrap(); + let idle_funds = defindex_contract.fetch_current_idle_funds().get(test.token_0.address.clone()).unwrap(); + assert_eq!(invested_funds, 4_0_000_000); + assert_eq!(idle_funds, deposit_amount - 4_0_000_000); + + //success withdraw from strategy + let withdraw_amount = 2_0_000_000i128; + let withdraw_result = defindex_contract.withdraw(&withdraw_amount, &users[0]); + + assert_eq!(withdraw_result, sorobanvec![&test.env, withdraw_amount.clone()]); +} diff --git a/apps/contracts/vault/src/test/vault/withdraw.rs b/apps/contracts/vault/src/test/vault/withdraw.rs index d629543b..da215b3b 100644 --- a/apps/contracts/vault/src/test/vault/withdraw.rs +++ b/apps/contracts/vault/src/test/vault/withdraw.rs @@ -1,9 +1,9 @@ -use soroban_sdk::{vec as sorobanvec, Map, String, Vec}; +use soroban_sdk::{testutils::{MockAuth, MockAuthInvoke}, vec as sorobanvec, IntoVal, Map, String, Vec}; // use super::hodl_strategy::StrategyError; use crate::test::{ create_defindex_vault, create_strategy_params_token_0, create_strategy_params_token_1, - defindex_vault::{ + create_hodl_strategy, defindex_vault::{ AssetInvestmentAllocation, AssetStrategySet, ContractError, CurrentAssetInvestmentAllocation, Strategy, StrategyAllocation, }, @@ -687,56 +687,109 @@ fn from_strategy_one_asset_one_strategy_success() { #[test] fn from_strategies_one_asset_two_strategies_success() { - todo!(); - // let test = DeFindexVaultTest::setup(); - // test.env.mock_all_auths(); - // let assets: Vec = sorobanvec![ - // &test.env, - // AssetStrategySet { - // address: test.token_0.address.clone(), - // strategies: sorobanvec![ - // &test.env, - // Strategy { - // name: String::from_str(&test.env, "Strategy 1"), - // address: test.strategy_client_token_0.address.clone(), - // paused: false, - // } - // ] - // } - // ]; - - // defindex_contract.initialize( - // &assets, - // &test.manager, - // &test.emergency_manager, - // &test.vault_fee_receiver, - // &2000u32, - // &test.defindex_protocol_receiver, - // &test.defindex_factory, - // &String::from_str(&test.env, "dfToken"), - // &String::from_str(&test.env, "DFT"), - // ); - // let amount = 1234567890000000i128; - - // let users = DeFindexVaultTest::generate_random_users(&test.env, 1); - - // test.token_0_admin_client.mint(&users[0], &amount); - // assert_eq!(test.token_0.balance(&users[0]), amount); - - // let df_balance = defindex_contract.balance(&users[0]); - // assert_eq!(df_balance, 0i128); - - // // Deposit - // let amount_to_deposit = 987654321i128; - - // defindex_contract.deposit( - // &sorobanvec![&test.env, amount_to_deposit], - // &sorobanvec![&test.env, amount_to_deposit], - // &users[0], - // &false - // ); - - // FIX invest in 2 stretegies for the same asset + let test = DeFindexVaultTest::setup(); + test.env.mock_all_auths(); + let strategy_client_1 = create_hodl_strategy(&test.env, &test.token_0.address.clone()); + + let strategy_params = sorobanvec![ + &test.env, + Strategy { + name: String::from_str(&test.env, "strategy1"), + address: test.strategy_client_token_0.address.clone(), + paused: false, + }, + Strategy { + name: String::from_str(&test.env, "strategy2"), + address: strategy_client_1.address.clone(), + paused: false, + }, + ]; + let assets: Vec = sorobanvec![ + &test.env, + AssetStrategySet { + address: test.token_0.address.clone(), + strategies: strategy_params.clone(), + } + ]; + + let defindex_contract = create_defindex_vault( + &test.env, + assets, + test.manager.clone(), + test.emergency_manager.clone(), + test.vault_fee_receiver.clone(), + 10u32, + test.defindex_protocol_receiver.clone(), + 2500u32, + test.defindex_factory.clone(), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT"), + ], + ); + + let assets = defindex_contract.get_assets(); + assert_eq!(assets.len(), 1); + let asset = assets.get(0).unwrap(); + assert_eq!(asset.strategies.len(), strategy_params.len()); + + let amount = 10_0_000_000i128; + + let users = DeFindexVaultTest::generate_random_users(&test.env, 1); + + test.token_0_admin_client.mint(&users[0], &amount); + let user_balance = test.token_0.balance(&users[0]); + assert_eq!(user_balance, amount); + // here youll need to create a client for a token with the same address + + let df_balance = defindex_contract.balance(&users[0]); + assert_eq!(df_balance, 0i128); + + defindex_contract.deposit( + &sorobanvec![&test.env, amount], + &sorobanvec![&test.env, amount], + &users[0], + &false, + ); + + let df_balance = defindex_contract.balance(&users[0]); + assert_eq!(df_balance, amount - 1000); + + + let amount_to_invest = 5_0_000_000i128; + + let investments = sorobanvec![ + &test.env, + Some(AssetInvestmentAllocation { + asset: test.token_0.address.clone(), + strategy_allocations: sorobanvec![ + &test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: amount_to_invest, + }), + Some(StrategyAllocation { + strategy_address: strategy_client_1.address.clone(), + amount: amount_to_invest, + }), + ], + }) + ]; + + defindex_contract.invest(&investments); + + let vault_balance = test.token_0.balance(&defindex_contract.address); + assert_eq!(vault_balance, 0); + + defindex_contract.withdraw(&df_balance, &users[0]); + + let df_balance = defindex_contract.balance(&users[0]); + assert_eq!(df_balance, 0i128); + + let user_balance = test.token_0.balance(&users[0]); + assert_eq!(user_balance, amount - 1000); } #[test] @@ -1101,5 +1154,106 @@ fn from_strategies_two_asset_each_one_strategy_success() { // test withdraw without mock all auths #[test] fn from_strategy_success_no_mock_all_auths() { - todo!(); + let test = DeFindexVaultTest::setup(); + let strategy_params_token_0 = create_strategy_params_token_0(&test); + let users = DeFindexVaultTest::generate_random_users(&test.env, 1); + + let assets: Vec = sorobanvec![ + &test.env, + AssetStrategySet { + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() + } + ]; + let defindex_contract = create_defindex_vault( + &test.env, + assets, + test.manager.clone(), + test.emergency_manager.clone(), + test.vault_fee_receiver.clone(), + 200u32, + test.defindex_protocol_receiver.clone(), + 2500u32, + test.defindex_factory.clone(), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], + ); + + // mint + let amount = 987654321i128; + let mocked_token_client = test.token_0_admin_client.mock_all_auths(); + mocked_token_client.mint(&users[0], &amount); + + assert_eq!(test.token_0.balance(&users[0]), amount); + + let assets = defindex_contract.get_assets(); + assert_eq!(assets.len(), 1); + let asset = assets.get(0).unwrap(); + assert_eq!(asset.strategies.len(), 1); + + + let deposit_amount = 1_0_000_000i128; + + + let amounts_desired = sorobanvec![&test.env, deposit_amount]; + let amounts_min = sorobanvec![&test.env, deposit_amount]; + let from = &users[0].clone(); + let invest = false; + + defindex_contract.mock_auths(&[MockAuth { + address: &from.clone(), + invoke: &MockAuthInvoke { + contract: &defindex_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&test.env, [deposit_amount]), + Vec::from_array(&test.env, [deposit_amount]), + from.clone(), + false + ).into_val(&test.env), + sub_invokes: &[MockAuthInvoke { + contract: &mocked_token_client.address.clone(), + fn_name: "transfer", + args: sorobanvec![ + &test.env, + from.clone().into_val(&test.env), + (defindex_contract.address).into_val(&test.env), + deposit_amount.into_val(&test.env), + ], + sub_invokes: &[], + }], + }, + } + ]).deposit(&amounts_desired, &amounts_min, &from, &invest); + + let invested_funds = defindex_contract.fetch_current_invested_funds().get(test.token_0.address.clone()).unwrap(); + let idle_funds = defindex_contract.fetch_current_idle_funds().get(test.token_0.address.clone()).unwrap(); + + assert_eq!(idle_funds, deposit_amount); + assert_eq!(invested_funds, 0); + + let withdraw_amount = deposit_amount/2; + defindex_contract.mock_auths(&[MockAuth { + address: &from.clone(), + invoke: &MockAuthInvoke { + contract: &defindex_contract.address.clone(), + fn_name: "withdraw", + args: ( + withdraw_amount, + from, + ).into_val(&test.env), + sub_invokes: &[], + }, + } + ]).withdraw(&withdraw_amount, &from.clone()); + + let invested_funds = defindex_contract.fetch_current_invested_funds().get(test.token_0.address.clone()).unwrap(); + let idle_funds = defindex_contract.fetch_current_idle_funds().get(test.token_0.address.clone()).unwrap(); + + assert_eq!(idle_funds, deposit_amount - withdraw_amount); + assert_eq!(invested_funds, 0); }