diff --git a/apps/contracts/Cargo.lock b/apps/contracts/Cargo.lock index f358b282..eae6bea9 100644 --- a/apps/contracts/Cargo.lock +++ b/apps/contracts/Cargo.lock @@ -412,6 +412,7 @@ dependencies = [ "defindex-strategy-core", "soroban-sdk", "soroban-token-sdk", + "soroswap-library", ] [[package]] @@ -1324,6 +1325,16 @@ dependencies = [ "wasmparser-nostd", ] +[[package]] +name = "soroswap-library" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4365cc0e03f153852d78228a5ea488447b69c974ec35084830c03f5aebb74a3f" +dependencies = [ + "num-integer", + "soroban-sdk", +] + [[package]] name = "soroswap_strategy" version = "0.1.0" diff --git a/apps/contracts/Cargo.toml b/apps/contracts/Cargo.toml index 483c2ca7..7c82f4d2 100644 --- a/apps/contracts/Cargo.toml +++ b/apps/contracts/Cargo.toml @@ -15,7 +15,7 @@ homepage = "https://defindex.io" [workspace.dependencies] soroban-sdk = "22.0.0-rc.2.1" soroban-token-sdk = { version = "22.0.0-rc.2.1" } -# soroswap-library = "0.3.0" +soroswap-library = "2.0.0" defindex-strategy-core={ path="./strategies/core", package="defindex-strategy-core" } common={ path="./common", package="common" } diff --git a/apps/contracts/README.md b/apps/contracts/README.md index 8a15a57d..eeab6177 100644 --- a/apps/contracts/README.md +++ b/apps/contracts/README.md @@ -40,6 +40,14 @@ yarn deploy-fixed yarn deploy-blend ``` +Do it all in testnet with +``` +yarn deploy-factory testnet +yarn deploy-hodl testnet +yarn deploy-fixed testnet +yarn deploy-blend testnet +``` + once you have deployed all the contracts you can run all the tests by running: ```bash diff --git a/apps/contracts/common/src/lib.rs b/apps/contracts/common/src/lib.rs index bc7fe786..cef9b391 100644 --- a/apps/contracts/common/src/lib.rs +++ b/apps/contracts/common/src/lib.rs @@ -1,3 +1,3 @@ #![no_std] -pub mod models; \ No newline at end of file +pub mod models; diff --git a/apps/contracts/common/src/models.rs b/apps/contracts/common/src/models.rs index 401e620a..fd866546 100644 --- a/apps/contracts/common/src/models.rs +++ b/apps/contracts/common/src/models.rs @@ -13,4 +13,4 @@ pub struct Strategy { pub struct AssetStrategySet { pub address: Address, pub strategies: Vec, -} \ No newline at end of file +} diff --git a/apps/contracts/factory/src/events.rs b/apps/contracts/factory/src/events.rs index 16773b34..6c79fc95 100644 --- a/apps/contracts/factory/src/events.rs +++ b/apps/contracts/factory/src/events.rs @@ -6,28 +6,28 @@ use soroban_sdk::{contracttype, symbol_short, Address, Env, Vec}; #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct CreateDeFindexEvent { - pub emergency_manager: Address, - pub fee_receiver: Address, + pub emergency_manager: Address, + pub fee_receiver: Address, pub manager: Address, pub vault_fee: u32, - pub assets: Vec + pub assets: Vec, } /// Publishes an `CreateDeFindexEvent` to the event stream. pub(crate) fn emit_create_defindex_vault( - e: &Env, - emergency_manager: Address, - fee_receiver: Address, + e: &Env, + emergency_manager: Address, + fee_receiver: Address, manager: Address, vault_fee: u32, assets: Vec, ) { - let event = CreateDeFindexEvent { - emergency_manager, - fee_receiver, - manager, - vault_fee, - assets, + let event = CreateDeFindexEvent { + emergency_manager, + fee_receiver, + manager, + vault_fee, + assets, }; e.events() @@ -56,7 +56,9 @@ pub struct NewDeFindexReceiverEvent { } pub(crate) fn emit_new_defindex_receiver(e: &Env, new_defindex_receiver: Address) { - let event = NewDeFindexReceiverEvent { new_defindex_receiver }; + let event = NewDeFindexReceiverEvent { + new_defindex_receiver, + }; e.events() .publish(("DeFindexFactory", symbol_short!("nreceiver")), event); @@ -74,4 +76,4 @@ pub(crate) fn emit_new_defindex_fee(e: &Env, new_defindex_fee: u32) { e.events() .publish(("DeFindexFactory", symbol_short!("n_fee")), event); -} \ No newline at end of file +} diff --git a/apps/contracts/factory/src/lib.rs b/apps/contracts/factory/src/lib.rs index 8bbb48ab..9730dd3c 100644 --- a/apps/contracts/factory/src/lib.rs +++ b/apps/contracts/factory/src/lib.rs @@ -1,43 +1,47 @@ #![no_std] -mod vault; +mod error; mod events; mod storage; -mod error; +mod vault; use common::models::AssetStrategySet; +use error::FactoryError; use soroban_sdk::{ - contract, contractimpl, vec, Address, BytesN, Env, Map, String, Symbol, Val, Vec, IntoVal + contract, contractimpl, vec, Address, BytesN, Env, IntoVal, Map, String, Symbol, Val, Vec, +}; +use storage::{ + add_new_defindex, extend_instance_ttl, get_admin, get_defindex_receiver, + get_deployed_defindexes, get_fee_rate, get_vault_wasm_hash, has_admin, put_admin, + put_defindex_fee, put_defindex_receiver, put_vault_wasm_hash, }; -use error::FactoryError; pub use vault::create_contract; -use storage::{ add_new_defindex, extend_instance_ttl, get_admin, get_vault_wasm_hash, get_defindex_receiver, get_deployed_defindexes, get_fee_rate, has_admin, put_admin, put_vault_wasm_hash, put_defindex_receiver, put_defindex_fee }; fn check_initialized(e: &Env) -> Result<(), FactoryError> { if !has_admin(e) { return Err(FactoryError::NotInitialized); - } + } Ok(()) } pub trait FactoryTrait { /// Initializes the factory contract with the given parameters. - /// + /// /// # Arguments /// * `e` - The environment in which the contract is running. /// * `admin` - The address of the contract administrator, who can manage settings. /// * `defindex_receiver` - The default address designated to receive a portion of fees. /// * `defindex_fee` - The initial annual fee rate (in basis points). /// * `vault_wasm_hash` - The hash of the DeFindex Vault's WASM file for deploying new vaults. - /// + /// /// # Returns /// * `Result<(), FactoryError>` - Returns Ok(()) if successful, otherwise an error. fn __constructor( - e: Env, + e: Env, admin: Address, defindex_receiver: Address, defindex_fee: u32, - vault_wasm_hash: BytesN<32> + vault_wasm_hash: BytesN<32>, ); /// Creates a new DeFindex Vault with specified parameters. @@ -56,15 +60,15 @@ pub trait FactoryTrait { /// # Returns /// * `Result` - Returns the address of the new vault, or an error if unsuccessful. fn create_defindex_vault( - e: Env, - emergency_manager: Address, - fee_receiver: Address, + e: Env, + emergency_manager: Address, + fee_receiver: Address, vault_fee: u32, - vault_name: String, - vault_symbol: String, manager: Address, assets: Vec, - salt: BytesN<32> + salt: BytesN<32>, + soroswap_router: Address, + name_symbol: Vec, ) -> Result; /// Creates a new DeFindex Vault with specified parameters and makes the first deposit to set ratios. @@ -84,21 +88,21 @@ pub trait FactoryTrait { /// # Returns /// * `Result` - Returns the address of the new vault, or an error if unsuccessful. fn create_defindex_vault_deposit( - e: Env, + e: Env, caller: Address, - emergency_manager: Address, - fee_receiver: Address, + emergency_manager: Address, + fee_receiver: Address, vault_fee: u32, - vault_name: String, - vault_symbol: String, manager: Address, assets: Vec, + salt: BytesN<32>, + soroswap_router: Address, + name_symbol: Vec, amounts: Vec, - salt: BytesN<32> ) -> Result; // --- Admin Functions --- - + /// Sets a new admin address. /// /// # Arguments @@ -128,7 +132,7 @@ pub trait FactoryTrait { /// # Returns /// * `Result<(), FactoryError>` - Returns Ok(()) if successful, or an error if not authorized. fn set_defindex_fee(e: Env, new_fee_rate: u32) -> Result<(), FactoryError>; - + // --- Read Methods --- /// Retrieves the current admin's address. @@ -139,7 +143,7 @@ pub trait FactoryTrait { /// # Returns /// * `Result` - Returns the admin's address or an error if not found. fn admin(e: Env) -> Result; - + /// Retrieves the current DeFindex receiver's address. /// /// # Arguments @@ -173,13 +177,12 @@ struct DeFindexFactory; #[contractimpl] impl FactoryTrait for DeFindexFactory { - fn __constructor( - e: Env, + e: Env, admin: Address, defindex_receiver: Address, defindex_fee: u32, - vault_wasm_hash: BytesN<32> + vault_wasm_hash: BytesN<32>, ) { put_admin(&e, &admin); put_defindex_receiver(&e, &defindex_receiver); @@ -190,19 +193,19 @@ impl FactoryTrait for DeFindexFactory { } /// Initializes the factory contract with the given parameters. - /// + /// /// # Arguments /// * `e` - The environment in which the contract is running. /// * `admin` - The address of the contract administrator, who can manage settings. /// * `defindex_receiver` - The default address designated to receive a portion of fees. /// * `defindex_fee` - The initial annual fee rate (in basis points). /// * `vault_wasm_hash` - The hash of the DeFindex Vault's WASM file for deploying new vaults. - /// + /// /// # Returns /// * `Result<(), FactoryError>` - Returns Ok(()) if successful, otherwise an error. // fn initialize( - // e: Env, - // admin: Address, + // e: Env, + // admin: Address, // defindex_receiver: Address, // defindex_fee: u32, // vault_wasm_hash: BytesN<32> @@ -235,22 +238,21 @@ impl FactoryTrait for DeFindexFactory { /// # Returns /// * `Result` - Returns the address of the new vault, or an error if unsuccessful. fn create_defindex_vault( - e: Env, - emergency_manager: Address, - fee_receiver: Address, + e: Env, + emergency_manager: Address, + fee_receiver: Address, vault_fee: u32, - vault_name: String, - vault_symbol: String, manager: Address, assets: Vec, - salt: BytesN<32> + salt: BytesN<32>, + soroswap_router: Address, + name_symbol: Vec, ) -> Result { extend_instance_ttl(&e); let current_contract = e.current_contract_address(); let vault_wasm_hash = get_vault_wasm_hash(&e)?; - let defindex_receiver = get_defindex_receiver(&e); let defindex_fee = get_fee_rate(&e); @@ -264,14 +266,21 @@ impl FactoryTrait for DeFindexFactory { init_args.push_back(defindex_receiver.to_val()); init_args.push_back(defindex_fee.into_val(&e)); init_args.push_back(current_contract.to_val()); - init_args.push_back(vault_name.to_val()); - init_args.push_back(vault_symbol.to_val()); + init_args.push_back(soroswap_router.to_val()); + init_args.push_back(name_symbol.to_val()); // e.invoke_contract::(&defindex_address, &Symbol::new(&e, "initialize"), init_args); let defindex_address = create_contract(&e, vault_wasm_hash, init_args, salt); add_new_defindex(&e, defindex_address.clone()); - events::emit_create_defindex_vault(&e, emergency_manager, fee_receiver, manager, vault_fee, assets); + events::emit_create_defindex_vault( + &e, + emergency_manager, + fee_receiver, + manager, + vault_fee, + assets, + ); Ok(defindex_address) } @@ -292,17 +301,17 @@ impl FactoryTrait for DeFindexFactory { /// # Returns /// * `Result` - Returns the address of the new vault, or an error if unsuccessful. fn create_defindex_vault_deposit( - e: Env, + e: Env, caller: Address, - emergency_manager: Address, - fee_receiver: Address, + emergency_manager: Address, + fee_receiver: Address, vault_fee: u32, - vault_name: String, - vault_symbol: String, manager: Address, assets: Vec, + salt: BytesN<32>, + soroswap_router: Address, + name_symbol: Vec, amounts: Vec, - salt: BytesN<32> ) -> Result { extend_instance_ttl(&e); caller.require_auth(); @@ -327,8 +336,8 @@ impl FactoryTrait for DeFindexFactory { init_args.push_back(defindex_receiver.to_val()); init_args.push_back(defindex_fee.into_val(&e)); init_args.push_back(current_contract.to_val()); - init_args.push_back(vault_name.to_val()); - init_args.push_back(vault_symbol.to_val()); + init_args.push_back(soroswap_router.to_val()); + init_args.push_back(name_symbol.to_val()); let defindex_address = create_contract(&e, vault_wasm_hash, init_args, salt); @@ -342,16 +351,23 @@ impl FactoryTrait for DeFindexFactory { deposit_args.push_back(amounts_min.to_val()); deposit_args.push_back(caller.to_val()); deposit_args.push_back(false.into_val(&e)); - + e.invoke_contract::(&defindex_address, &Symbol::new(&e, "deposit"), deposit_args); add_new_defindex(&e, defindex_address.clone()); - events::emit_create_defindex_vault(&e, emergency_manager, fee_receiver, manager, vault_fee, assets); + events::emit_create_defindex_vault( + &e, + emergency_manager, + fee_receiver, + manager, + vault_fee, + assets, + ); Ok(defindex_address) } // --- Admin Functions --- - + /// Sets a new admin address. /// /// # Arguments @@ -436,7 +452,7 @@ impl FactoryTrait for DeFindexFactory { extend_instance_ttl(&e); Ok(get_defindex_receiver(&e)) } - + /// Retrieves a map of all deployed DeFindex vaults. /// /// # Arguments @@ -464,4 +480,4 @@ impl FactoryTrait for DeFindexFactory { } } -mod test; \ No newline at end of file +mod test; diff --git a/apps/contracts/factory/src/storage.rs b/apps/contracts/factory/src/storage.rs index 7dca9473..b23ce7d4 100644 --- a/apps/contracts/factory/src/storage.rs +++ b/apps/contracts/factory/src/storage.rs @@ -1,7 +1,5 @@ -use soroban_sdk::{ - contracttype, Address, BytesN, Env, Map, TryFromVal, Val -}; use crate::error::FactoryError; +use soroban_sdk::{contracttype, Address, BytesN, Env, Map, TryFromVal, Val}; #[derive(Clone)] #[contracttype] @@ -30,19 +28,21 @@ pub fn extend_instance_ttl(e: &Env) { fn get_persistent_extend_or_error>( e: &Env, key: &DataKey, - error: FactoryError + error: FactoryError, ) -> Result { if let Some(result) = e.storage().persistent().get(key) { - e.storage() - .persistent() - .extend_ttl(key, PERSISTENT_LIFETIME_THRESHOLD, PERSISTENT_BUMP_AMOUNT); + e.storage().persistent().extend_ttl( + key, + PERSISTENT_LIFETIME_THRESHOLD, + PERSISTENT_BUMP_AMOUNT, + ); result } else { return Err(error); } } -pub fn get_vault_wasm_hash(e: &Env) -> Result, FactoryError>{ +pub fn get_vault_wasm_hash(e: &Env) -> Result, FactoryError> { let key = DataKey::DeFindexWasmHash; get_persistent_extend_or_error(&e, &key, FactoryError::NotInitialized) } @@ -51,8 +51,8 @@ pub fn put_vault_wasm_hash(e: &Env, vault_wasm_hash: BytesN<32>) { let key = DataKey::DeFindexWasmHash; e.storage().persistent().set(&key, &vault_wasm_hash); e.storage() - .persistent() - .extend_ttl(&key, PERSISTENT_LIFETIME_THRESHOLD, PERSISTENT_BUMP_AMOUNT) + .persistent() + .extend_ttl(&key, PERSISTENT_LIFETIME_THRESHOLD, PERSISTENT_BUMP_AMOUNT) } // Storing deployed defindexes @@ -65,12 +65,13 @@ fn put_deployed_defindexes(e: &Env, deployed_defindexes: Map) { let key = DataKey::DeFindexesMap; e.storage().persistent().set(&key, &deployed_defindexes); e.storage() - .persistent() - .extend_ttl(&key, PERSISTENT_LIFETIME_THRESHOLD, PERSISTENT_BUMP_AMOUNT) + .persistent() + .extend_ttl(&key, PERSISTENT_LIFETIME_THRESHOLD, PERSISTENT_BUMP_AMOUNT) } pub fn add_new_defindex(e: &Env, defindex_address: Address) { - let mut deployed_defindexes: Map = get_deployed_defindexes(&e).unwrap_or(Map::new(&e)); + let mut deployed_defindexes: Map = + get_deployed_defindexes(&e).unwrap_or(Map::new(&e)); let new_id = deployed_defindexes.len() as u32; deployed_defindexes.set(new_id, defindex_address); put_deployed_defindexes(&e, deployed_defindexes); @@ -91,11 +92,16 @@ pub fn get_admin(e: &Env) -> Address { // Fee Receiver pub fn put_defindex_receiver(e: &Env, address: &Address) { - e.storage().instance().set(&DataKey::DeFindexReceiver, address); + e.storage() + .instance() + .set(&DataKey::DeFindexReceiver, address); } pub fn get_defindex_receiver(e: &Env) -> Address { - e.storage().instance().get(&DataKey::DeFindexReceiver).unwrap() + e.storage() + .instance() + .get(&DataKey::DeFindexReceiver) + .unwrap() } // Fee Rate BPS (MAX BPS = 10000) @@ -105,4 +111,4 @@ pub fn put_defindex_fee(e: &Env, value: &u32) { pub fn get_fee_rate(e: &Env) -> u32 { e.storage().instance().get(&DataKey::FeeRate).unwrap() -} \ No newline at end of file +} diff --git a/apps/contracts/factory/src/test.rs b/apps/contracts/factory/src/test.rs index 11978c9a..33bab9db 100644 --- a/apps/contracts/factory/src/test.rs +++ b/apps/contracts/factory/src/test.rs @@ -5,47 +5,58 @@ use common::models::{AssetStrategySet, Strategy}; use soroban_sdk::token::{ StellarAssetClient as SorobanTokenAdminClient, TokenClient as SorobanTokenClient, }; +use soroban_sdk::{testutils::Address as _, vec as sorobanvec, Address, Env, String, Vec}; use soroban_sdk::{BytesN, Val}; -use soroban_sdk::{ - Env, - Address, - testutils::Address as _, - Vec, - vec as sorobanvec, - String -}; use std::vec; // DeFindex Hodl Strategy Contract mod hodl_strategy { - soroban_sdk::contractimport!(file = "../target/wasm32-unknown-unknown/release/hodl_strategy.optimized.wasm"); + soroban_sdk::contractimport!( + file = "../target/wasm32-unknown-unknown/release/hodl_strategy.optimized.wasm" + ); pub type StrategyContractClient<'a> = Client<'a>; } use hodl_strategy::StrategyContractClient; -fn create_strategy_contract<'a>(e: &Env, asset: &Address, init_args: &Vec) -> StrategyContractClient<'a> { +fn create_strategy_contract<'a>( + e: &Env, + asset: &Address, + init_args: &Vec, +) -> StrategyContractClient<'a> { let args = (asset.clone(), init_args.clone()); let address = &e.register(hodl_strategy::WASM, args); - let strategy = StrategyContractClient::new(e, address); + let strategy = StrategyContractClient::new(e, address); strategy -} +} // DeFindex Vault Contract -fn create_defindex_factory<'a>(e: &Env, admin: &Address, defindex_receiver: &Address, defindex_fee: u32, defindex_wasm_hash: &BytesN<32>) -> DeFindexFactoryClient<'a> { +fn create_defindex_factory<'a>( + e: &Env, + admin: &Address, + defindex_receiver: &Address, + defindex_fee: u32, + defindex_wasm_hash: &BytesN<32>, +) -> DeFindexFactoryClient<'a> { let args = (admin, defindex_receiver, defindex_fee, defindex_wasm_hash); DeFindexFactoryClient::new(e, &e.register(DeFindexFactory, args)) } // DeFindex Vault Contract mod defindex_vault_contract { - soroban_sdk::contractimport!(file = "../target/wasm32-unknown-unknown/release/defindex_vault.optimized.wasm"); + soroban_sdk::contractimport!( + file = "../target/wasm32-unknown-unknown/release/defindex_vault.optimized.wasm" + ); } // Create Test Token pub(crate) fn create_token_contract<'a>(e: &Env, admin: &Address) -> SorobanTokenClient<'a> { - SorobanTokenClient::new(e, &e.register_stellar_asset_contract_v2(admin.clone()).address()) + SorobanTokenClient::new( + e, + &e.register_stellar_asset_contract_v2(admin.clone()) + .address(), + ) } pub(crate) fn get_token_admin_client<'a>( @@ -105,13 +116,21 @@ impl<'a> DeFindexFactoryTest<'a> { let env = Env::default(); env.budget().reset_unlimited(); // env.mock_all_auths(); - + let admin = Address::generate(&env); let defindex_receiver = Address::generate(&env); - let defindex_wasm_hash = env.deployer().upload_contract_wasm(defindex_vault_contract::WASM); + let defindex_wasm_hash = env + .deployer() + .upload_contract_wasm(defindex_vault_contract::WASM); - let factory_contract = create_defindex_factory(&env, &admin, &defindex_receiver, 100u32, &defindex_wasm_hash); + let factory_contract = create_defindex_factory( + &env, + &admin, + &defindex_receiver, + 100u32, + &defindex_wasm_hash, + ); let emergency_manager = Address::generate(&env); let fee_receiver = Address::generate(&env); @@ -122,14 +141,15 @@ impl<'a> DeFindexFactoryTest<'a> { let token1_admin = Address::generate(&env); let token1 = create_token_contract(&env, &token1_admin); - + let token0_admin_client = get_token_admin_client(&env, &token0.address.clone()); let token1_admin_client = get_token_admin_client(&env, &token1.address.clone()); - // TODO: Add a strategy adapter, this is a mockup - let strategy_contract_token0 = create_strategy_contract(&env, &token0.address, &Vec::new(&env)); - let strategy_contract_token1 = create_strategy_contract(&env, &token1.address, &Vec::new(&env)); + let strategy_contract_token0 = + create_strategy_contract(&env, &token0.address, &Vec::new(&env)); + let strategy_contract_token1 = + create_strategy_contract(&env, &token1.address, &Vec::new(&env)); DeFindexFactoryTest { env, @@ -145,10 +165,10 @@ impl<'a> DeFindexFactoryTest<'a> { token1_admin_client, token1, strategy_contract_token0, - strategy_contract_token1 + strategy_contract_token1, } } - + pub(crate) fn generate_random_users(e: &Env, users_count: u32) -> vec::Vec
{ let mut users = vec![]; for _c in 0..users_count { @@ -158,4 +178,4 @@ impl<'a> DeFindexFactoryTest<'a> { } } -mod factory; \ No newline at end of file +mod factory; diff --git a/apps/contracts/factory/src/test/factory/admin.rs b/apps/contracts/factory/src/test/factory/admin.rs index 7f0dcbf4..7103fc13 100644 --- a/apps/contracts/factory/src/test/factory/admin.rs +++ b/apps/contracts/factory/src/test/factory/admin.rs @@ -1,4 +1,7 @@ -use soroban_sdk::{testutils::{AuthorizedFunction, AuthorizedInvocation, MockAuth, MockAuthInvoke}, Address, IntoVal, Symbol}; +use soroban_sdk::{ + testutils::{AuthorizedFunction, AuthorizedInvocation, MockAuth, MockAuthInvoke}, + Address, IntoVal, Symbol, +}; extern crate alloc; use alloc::vec; @@ -6,35 +9,28 @@ use crate::test::DeFindexFactoryTest; #[test] fn set_new_admin_by_admin() { - let test = DeFindexFactoryTest::setup(); let users = DeFindexFactoryTest::generate_random_users(&test.env, 1); test.factory_contract - .mock_auths(&[ - MockAuth { + .mock_auths(&[MockAuth { address: &test.admin, - invoke: - &MockAuthInvoke { - contract: &test.factory_contract.address.clone(), - fn_name: "set_new_admin", - args: (&users[0],).into_val(&test.env), - sub_invokes: &[], - }, - } - ]) - .set_new_admin(&users[0]); + invoke: &MockAuthInvoke { + contract: &test.factory_contract.address.clone(), + fn_name: "set_new_admin", + args: (&users[0],).into_val(&test.env), + sub_invokes: &[], + }, + }]) + .set_new_admin(&users[0]); let expected_auth = AuthorizedInvocation { function: AuthorizedFunction::Contract(( test.factory_contract.address.clone(), Symbol::new(&test.env, "set_new_admin"), - ( - users[0].clone(), - ) - .into_val(&test.env), + (users[0].clone(),).into_val(&test.env), )), - sub_invocations: vec![], + sub_invocations: vec![], }; assert_eq!(test.env.auths(), vec![(test.admin, expected_auth)]); @@ -49,19 +45,16 @@ fn set_new_admin_by_unauthorized() { let users = DeFindexFactoryTest::generate_random_users(&test.env, 1); test.factory_contract - .mock_auths(&[ - MockAuth { + .mock_auths(&[MockAuth { address: &users[0], - invoke: - &MockAuthInvoke { - contract: &test.factory_contract.address.clone(), - fn_name: "set_new_admin", - args: (&users[0],).into_val(&test.env), - sub_invokes: &[], - }, - } - ]) - .set_new_admin(&users[0]); + invoke: &MockAuthInvoke { + contract: &test.factory_contract.address.clone(), + fn_name: "set_new_admin", + args: (&users[0],).into_val(&test.env), + sub_invokes: &[], + }, + }]) + .set_new_admin(&users[0]); } #[test] @@ -70,30 +63,24 @@ fn set_defindex_receiver_by_admin() { let users = DeFindexFactoryTest::generate_random_users(&test.env, 1); test.factory_contract - .mock_auths(&[ - MockAuth { + .mock_auths(&[MockAuth { address: &test.admin, - invoke: - &MockAuthInvoke { - contract: &test.factory_contract.address.clone(), - fn_name: "set_defindex_receiver", - args: (&users[0],).into_val(&test.env), - sub_invokes: &[], - }, - } - ]) - .set_defindex_receiver(&users[0]); + invoke: &MockAuthInvoke { + contract: &test.factory_contract.address.clone(), + fn_name: "set_defindex_receiver", + args: (&users[0],).into_val(&test.env), + sub_invokes: &[], + }, + }]) + .set_defindex_receiver(&users[0]); let expected_auth = AuthorizedInvocation { function: AuthorizedFunction::Contract(( test.factory_contract.address.clone(), Symbol::new(&test.env, "set_defindex_receiver"), - ( - users[0].clone(), - ) - .into_val(&test.env), + (users[0].clone(),).into_val(&test.env), )), - sub_invocations: vec![], + sub_invocations: vec![], }; assert_eq!(test.env.auths(), vec![(test.admin, expected_auth)]); @@ -108,17 +95,14 @@ fn set_fee_receiver_by_unauthorized() { let users = DeFindexFactoryTest::generate_random_users(&test.env, 1); test.factory_contract - .mock_auths(&[ - MockAuth { + .mock_auths(&[MockAuth { address: &users[0], - invoke: - &MockAuthInvoke { - contract: &test.factory_contract.address.clone(), - fn_name: "set_defindex_receiver", - args: (&users[0],).into_val(&test.env), - sub_invokes: &[], - }, - } - ]) - .set_defindex_receiver(&users[0]); -} \ No newline at end of file + invoke: &MockAuthInvoke { + contract: &test.factory_contract.address.clone(), + fn_name: "set_defindex_receiver", + args: (&users[0],).into_val(&test.env), + sub_invokes: &[], + }, + }]) + .set_defindex_receiver(&users[0]); +} diff --git a/apps/contracts/factory/src/test/factory/budget.rs b/apps/contracts/factory/src/test/factory/budget.rs index bea39ddb..16fbabe5 100644 --- a/apps/contracts/factory/src/test/factory/budget.rs +++ b/apps/contracts/factory/src/test/factory/budget.rs @@ -1,84 +1,88 @@ extern crate std; use crate::test::{create_asset_params, create_defindex_factory, DeFindexFactoryTest}; -use soroban_sdk::{vec as sorobanvec, BytesN, String, Vec}; +use soroban_sdk::{vec, BytesN, String, Vec}; #[test] fn budget() { - - let test = DeFindexFactoryTest::setup(); - test.env.mock_all_auths(); - - test.env.budget().reset_unlimited(); - - // initialize factory contract - let factory_contract = create_defindex_factory( - &test.env, - &test.admin, - &test.defindex_receiver, - 2000u32, - &test.defindex_wasm_hash, - ); - - let mem = test.env.budget().memory_bytes_cost(); - let cpu = test.env.budget().cpu_instruction_cost(); - - std::println!("create_defindex_factory() | cpu: {}, mem: {}", cpu, mem); - - test.env.budget().reset_unlimited(); - - // create defindex vault - - let asset_params = create_asset_params(&test); - - let salt = BytesN::from_array(&test.env, &[0; 32]); - - let _ = factory_contract.create_defindex_vault( - &test.emergency_manager, - &test.fee_receiver, - &200u32, - &String::from_str(&test.env, "dfToken"), - &String::from_str(&test.env, "DFT"), - &test.admin, - &asset_params, - &salt - ); - - let mem = test.env.budget().memory_bytes_cost(); - let cpu = test.env.budget().cpu_instruction_cost(); - std::println!("create_defindex_vault() | cpu: {}, mem: {}", cpu, mem); - - test.env.budget().reset_unlimited(); - // create defindex vault deposit - let asset_params = create_asset_params(&test); - let salt = BytesN::from_array(&test.env, &[0; 32]); - - let amount_0 = 1000i128; - let amount_1 = 2000i128; - - let amounts: Vec = sorobanvec![&test.env, amount_0.clone(), amount_1.clone()]; - - // Mint tokens to manager - test.token0_admin_client.mint(&test.manager, &amount_0); - test.token1_admin_client.mint(&test.manager, &amount_1); - - test.factory_contract.create_defindex_vault_deposit( - &test.manager, - &test.emergency_manager, - &test.fee_receiver, - &2000u32, - &String::from_str(&test.env, "dfToken"), - &String::from_str(&test.env, "DFT"), - &test.manager, - &asset_params, - &amounts, - &salt - ); - - - let mem = test.env.budget().memory_bytes_cost(); - let cpu = test.env.budget().cpu_instruction_cost(); - std::println!("create_defindex_vault_deposit() | cpu: {}, mem: {}", cpu, mem); - - -} \ No newline at end of file + let test = DeFindexFactoryTest::setup(); + test.env.mock_all_auths(); + + test.env.budget().reset_unlimited(); + + // initialize factory contract + let factory_contract = create_defindex_factory( + &test.env, + &test.admin, + &test.defindex_receiver, + 2000u32, + &test.defindex_wasm_hash, + ); + + let mem = test.env.budget().memory_bytes_cost(); + let cpu = test.env.budget().cpu_instruction_cost(); + + std::println!("create_defindex_factory() | cpu: {}, mem: {}", cpu, mem); + + test.env.budget().reset_unlimited(); + + // create defindex vault + + let asset_params = create_asset_params(&test); + + let salt = BytesN::from_array(&test.env, &[0; 32]); + + let _ = factory_contract.create_defindex_vault( + &test.emergency_manager, + &test.fee_receiver, + &2000u32, + &test.manager, + &asset_params, + &salt, + &test.emergency_manager, //soroswap_router, + &vec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT"), + ], + ); + + let mem = test.env.budget().memory_bytes_cost(); + let cpu = test.env.budget().cpu_instruction_cost(); + std::println!("create_defindex_vault() | cpu: {}, mem: {}", cpu, mem); + + test.env.budget().reset_unlimited(); + // create defindex vault deposit + let asset_params = create_asset_params(&test); + let salt = BytesN::from_array(&test.env, &[0; 32]); + + let amount_0 = 1000i128; + let amount_1 = 2000i128; + + let amounts: Vec = vec![&test.env, amount_0.clone(), amount_1.clone()]; + + // Mint tokens to manager + test.token0_admin_client.mint(&test.manager, &amount_0); + test.token1_admin_client.mint(&test.manager, &amount_1); + + test.factory_contract.create_defindex_vault_deposit( + &test.manager, + &test.emergency_manager, + &test.fee_receiver, + &2000u32, + &test.manager, + &asset_params, + &salt, + &test.emergency_manager, //soroswap_router, + &vec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT"), + ], + &amounts, + ); + + let mem = test.env.budget().memory_bytes_cost(); + let cpu = test.env.budget().cpu_instruction_cost(); + std::println!("create_defindex_vault_deposit() | cpu: {}, mem: {}", cpu, mem); +} diff --git a/apps/contracts/factory/src/test/factory/create_defindex.rs b/apps/contracts/factory/src/test/factory/create_defindex.rs index 5cbb7878..d5dcbea9 100644 --- a/apps/contracts/factory/src/test/factory/create_defindex.rs +++ b/apps/contracts/factory/src/test/factory/create_defindex.rs @@ -4,65 +4,71 @@ use crate::test::{create_asset_params, DeFindexFactoryTest}; #[test] fn create_success() { - let test = DeFindexFactoryTest::setup(); - - let asset_params = create_asset_params(&test); - - let salt = BytesN::from_array(&test.env, &[0; 32]); - - test.factory_contract.create_defindex_vault( - &test.emergency_manager, - &test.fee_receiver, - &2000u32, - &String::from_str(&test.env, "dfToken"), - &String::from_str(&test.env, "DFT"), - &test.manager, - &asset_params, - &salt - ); - - let deployed_defindexes = test.factory_contract.deployed_defindexes(); - assert_eq!(deployed_defindexes.len(), 1); + let test = DeFindexFactoryTest::setup(); + + let asset_params = create_asset_params(&test); + + let salt = BytesN::from_array(&test.env, &[0; 32]); + + test.factory_contract.create_defindex_vault( + &test.emergency_manager, + &test.fee_receiver, + &2000u32, + &test.manager, + &asset_params, + &salt, + &test.emergency_manager, //soroswap_router, + &vec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT"), + ], + ); + + let deployed_defindexes = test.factory_contract.deployed_defindexes(); + assert_eq!(deployed_defindexes.len(), 1); } #[test] fn create_and_deposit_success() { - let test = DeFindexFactoryTest::setup(); - test.env.mock_all_auths(); - - let asset_params = create_asset_params(&test); - let salt = BytesN::from_array(&test.env, &[0; 32]); - - let amount_0 = 1000i128; - let amount_1 = 2000i128; - - let amounts: Vec = vec![&test.env, amount_0.clone(), amount_1.clone()]; - - // Mint tokens to manager - test.token0_admin_client.mint(&test.manager, &amount_0); - test.token1_admin_client.mint(&test.manager, &amount_1); - - test.factory_contract.create_defindex_vault_deposit( - &test.manager, - &test.emergency_manager, - &test.fee_receiver, - &2000u32, - &String::from_str(&test.env, "dfToken"), - &String::from_str(&test.env, "DFT"), - &test.manager, - &asset_params, - &amounts, - &salt - ); - - - let deployed_defindexes = test.factory_contract.deployed_defindexes(); - assert_eq!(deployed_defindexes.len(), 1); - - let token_0_vault_balance = test.token0.balance(&deployed_defindexes.get(0).unwrap()); - assert_eq!(token_0_vault_balance, amount_0); - - let token_1_vault_balance = test.token1.balance(&deployed_defindexes.get(0).unwrap()); - assert_eq!(token_1_vault_balance, amount_1); - -} \ No newline at end of file + let test = DeFindexFactoryTest::setup(); + test.env.mock_all_auths(); + + let asset_params = create_asset_params(&test); + let salt = BytesN::from_array(&test.env, &[0; 32]); + + let amount_0 = 1000i128; + let amount_1 = 2000i128; + + let amounts: Vec = vec![&test.env, amount_0.clone(), amount_1.clone()]; + + // Mint tokens to manager + test.token0_admin_client.mint(&test.manager, &amount_0); + test.token1_admin_client.mint(&test.manager, &amount_1); + + test.factory_contract.create_defindex_vault_deposit( + &test.manager, + &test.emergency_manager, + &test.fee_receiver, + &2000u32, + &test.manager, + &asset_params, + &salt, + &test.emergency_manager, //soroswap_router, + &vec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT"), + ], + &amounts, + ); + + let deployed_defindexes = test.factory_contract.deployed_defindexes(); + assert_eq!(deployed_defindexes.len(), 1); + + let token_0_vault_balance = test.token0.balance(&deployed_defindexes.get(0).unwrap()); + assert_eq!(token_0_vault_balance, amount_0); + + let token_1_vault_balance = test.token1.balance(&deployed_defindexes.get(0).unwrap()); + assert_eq!(token_1_vault_balance, amount_1); +} diff --git a/apps/contracts/factory/src/test/factory/initialize.rs b/apps/contracts/factory/src/test/factory/initialize.rs index 379df483..856f6b07 100644 --- a/apps/contracts/factory/src/test/factory/initialize.rs +++ b/apps/contracts/factory/src/test/factory/initialize.rs @@ -6,7 +6,7 @@ fn get_storage() { let factory_admin = test.factory_contract.admin(); let factory_defindex_receiver = test.factory_contract.defindex_receiver(); - + assert_eq!(factory_admin, test.admin); assert_eq!(factory_defindex_receiver, test.defindex_receiver); -} \ No newline at end of file +} diff --git a/apps/contracts/factory/src/test/factory/mod.rs b/apps/contracts/factory/src/test/factory/mod.rs index 77931274..bab127bb 100644 --- a/apps/contracts/factory/src/test/factory/mod.rs +++ b/apps/contracts/factory/src/test/factory/mod.rs @@ -1,4 +1,4 @@ mod admin; +mod budget; mod create_defindex; mod initialize; -mod budget; \ No newline at end of file diff --git a/apps/contracts/factory/src/vault.rs b/apps/contracts/factory/src/vault.rs index 616d766e..b27a787e 100644 --- a/apps/contracts/factory/src/vault.rs +++ b/apps/contracts/factory/src/vault.rs @@ -3,13 +3,12 @@ use soroban_sdk::{contracterror, contracttype, xdr::ToXdr, Address, Bytes, Bytes // Define a function to create a new contract instance pub fn create_contract( - e: &Env, // Pass in the current environment as an argument + e: &Env, // Pass in the current environment as an argument defindex_wasm_hash: BytesN<32>, // Pass in the hash of the token contract's WASM file constructor_args: Vec, salt: BytesN<32>, ) -> Address { - e.deployer() - .with_current_contract(salt) + .with_current_contract(salt) .deploy_v2(defindex_wasm_hash, constructor_args) -} \ No newline at end of file +} diff --git a/apps/contracts/integration-test/src/factory.rs b/apps/contracts/integration-test/src/factory.rs index 5fdba2c6..e2dadd74 100644 --- a/apps/contracts/integration-test/src/factory.rs +++ b/apps/contracts/integration-test/src/factory.rs @@ -1,17 +1,30 @@ mod factory_contract { - soroban_sdk::contractimport!(file = "../target/wasm32-unknown-unknown/release/defindex_factory.optimized.wasm"); + soroban_sdk::contractimport!( + file = "../target/wasm32-unknown-unknown/release/defindex_factory.optimized.wasm" + ); pub type DeFindexFactoryClient<'a> = Client<'a>; } -pub use factory_contract::{AssetStrategySet, Strategy, DeFindexFactoryClient}; +pub use factory_contract::{AssetStrategySet, DeFindexFactoryClient, Strategy}; use soroban_sdk::{Address, BytesN, Env}; // DeFindex Factory Contract -pub fn create_factory_contract<'a>(e: &Env, admin: &Address, defindex_receiver: &Address, defindex_fee: &u32, vault_wasm_hash: &BytesN<32>) -> DeFindexFactoryClient<'a> { - let args = (admin.clone(), defindex_receiver.clone(), defindex_fee.clone(), vault_wasm_hash.clone()); +pub fn create_factory_contract<'a>( + e: &Env, + admin: &Address, + defindex_receiver: &Address, + defindex_fee: &u32, + vault_wasm_hash: &BytesN<32>, +) -> DeFindexFactoryClient<'a> { + let args = ( + admin.clone(), + defindex_receiver.clone(), + defindex_fee.clone(), + vault_wasm_hash.clone(), + ); let address = &e.register(factory_contract::WASM, args); - let factory = DeFindexFactoryClient::new(e, address); + let factory = DeFindexFactoryClient::new(e, address); factory -} \ No newline at end of file +} diff --git a/apps/contracts/integration-test/src/fixed_strategy.rs b/apps/contracts/integration-test/src/fixed_strategy.rs index 675e0f4a..a2c60889 100644 --- a/apps/contracts/integration-test/src/fixed_strategy.rs +++ b/apps/contracts/integration-test/src/fixed_strategy.rs @@ -1,23 +1,31 @@ // DeFindex Hodl Strategy Contract mod fixed_strategy { - soroban_sdk::contractimport!(file = "../target/wasm32-unknown-unknown/release/fixed_apr_strategy.optimized.wasm"); + soroban_sdk::contractimport!( + file = "../target/wasm32-unknown-unknown/release/fixed_apr_strategy.optimized.wasm" + ); pub type FixedStrategyClient<'a> = Client<'a>; } pub use fixed_strategy::FixedStrategyClient; use soroban_sdk::{token::StellarAssetClient, vec, Address, Env, IntoVal, Val, Vec}; -pub fn create_fixed_strategy_contract<'a>(e: &Env, asset: &Address, apr_bps: u32, token_admin_client: &StellarAssetClient) -> FixedStrategyClient<'a> { - let init_args: Vec= vec![e, apr_bps.into_val(e)]; +pub fn create_fixed_strategy_contract<'a>( + e: &Env, + asset: &Address, + apr_bps: u32, + token_admin_client: &StellarAssetClient, +) -> FixedStrategyClient<'a> { + let init_args: Vec = vec![e, apr_bps.into_val(e)]; let args = (asset, init_args); - + let client = FixedStrategyClient::new(e, &e.register(fixed_strategy::WASM, args)); // Mint 100M to the strategy let starting_amount = 100_000_000_000_0_000_000i128; - token_admin_client.mock_all_auths().mint(&client.address, &starting_amount); + token_admin_client + .mock_all_auths() + .mint(&client.address, &starting_amount); client } - diff --git a/apps/contracts/integration-test/src/hodl_strategy.rs b/apps/contracts/integration-test/src/hodl_strategy.rs index dcd93a19..fb5b4dda 100644 --- a/apps/contracts/integration-test/src/hodl_strategy.rs +++ b/apps/contracts/integration-test/src/hodl_strategy.rs @@ -1,15 +1,17 @@ // DeFindex Hodl Strategy Contract mod hodl_strategy { - soroban_sdk::contractimport!(file = "../target/wasm32-unknown-unknown/release/hodl_strategy.optimized.wasm"); + soroban_sdk::contractimport!( + file = "../target/wasm32-unknown-unknown/release/hodl_strategy.optimized.wasm" + ); pub type HodlStrategyClient<'a> = Client<'a>; } pub use hodl_strategy::HodlStrategyClient; -use soroban_sdk::{Address, Env, Val, Vec, vec}; +use soroban_sdk::{vec, Address, Env, Val, Vec}; pub fn create_hodl_strategy_contract<'a>(e: &Env, asset: &Address) -> HodlStrategyClient<'a> { - let init_args: Vec= vec![e]; + let init_args: Vec = vec![e]; let args = (asset.clone(), init_args); HodlStrategyClient::new(e, &e.register(hodl_strategy::WASM, args)) -} \ No newline at end of file +} diff --git a/apps/contracts/integration-test/src/lib.rs b/apps/contracts/integration-test/src/lib.rs index 5eaa850f..513aaeea 100644 --- a/apps/contracts/integration-test/src/lib.rs +++ b/apps/contracts/integration-test/src/lib.rs @@ -1,8 +1,8 @@ #![allow(clippy::all)] +pub mod factory; +pub mod fixed_strategy; +pub mod hodl_strategy; +pub mod setup; pub mod test; pub mod token; -pub mod hodl_strategy; -pub mod fixed_strategy; pub mod vault; -pub mod factory; -pub mod setup; \ No newline at end of file diff --git a/apps/contracts/integration-test/src/setup.rs b/apps/contracts/integration-test/src/setup.rs index 02ddb4cb..f96dc8d1 100644 --- a/apps/contracts/integration-test/src/setup.rs +++ b/apps/contracts/integration-test/src/setup.rs @@ -2,11 +2,11 @@ use soroban_sdk::token::{StellarAssetClient, TokenClient}; use soroban_sdk::BytesN; use soroban_sdk::{testutils::Address as _, vec as sorobanvec, Address, String}; +use crate::factory::{AssetStrategySet, Strategy}; use crate::fixed_strategy::{create_fixed_strategy_contract, FixedStrategyClient}; use crate::hodl_strategy::{create_hodl_strategy_contract, HodlStrategyClient}; use crate::test::IntegrationTest; use crate::token::create_token; -use crate::factory::{AssetStrategySet, Strategy}; use crate::vault::defindex_vault_contract::VaultContractClient; pub struct VaultOneAseetHodlStrategy<'a> { @@ -38,7 +38,7 @@ pub fn create_vault_one_asset_hodl_strategy<'a>() -> VaultOneAseetHodlStrategy<' let vault_name = String::from_str(&setup.env, "HodlVault"); let vault_symbol = String::from_str(&setup.env, "HVLT"); let manager = Address::generate(&setup.env); - + let assets = sorobanvec![ &setup.env, AssetStrategySet { @@ -57,14 +57,14 @@ pub fn create_vault_one_asset_hodl_strategy<'a>() -> VaultOneAseetHodlStrategy<' let salt = BytesN::from_array(&setup.env, &[0; 32]); let vault_contract_address = setup.factory_contract.create_defindex_vault( - &emergency_manager, - &fee_receiver, - &vault_fee, - &vault_name, - &vault_symbol, - &manager, - &assets, - &salt + &emergency_manager, + &fee_receiver, + &vault_fee, + &vault_name, + &vault_symbol, + &manager, + &assets, + &salt, ); let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); @@ -103,7 +103,8 @@ pub fn create_vault_one_asset_fixed_strategy<'a>() -> VaultOneAseetFixedStrategy let (token, token_admin_client) = create_token(&setup.env, &token_admin); setup.env.mock_all_auths(); - let strategy_contract = create_fixed_strategy_contract(&setup.env, &token.address, 1000u32, &token_admin_client); + let strategy_contract = + create_fixed_strategy_contract(&setup.env, &token.address, 1000u32, &token_admin_client); let emergency_manager = Address::generate(&setup.env); let fee_receiver = Address::generate(&setup.env); @@ -111,7 +112,7 @@ pub fn create_vault_one_asset_fixed_strategy<'a>() -> VaultOneAseetFixedStrategy let vault_name = String::from_str(&setup.env, "FixedVault"); let vault_symbol = String::from_str(&setup.env, "FVLT"); let manager = Address::generate(&setup.env); - + let assets = sorobanvec![ &setup.env, AssetStrategySet { @@ -130,14 +131,14 @@ pub fn create_vault_one_asset_fixed_strategy<'a>() -> VaultOneAseetFixedStrategy let salt = BytesN::from_array(&setup.env, &[0; 32]); let vault_contract_address = setup.factory_contract.create_defindex_vault( - &emergency_manager, - &fee_receiver, - &vault_fee, - &vault_name, - &vault_symbol, - &manager, - &assets, - &salt + &emergency_manager, + &fee_receiver, + &vault_fee, + &vault_name, + &vault_symbol, + &manager, + &assets, + &salt, ); let vault_contract = VaultContractClient::new(&setup.env, &vault_contract_address); @@ -228,11 +229,13 @@ mod tests { ], } ]; - + let vault_assets = enviroment.vault_contract.get_assets(); assert_eq!(vault_assets, assets); - let strategy_contract_balance = enviroment.token.balance(&enviroment.strategy_contract.address); + let strategy_contract_balance = enviroment + .token + .balance(&enviroment.strategy_contract.address); assert_eq!(strategy_contract_balance, 100_000_000_000_0_000_000i128); let vault_emergency_manager = enviroment.vault_contract.get_emergency_manager(); @@ -250,5 +253,4 @@ mod tests { let vault_symbol = enviroment.vault_contract.symbol(); assert_eq!(vault_symbol, String::from_str(&setup.env, "FVLT")); } - -} \ No newline at end of file +} diff --git a/apps/contracts/integration-test/src/test.rs b/apps/contracts/integration-test/src/test.rs index 3ddb643c..778a5d97 100644 --- a/apps/contracts/integration-test/src/test.rs +++ b/apps/contracts/integration-test/src/test.rs @@ -1,10 +1,9 @@ extern crate std; use crate::factory::DeFindexFactoryClient; use soroban_sdk::{ - testutils::{LedgerInfo, Ledger}, - Env, - Address, testutils::Address as _, + testutils::{Ledger, LedgerInfo}, + Address, Env, }; use std::vec as std_vec; @@ -20,7 +19,7 @@ pub struct IntegrationTest<'a> { pub factory_contract: DeFindexFactoryClient<'a>, pub admin: Address, pub defindex_receiver: Address, - pub defindex_fee: u32 + pub defindex_fee: u32, } pub trait EnvTestUtils { @@ -28,7 +27,6 @@ pub trait EnvTestUtils { fn jump(&self, ledgers: u32); /// Jump the env by the given amount of seconds. Incremends the sequence by 1. fn jump_time(&self, seconds: u64); - } impl EnvTestUtils for Env { @@ -45,7 +43,6 @@ impl EnvTestUtils for Env { }); } - fn jump_time(&self, seconds: u64) { self.ledger().set(LedgerInfo { timestamp: self.ledger().timestamp().saturating_add(seconds), @@ -63,14 +60,22 @@ impl EnvTestUtils for Env { impl<'a> IntegrationTest<'a> { pub fn setup() -> Self { let env = Env::default(); - + let admin = Address::generate(&env); let defindex_receiver = Address::generate(&env); - let vault_wasm_hash = env.deployer().upload_contract_wasm(defindex_vault_contract::WASM); + let vault_wasm_hash = env + .deployer() + .upload_contract_wasm(defindex_vault_contract::WASM); let defindex_fee = DEFINDEX_FEE; - let factory_contract = create_factory_contract(&env, &admin, &defindex_receiver, &defindex_fee, &vault_wasm_hash); + let factory_contract = create_factory_contract( + &env, + &admin, + &defindex_receiver, + &defindex_fee, + &vault_wasm_hash, + ); env.budget().reset_unlimited(); @@ -79,10 +84,10 @@ impl<'a> IntegrationTest<'a> { factory_contract, admin, defindex_receiver, - defindex_fee + defindex_fee, } } - + pub fn generate_random_users(e: &Env, users_count: u32) -> std_vec::Vec
{ let mut users = std_vec![]; for _c in 0..users_count { @@ -93,5 +98,5 @@ impl<'a> IntegrationTest<'a> { } // #[cfg(test)] +mod vault_one_fixed_strategy; mod vault_one_hodl_strategy; -mod vault_one_fixed_strategy; \ No newline at end of file diff --git a/apps/contracts/integration-test/src/test/vault_one_fixed_strategy/deposit.rs b/apps/contracts/integration-test/src/test/vault_one_fixed_strategy/deposit.rs index f7cd7d8d..0608c456 100644 --- a/apps/contracts/integration-test/src/test/vault_one_fixed_strategy/deposit.rs +++ b/apps/contracts/integration-test/src/test/vault_one_fixed_strategy/deposit.rs @@ -1,5 +1,12 @@ -use crate::{setup::create_vault_one_asset_fixed_strategy, test::IntegrationTest, vault::{VaultContractError, MINIMUM_LIQUIDITY}}; -use soroban_sdk::{testutils::{MockAuth, MockAuthInvoke}, vec as svec, IntoVal, Vec}; +use crate::{ + setup::create_vault_one_asset_fixed_strategy, + test::IntegrationTest, + vault::{VaultContractError, MINIMUM_LIQUIDITY}, +}; +use soroban_sdk::{ + testutils::{MockAuth, MockAuthInvoke}, + vec as svec, IntoVal, Vec, +}; #[test] fn fixed_apr_deposit_success() { @@ -11,52 +18,64 @@ fn fixed_apr_deposit_success() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); let deposit_amount = 10_000_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user.clone(), + user.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); let vault_balance = enviroment.token.balance(&enviroment.vault_contract.address); assert_eq!(vault_balance, deposit_amount); let user_balance_after_deposit = enviroment.token.balance(user); - assert_eq!(user_balance_after_deposit, user_starting_balance - deposit_amount); + assert_eq!( + user_balance_after_deposit, + user_starting_balance - deposit_amount + ); let df_balance = enviroment.vault_contract.balance(&user); assert_eq!(df_balance, deposit_amount - MINIMUM_LIQUIDITY); @@ -76,46 +95,55 @@ fn fixed_apr_deposit_insufficient_balance() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); let deposit_amount = 10_000_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user.clone(), + user.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); } #[test] @@ -129,24 +157,30 @@ fn fixed_apr_deposit_multiple_users() { let user1 = &users[0]; let user2 = &users[1]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user1, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user1, &user_starting_balance); - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user2, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user2, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user1, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user1, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user2, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user2, &user_starting_balance); let user1_balance = enviroment.token.balance(user1); let user2_balance = enviroment.token.balance(user2); @@ -154,69 +188,87 @@ fn fixed_apr_deposit_multiple_users() { assert_eq!(user2_balance, user_starting_balance); let deposit_amount = 10_000_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user1.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user1.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user1.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user1.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user1.clone(), + user1.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user1, &false); - - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user2.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user2.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user1, + &false, + ); + + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user2.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user2.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user2.clone(), + user2.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user2, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user2, + &false, + ); let vault_balance = enviroment.token.balance(&enviroment.vault_contract.address); assert_eq!(vault_balance, deposit_amount * 2); let user1_balance_after_deposit = enviroment.token.balance(user1); let user2_balance_after_deposit = enviroment.token.balance(user2); - assert_eq!(user1_balance_after_deposit, user_starting_balance - deposit_amount); - assert_eq!(user2_balance_after_deposit, user_starting_balance - deposit_amount); + assert_eq!( + user1_balance_after_deposit, + user_starting_balance - deposit_amount + ); + assert_eq!( + user2_balance_after_deposit, + user_starting_balance - deposit_amount + ); let df_balance_user1 = enviroment.vault_contract.balance(&user1); let df_balance_user2 = enviroment.vault_contract.balance(&user2); @@ -237,15 +289,18 @@ fn fixed_apr_deposit_zero_amount() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); @@ -254,7 +309,7 @@ fn fixed_apr_deposit_zero_amount() { &svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, - &false + &false, ); assert_eq!(result, Err(Ok(VaultContractError::InsufficientAmount))); @@ -270,15 +325,18 @@ fn fixed_apr_deposit_negative_amount() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); @@ -287,7 +345,7 @@ fn fixed_apr_deposit_negative_amount() { &svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, - &false + &false, ); assert_eq!(result, Err(Ok(VaultContractError::NegativeNotAllowed))); @@ -303,15 +361,18 @@ fn fixed_apr_deposit_insufficient_minimum_liquidity() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); @@ -320,8 +381,8 @@ fn fixed_apr_deposit_insufficient_minimum_liquidity() { &svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, - &false + &false, ); assert_eq!(result, Err(Ok(VaultContractError::InsufficientAmount))); -} \ No newline at end of file +} diff --git a/apps/contracts/integration-test/src/test/vault_one_fixed_strategy/fee_performance.rs b/apps/contracts/integration-test/src/test/vault_one_fixed_strategy/fee_performance.rs index ad252b13..968a3dce 100644 --- a/apps/contracts/integration-test/src/test/vault_one_fixed_strategy/fee_performance.rs +++ b/apps/contracts/integration-test/src/test/vault_one_fixed_strategy/fee_performance.rs @@ -1,5 +1,15 @@ -use crate::{setup::create_vault_one_asset_fixed_strategy, test::{EnvTestUtils, IntegrationTest, ONE_YEAR_IN_SECONDS}, vault::{defindex_vault_contract::{AssetInvestmentAllocation, StrategyAllocation}, VaultContractError, MINIMUM_LIQUIDITY}}; -use soroban_sdk::{testutils::{Ledger, MockAuth, MockAuthInvoke}, vec as svec, IntoVal, Vec}; +use crate::{ + setup::create_vault_one_asset_fixed_strategy, + test::{EnvTestUtils, IntegrationTest, ONE_YEAR_IN_SECONDS}, + vault::{ + defindex_vault_contract::{AssetInvestmentAllocation, StrategyAllocation}, + VaultContractError, MINIMUM_LIQUIDITY, + }, +}; +use soroban_sdk::{ + testutils::{Ledger, MockAuth, MockAuthInvoke}, + vec as svec, IntoVal, Vec, +}; #[test] fn fee_performance() { @@ -11,46 +21,55 @@ fn fee_performance() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); let deposit_amount = 100_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user.clone(), + user.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); // Create investment strategies for the deposited tokens let investments = svec![ @@ -67,33 +86,34 @@ fn fee_performance() { }), ]; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &enviroment.manager.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "invest", - args: ( - Vec::from_array(&setup.env,[ - Some( - AssetInvestmentAllocation { - asset: enviroment.token.address.clone(), - strategy_allocations: - svec![&setup.env, - Some(StrategyAllocation { - amount: deposit_amount, - strategy_address: enviroment.strategy_contract.address.clone(), - }) - ] - } - ) - ]), - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .invest(&investments); - let vault_balance_in_strategy = enviroment.strategy_contract.balance(&enviroment.vault_contract.address); + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &enviroment.manager.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "invest", + args: (Vec::from_array( + &setup.env, + [Some(AssetInvestmentAllocation { + asset: enviroment.token.address.clone(), + strategy_allocations: svec![ + &setup.env, + Some(StrategyAllocation { + amount: deposit_amount, + strategy_address: enviroment.strategy_contract.address.clone(), + }) + ], + })], + ),) + .into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .invest(&investments); + let vault_balance_in_strategy = enviroment + .strategy_contract + .balance(&enviroment.vault_contract.address); std::println!("Shares: {:?}", vault_balance_in_strategy); @@ -101,78 +121,120 @@ fn fee_performance() { setup.env.jump_time(ONE_YEAR_IN_SECONDS); // Harvest - enviroment.strategy_contract.harvest(&enviroment.vault_contract.address); + enviroment + .strategy_contract + .harvest(&enviroment.vault_contract.address); - let vault_balance_in_strategy = enviroment.strategy_contract.balance(&enviroment.vault_contract.address); + let vault_balance_in_strategy = enviroment + .strategy_contract + .balance(&enviroment.vault_contract.address); std::println!("Shares after one year: {:?}", vault_balance_in_strategy); // Report let _report = enviroment.vault_contract.mock_all_auths().report(); - + let expected_balance = deposit_amount * 11 / 10; // 10% fixed APR assert_eq!(vault_balance_in_strategy, expected_balance); // Lock fees let lock_fees_bps = 2000u32; - let lock_fees_result = enviroment.vault_contract.mock_auths(&[MockAuth { - address: &enviroment.manager.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "lock_fees", - args: svec![&setup.env, lock_fees_bps].into_val(&setup.env), - sub_invokes: &[] - }, - }]).lock_fees(&Some(lock_fees_bps)); + let lock_fees_result = enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &enviroment.manager.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "lock_fees", + args: svec![&setup.env, lock_fees_bps].into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .lock_fees(&Some(lock_fees_bps)); let locked_fee = lock_fees_result.get(0).unwrap().locked_fee; - - let total_funds_after_lock = enviroment.vault_contract.fetch_total_managed_funds().get(token_address.clone()).unwrap().total_amount; - assert_eq!( total_funds_after_lock, (expected_balance - locked_fee)); - + + let total_funds_after_lock = enviroment + .vault_contract + .fetch_total_managed_funds() + .get(token_address.clone()) + .unwrap() + .total_amount; + assert_eq!(total_funds_after_lock, (expected_balance - locked_fee)); + // Release fees let release_fees_amount = 2_0_000_000i128; // release all locked fees (10_0_000_000 * 0.2 = 2_0_000_000) - let _release_fees_result = enviroment.vault_contract.mock_auths(&[MockAuth { - address: &enviroment.manager.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "release_fees", - args: ( - &enviroment.strategy_contract.address.clone(), - release_fees_amount - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]).release_fees(&enviroment.strategy_contract.address.clone(), &release_fees_amount); - - let total_funds_after_release = enviroment.vault_contract.fetch_total_managed_funds().get(token_address.clone()).unwrap().total_amount; - assert_eq!( total_funds_after_release, (total_funds_after_lock + release_fees_amount)); + let _release_fees_result = enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &enviroment.manager.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "release_fees", + args: ( + &enviroment.strategy_contract.address.clone(), + release_fees_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .release_fees( + &enviroment.strategy_contract.address.clone(), + &release_fees_amount, + ); + + let total_funds_after_release = enviroment + .vault_contract + .fetch_total_managed_funds() + .get(token_address.clone()) + .unwrap() + .total_amount; + assert_eq!( + total_funds_after_release, + (total_funds_after_lock + release_fees_amount) + ); // Lock fees let lock_fees_bps = 2000u32; - let _lock_fees_result = enviroment.vault_contract.mock_auths(&[MockAuth { - address: &enviroment.manager.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "lock_fees", - args: svec![&setup.env, lock_fees_bps].into_val(&setup.env), - sub_invokes: &[] - }, - }]).lock_fees(&Some(lock_fees_bps)); - - let total_funds_after_lock = enviroment.vault_contract.fetch_total_managed_funds().get(token_address.clone()).unwrap().total_amount; - + let _lock_fees_result = enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &enviroment.manager.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "lock_fees", + args: svec![&setup.env, lock_fees_bps].into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .lock_fees(&Some(lock_fees_bps)); + + let total_funds_after_lock = enviroment + .vault_contract + .fetch_total_managed_funds() + .get(token_address.clone()) + .unwrap() + .total_amount; // Distribute fees - let _distribute_fees_result = enviroment.vault_contract.mock_auths(&[MockAuth { - address: &enviroment.manager.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "distribute_fees", - args: ().into_val(&setup.env), - sub_invokes: &[] - }, - }]).distribute_fees(); - - let total_funds_after_distribute = enviroment.vault_contract.fetch_total_managed_funds().get(token_address.clone()).unwrap().total_amount; + let _distribute_fees_result = enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &enviroment.manager.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "distribute_fees", + args: ().into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .distribute_fees(); + + let total_funds_after_distribute = enviroment + .vault_contract + .fetch_total_managed_funds() + .get(token_address.clone()) + .unwrap() + .total_amount; assert_eq!(total_funds_after_distribute, total_funds_after_lock); -} \ No newline at end of file +} diff --git a/apps/contracts/integration-test/src/test/vault_one_fixed_strategy/mod.rs b/apps/contracts/integration-test/src/test/vault_one_fixed_strategy/mod.rs index d58495a3..971e963d 100644 --- a/apps/contracts/integration-test/src/test/vault_one_fixed_strategy/mod.rs +++ b/apps/contracts/integration-test/src/test/vault_one_fixed_strategy/mod.rs @@ -11,4 +11,4 @@ pub fn calculate_yield(user_balance: i128, apr: u32, time_elapsed: u64) -> i128 let time_elapsed_i128 = time_elapsed as i128; (user_balance * apr_bps * time_elapsed_i128) / (seconds_per_year as i128 * 10000) -} \ No newline at end of file +} diff --git a/apps/contracts/integration-test/src/test/vault_one_fixed_strategy/withdraw.rs b/apps/contracts/integration-test/src/test/vault_one_fixed_strategy/withdraw.rs index 64aad4bd..4c5fa4b5 100644 --- a/apps/contracts/integration-test/src/test/vault_one_fixed_strategy/withdraw.rs +++ b/apps/contracts/integration-test/src/test/vault_one_fixed_strategy/withdraw.rs @@ -1,5 +1,18 @@ -use crate::{setup::{create_vault_one_asset_fixed_strategy, VAULT_FEE}, test::{vault_one_fixed_strategy::calculate_yield, IntegrationTest, DEFINDEX_FEE, ONE_YEAR_IN_SECONDS}, vault::{defindex_vault_contract::{AssetInvestmentAllocation, StrategyAllocation}, MINIMUM_LIQUIDITY}}; -use soroban_sdk::{testutils::{Ledger, MockAuth, MockAuthInvoke}, vec as svec, IntoVal, Vec}; +use crate::{ + setup::{create_vault_one_asset_fixed_strategy, VAULT_FEE}, + test::{ + vault_one_fixed_strategy::calculate_yield, IntegrationTest, DEFINDEX_FEE, + ONE_YEAR_IN_SECONDS, + }, + vault::{ + defindex_vault_contract::{AssetInvestmentAllocation, StrategyAllocation}, + MINIMUM_LIQUIDITY, + }, +}; +use soroban_sdk::{ + testutils::{Ledger, MockAuth, MockAuthInvoke}, + vec as svec, IntoVal, Vec, +}; #[test] fn fixed_apr_no_invest_withdraw_success() { @@ -12,64 +25,79 @@ fn fixed_apr_no_invest_withdraw_success() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); - - enviroment.vault_contract.mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); + + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user.clone(), + user.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); - setup.env.ledger().set_timestamp(setup.env.ledger().timestamp() + ONE_YEAR_IN_SECONDS); + setup + .env + .ledger() + .set_timestamp(setup.env.ledger().timestamp() + ONE_YEAR_IN_SECONDS); // // TODO: The vault should call harvest method on the strategy contract // enviroment.strategy_contract.mock_all_auths().harvest(&enviroment.vault_contract.address); let df_balance_before_withdraw = enviroment.vault_contract.balance(&user); - assert_eq!(df_balance_before_withdraw, deposit_amount - MINIMUM_LIQUIDITY); - - enviroment.vault_contract.mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "withdraw", - args: ( - df_balance_before_withdraw.clone(), - user.clone() - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .withdraw(&df_balance_before_withdraw, &user); + assert_eq!( + df_balance_before_withdraw, + deposit_amount - MINIMUM_LIQUIDITY + ); + + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "withdraw", + args: (df_balance_before_withdraw.clone(), user.clone()).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .withdraw(&df_balance_before_withdraw, &user); let expected_amount_user = deposit_amount - MINIMUM_LIQUIDITY; @@ -94,42 +122,52 @@ fn fixed_apr_invest_withdraw_success() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); - - enviroment.vault_contract.mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); + + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user.clone(), + user.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); let investments = svec![ &setup.env, @@ -145,63 +183,71 @@ fn fixed_apr_invest_withdraw_success() { }), ]; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &enviroment.manager.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "invest", - args: ( - Vec::from_array(&setup.env,[ - Some( - AssetInvestmentAllocation { - asset: enviroment.token.address.clone(), - strategy_allocations: - svec![&setup.env, - Some(StrategyAllocation { - amount: deposit_amount, - strategy_address: enviroment.strategy_contract.address.clone(), - }) - ] - } - ) - ]), - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .invest(&investments); + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &enviroment.manager.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "invest", + args: (Vec::from_array( + &setup.env, + [Some(AssetInvestmentAllocation { + asset: enviroment.token.address.clone(), + strategy_allocations: svec![ + &setup.env, + Some(StrategyAllocation { + amount: deposit_amount, + strategy_address: enviroment.strategy_contract.address.clone(), + }) + ], + })], + ),) + .into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .invest(&investments); - setup.env.ledger().set_timestamp(setup.env.ledger().timestamp() + ONE_YEAR_IN_SECONDS); + setup + .env + .ledger() + .set_timestamp(setup.env.ledger().timestamp() + ONE_YEAR_IN_SECONDS); // TODO: The vault should call harvest method on the strategy contract - enviroment.strategy_contract.mock_all_auths().harvest(&enviroment.vault_contract.address); + enviroment + .strategy_contract + .mock_all_auths() + .harvest(&enviroment.vault_contract.address); let df_balance_before_withdraw = enviroment.vault_contract.balance(&user); - assert_eq!(df_balance_before_withdraw, deposit_amount - MINIMUM_LIQUIDITY); - - enviroment.vault_contract.mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "withdraw", - args: ( - df_balance_before_withdraw.clone(), - user.clone() - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .withdraw(&df_balance_before_withdraw, &user); + assert_eq!( + df_balance_before_withdraw, + deposit_amount - MINIMUM_LIQUIDITY + ); + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "withdraw", + args: (df_balance_before_withdraw.clone(), user.clone()).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .withdraw(&df_balance_before_withdraw, &user); let apr_bps = 1000u32; - let user_expected_reward = calculate_yield(deposit_amount.clone(), apr_bps, ONE_YEAR_IN_SECONDS); + let user_expected_reward = + calculate_yield(deposit_amount.clone(), apr_bps, ONE_YEAR_IN_SECONDS); let minimum_liquidity_reward = calculate_yield(MINIMUM_LIQUIDITY, apr_bps, ONE_YEAR_IN_SECONDS); assert_eq!(minimum_liquidity_reward, 100); - let expected_amount_user = deposit_amount + user_expected_reward - MINIMUM_LIQUIDITY - minimum_liquidity_reward; + let expected_amount_user = + deposit_amount + user_expected_reward - MINIMUM_LIQUIDITY - minimum_liquidity_reward; let user_balance_after_withdraw = enviroment.token.balance(user); assert_eq!(user_balance_after_withdraw, expected_amount_user); @@ -211,4 +257,4 @@ fn fixed_apr_invest_withdraw_success() { let df_balance = enviroment.vault_contract.balance(&user); assert_eq!(df_balance, 0); -} \ No newline at end of file +} diff --git a/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/deposit.rs b/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/deposit.rs index a8753f72..88ae343d 100644 --- a/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/deposit.rs +++ b/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/deposit.rs @@ -1,5 +1,12 @@ -use crate::{setup::create_vault_one_asset_hodl_strategy, test::IntegrationTest, vault::{VaultContractError, MINIMUM_LIQUIDITY}}; -use soroban_sdk::{testutils::{MockAuth, MockAuthInvoke}, vec as svec, IntoVal, Vec}; +use crate::{ + setup::create_vault_one_asset_hodl_strategy, + test::IntegrationTest, + vault::{VaultContractError, MINIMUM_LIQUIDITY}, +}; +use soroban_sdk::{ + testutils::{MockAuth, MockAuthInvoke}, + vec as svec, IntoVal, Vec, +}; #[test] fn test_deposit_success() { @@ -11,52 +18,64 @@ fn test_deposit_success() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); let deposit_amount = 10_000_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user.clone(), + user.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); let vault_balance = enviroment.token.balance(&enviroment.vault_contract.address); assert_eq!(vault_balance, deposit_amount); let user_balance_after_deposit = enviroment.token.balance(user); - assert_eq!(user_balance_after_deposit, user_starting_balance - deposit_amount); + assert_eq!( + user_balance_after_deposit, + user_starting_balance - deposit_amount + ); let df_balance = enviroment.vault_contract.balance(&user); assert_eq!(df_balance, deposit_amount - MINIMUM_LIQUIDITY); @@ -76,46 +95,55 @@ fn test_deposit_insufficient_balance() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); let deposit_amount = 10_000_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user.clone(), + user.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); } #[test] @@ -129,24 +157,30 @@ fn test_deposit_multiple_users() { let user1 = &users[0]; let user2 = &users[1]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user1, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user1, &user_starting_balance); - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user2, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user2, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user1, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user1, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user2, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user2, &user_starting_balance); let user1_balance = enviroment.token.balance(user1); let user2_balance = enviroment.token.balance(user2); @@ -154,69 +188,87 @@ fn test_deposit_multiple_users() { assert_eq!(user2_balance, user_starting_balance); let deposit_amount = 10_000_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user1.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user1.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user1.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user1.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user1.clone(), + user1.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user1, &false); - - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user2.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user2.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user1, + &false, + ); + + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user2.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user2.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user2.clone(), + user2.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user2, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user2, + &false, + ); let vault_balance = enviroment.token.balance(&enviroment.vault_contract.address); assert_eq!(vault_balance, deposit_amount * 2); let user1_balance_after_deposit = enviroment.token.balance(user1); let user2_balance_after_deposit = enviroment.token.balance(user2); - assert_eq!(user1_balance_after_deposit, user_starting_balance - deposit_amount); - assert_eq!(user2_balance_after_deposit, user_starting_balance - deposit_amount); + assert_eq!( + user1_balance_after_deposit, + user_starting_balance - deposit_amount + ); + assert_eq!( + user2_balance_after_deposit, + user_starting_balance - deposit_amount + ); let df_balance_user1 = enviroment.vault_contract.balance(&user1); let df_balance_user2 = enviroment.vault_contract.balance(&user2); @@ -237,15 +289,18 @@ fn test_deposit_zero_amount() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); @@ -254,7 +309,7 @@ fn test_deposit_zero_amount() { &svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, - &false + &false, ); assert_eq!(result, Err(Ok(VaultContractError::InsufficientAmount))); @@ -270,15 +325,18 @@ fn test_deposit_negative_amount() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); @@ -287,7 +345,7 @@ fn test_deposit_negative_amount() { &svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, - &false + &false, ); assert_eq!(result, Err(Ok(VaultContractError::NegativeNotAllowed))); @@ -303,15 +361,18 @@ fn test_deposit_insufficient_minimum_liquidity() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); @@ -320,8 +381,8 @@ fn test_deposit_insufficient_minimum_liquidity() { &svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, - &false + &false, ); assert_eq!(result, Err(Ok(VaultContractError::InsufficientAmount))); -} \ No newline at end of file +} diff --git a/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/fee_performance.rs b/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/fee_performance.rs index 8f802f8c..1e8277dc 100644 --- a/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/fee_performance.rs +++ b/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/fee_performance.rs @@ -1,5 +1,15 @@ -use crate::{setup::create_vault_one_asset_hodl_strategy, test::{EnvTestUtils, IntegrationTest, ONE_YEAR_IN_SECONDS}, vault::{defindex_vault_contract::{AssetInvestmentAllocation, StrategyAllocation}, VaultContractError, MINIMUM_LIQUIDITY}}; -use soroban_sdk::{testutils::{MockAuth, MockAuthInvoke}, vec as svec, IntoVal, Vec}; +use crate::{ + setup::create_vault_one_asset_hodl_strategy, + test::{EnvTestUtils, IntegrationTest, ONE_YEAR_IN_SECONDS}, + vault::{ + defindex_vault_contract::{AssetInvestmentAllocation, StrategyAllocation}, + VaultContractError, MINIMUM_LIQUIDITY, + }, +}; +use soroban_sdk::{ + testutils::{MockAuth, MockAuthInvoke}, + vec as svec, IntoVal, Vec, +}; extern crate std; #[test] @@ -12,46 +22,55 @@ fn fee_performance() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); let deposit_amount = 10_000_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user.clone(), + user.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); // Split deposit amount in two let half_deposit = deposit_amount / 2; @@ -70,123 +89,152 @@ fn fee_performance() { ]; // First investment - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &enviroment.manager.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "invest", - args: ( - Vec::from_array(&setup.env,[ - Some( - AssetInvestmentAllocation { - asset: enviroment.token.address.clone(), - strategy_allocations: - svec![&setup.env, - Some(StrategyAllocation { - amount: half_deposit, - strategy_address: enviroment.strategy_contract.address.clone(), - }) - ] - } - ) - ]), - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .invest(&investments); + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &enviroment.manager.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "invest", + args: (Vec::from_array( + &setup.env, + [Some(AssetInvestmentAllocation { + asset: enviroment.token.address.clone(), + strategy_allocations: svec![ + &setup.env, + Some(StrategyAllocation { + amount: half_deposit, + strategy_address: enviroment.strategy_contract.address.clone(), + }) + ], + })], + ),) + .into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .invest(&investments); let report_result_after_1_invest = enviroment.vault_contract.report(); - println!("report_result_after_1_invest: {:?}", report_result_after_1_invest); + println!( + "report_result_after_1_invest: {:?}", + report_result_after_1_invest + ); // Second investment - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &enviroment.manager.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "invest", - args: ( - Vec::from_array(&setup.env,[ - Some( - AssetInvestmentAllocation { - asset: enviroment.token.address.clone(), - strategy_allocations: - svec![&setup.env, - Some(StrategyAllocation { - amount: half_deposit, - strategy_address: enviroment.strategy_contract.address.clone(), - }) - ] - } - ) - ]), - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .invest(&investments); + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &enviroment.manager.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "invest", + args: (Vec::from_array( + &setup.env, + [Some(AssetInvestmentAllocation { + asset: enviroment.token.address.clone(), + strategy_allocations: svec![ + &setup.env, + Some(StrategyAllocation { + amount: half_deposit, + strategy_address: enviroment.strategy_contract.address.clone(), + }) + ], + })], + ),) + .into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .invest(&investments); let report_result_after_2_invests = enviroment.vault_contract.report(); - println!("report_result_after_2_invests: {:?}", report_result_after_2_invests); - + println!( + "report_result_after_2_invests: {:?}", + report_result_after_2_invests + ); setup.env.jump_time(ONE_YEAR_IN_SECONDS); - enviroment.strategy_contract.harvest(&enviroment.vault_contract.address); + enviroment + .strategy_contract + .harvest(&enviroment.vault_contract.address); enviroment.vault_contract.mock_auths(&[MockAuth { address: &enviroment.manager.clone(), invoke: &MockAuthInvoke { contract: &enviroment.vault_contract.address.clone(), fn_name: "report", - args: ( ).into_val(&setup.env), - sub_invokes: &[] - }, + args: ().into_val(&setup.env), + sub_invokes: &[], + }, }]); - - let _lock_fees_result = enviroment.vault_contract.mock_auths(&[MockAuth { - address: &enviroment.manager.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "lock_fees", - args: svec![&setup.env, 2000u32].into_val(&setup.env), - sub_invokes: &[] - }, - }]).lock_fees(&Some(2000u32)); - let total_funds_after_lock = enviroment.vault_contract.fetch_total_managed_funds().get(enviroment.token.address.clone()).unwrap().total_amount; + let _lock_fees_result = enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &enviroment.manager.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "lock_fees", + args: svec![&setup.env, 2000u32].into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .lock_fees(&Some(2000u32)); + let total_funds_after_lock = enviroment + .vault_contract + .fetch_total_managed_funds() + .get(enviroment.token.address.clone()) + .unwrap() + .total_amount; assert_eq!(total_funds_after_lock, deposit_amount); let release_fees_amount = 1_0_000_000i128; - let release_fees_result = enviroment.vault_contract.mock_auths(&[MockAuth { - address: &enviroment.manager.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "release_fees", - args: ( - &enviroment.strategy_contract.address.clone(), - release_fees_amount - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]).try_release_fees(&enviroment.strategy_contract.address.clone(), &release_fees_amount); - - assert_eq!(release_fees_result, Err(Ok(VaultContractError::InsufficientManagedFunds))); - - let _distribute_fees_result = enviroment.vault_contract.mock_auths(&[MockAuth { - address: &enviroment.manager.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "distribute_fees", - args: ().into_val(&setup.env), - sub_invokes: &[] - }, - }]).distribute_fees(); + let release_fees_result = enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &enviroment.manager.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "release_fees", + args: ( + &enviroment.strategy_contract.address.clone(), + release_fees_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .try_release_fees( + &enviroment.strategy_contract.address.clone(), + &release_fees_amount, + ); + + assert_eq!( + release_fees_result, + Err(Ok(VaultContractError::InsufficientManagedFunds)) + ); + + let _distribute_fees_result = enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &enviroment.manager.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "distribute_fees", + args: ().into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .distribute_fees(); let _report_result = enviroment.vault_contract.report(); - let total_funds_after_distribute = enviroment.vault_contract.fetch_total_managed_funds().get(enviroment.token.address.clone()).unwrap().total_amount; + let total_funds_after_distribute = enviroment + .vault_contract + .fetch_total_managed_funds() + .get(enviroment.token.address.clone()) + .unwrap() + .total_amount; assert_eq!(total_funds_after_distribute, deposit_amount); - } diff --git a/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/invest.rs b/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/invest.rs index fd7b5e0f..d42784cf 100644 --- a/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/invest.rs +++ b/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/invest.rs @@ -1,5 +1,15 @@ -use crate::{setup::create_vault_one_asset_hodl_strategy, test::{IntegrationTest, ONE_YEAR_IN_SECONDS}, vault::{defindex_vault_contract::{AssetInvestmentAllocation, StrategyAllocation}, VaultContractError, MINIMUM_LIQUIDITY}}; -use soroban_sdk::{testutils::{Ledger, MockAuth, MockAuthInvoke, Address as _}, vec as svec, Address, IntoVal, Vec}; +use crate::{ + setup::create_vault_one_asset_hodl_strategy, + test::{IntegrationTest, ONE_YEAR_IN_SECONDS}, + vault::{ + defindex_vault_contract::{AssetInvestmentAllocation, StrategyAllocation}, + VaultContractError, MINIMUM_LIQUIDITY, + }, +}; +use soroban_sdk::{ + testutils::{Address as _, Ledger, MockAuth, MockAuthInvoke}, + vec as svec, Address, IntoVal, Vec, +}; #[test] fn invest_success() { @@ -11,46 +21,55 @@ fn invest_success() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); let deposit_amount = 10_000_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user.clone(), + user.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); let df_balance = enviroment.vault_contract.balance(&user); assert_eq!(df_balance, deposit_amount - MINIMUM_LIQUIDITY); @@ -70,39 +89,43 @@ fn invest_success() { }), ]; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &enviroment.manager.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "invest", - args: ( - Vec::from_array(&setup.env,[ - Some( - AssetInvestmentAllocation { - asset: enviroment.token.address.clone(), - strategy_allocations: - svec![&setup.env, - Some(StrategyAllocation { - amount: deposit_amount, - strategy_address: enviroment.strategy_contract.address.clone(), - }) - ] - } - ) - ]), - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .invest(&investments); - - setup.env.ledger().set_timestamp(setup.env.ledger().timestamp() + ONE_YEAR_IN_SECONDS); + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &enviroment.manager.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "invest", + args: (Vec::from_array( + &setup.env, + [Some(AssetInvestmentAllocation { + asset: enviroment.token.address.clone(), + strategy_allocations: svec![ + &setup.env, + Some(StrategyAllocation { + amount: deposit_amount, + strategy_address: enviroment.strategy_contract.address.clone(), + }) + ], + })], + ),) + .into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .invest(&investments); + + setup + .env + .ledger() + .set_timestamp(setup.env.ledger().timestamp() + ONE_YEAR_IN_SECONDS); let token_balance_after_invest = enviroment.token.balance(&enviroment.vault_contract.address); assert_eq!(token_balance_after_invest, 0); - let strategy_balance = enviroment.strategy_contract.balance(&enviroment.vault_contract.address); + let strategy_balance = enviroment + .strategy_contract + .balance(&enviroment.vault_contract.address); assert_eq!(strategy_balance, deposit_amount); } @@ -116,46 +139,55 @@ fn invest_exceeding_investing_lenght() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); let deposit_amount = 10_000_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user.clone(), + user.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); let df_balance = enviroment.vault_contract.balance(&user); assert_eq!(df_balance, deposit_amount - MINIMUM_LIQUIDITY); @@ -187,44 +219,43 @@ fn invest_exceeding_investing_lenght() { }), ]; - let result = enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &enviroment.manager.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "invest", - args: ( - Vec::from_array(&setup.env,[ - Some( - AssetInvestmentAllocation { + let result = enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &enviroment.manager.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "invest", + args: (Vec::from_array( + &setup.env, + [ + Some(AssetInvestmentAllocation { asset: enviroment.token.address.clone(), - strategy_allocations: - svec![&setup.env, - Some(StrategyAllocation { - amount: deposit_amount, - strategy_address: enviroment.strategy_contract.address.clone(), - }) - ] - } - ), - Some( - AssetInvestmentAllocation { + strategy_allocations: svec![ + &setup.env, + Some(StrategyAllocation { + amount: deposit_amount, + strategy_address: enviroment.strategy_contract.address.clone(), + }) + ], + }), + Some(AssetInvestmentAllocation { asset: asset_address_2.clone(), - strategy_allocations: - svec![&setup.env, - Some(StrategyAllocation { - amount: deposit_amount, - strategy_address: strategy_address_2.clone(), - }) - ] - } - ) - ]), - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .try_invest(&investments); + strategy_allocations: svec![ + &setup.env, + Some(StrategyAllocation { + amount: deposit_amount, + strategy_address: strategy_address_2.clone(), + }) + ], + }), + ], + ),) + .into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .try_invest(&investments); assert_eq!(result, Err(Ok(VaultContractError::WrongInvestmentLength))); } @@ -240,46 +271,55 @@ fn invest_insufficient_balance() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); let deposit_amount = 10_000_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user.clone(), + user.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); } #[test] @@ -293,24 +333,30 @@ fn invest_multiple_users() { let user1 = &users[0]; let user2 = &users[1]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user1, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user1, &user_starting_balance); - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user2, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user2, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user1, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user1, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user2, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user2, &user_starting_balance); let user1_balance = enviroment.token.balance(user1); let user2_balance = enviroment.token.balance(user2); @@ -318,61 +364,73 @@ fn invest_multiple_users() { assert_eq!(user2_balance, user_starting_balance); let deposit_amount = 10_000_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user1.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user1.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user1.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user1.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user1.clone(), + user1.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user1, &false); - - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user2.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user2.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user1, + &false, + ); + + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user2.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user2.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user2.clone(), + user2.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user2, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user2, + &false, + ); let df_balance_user1 = enviroment.vault_contract.balance(&user1); let df_balance_user2 = enviroment.vault_contract.balance(&user2); @@ -387,45 +445,49 @@ fn invest_multiple_users() { strategy_allocations: svec![ &setup.env, Some(StrategyAllocation { - amount: deposit_amount*2, + amount: deposit_amount * 2, strategy_address: enviroment.strategy_contract.address.clone(), }), ], }), ]; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &enviroment.manager.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "invest", - args: ( - Vec::from_array(&setup.env,[ - Some( - AssetInvestmentAllocation { - asset: enviroment.token.address.clone(), - strategy_allocations: - svec![&setup.env, - Some(StrategyAllocation { - amount: deposit_amount*2, - strategy_address: enviroment.strategy_contract.address.clone(), - }) - ] - } - ) - ]), - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .invest(&investments); - - setup.env.ledger().set_timestamp(setup.env.ledger().timestamp() + ONE_YEAR_IN_SECONDS); + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &enviroment.manager.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "invest", + args: (Vec::from_array( + &setup.env, + [Some(AssetInvestmentAllocation { + asset: enviroment.token.address.clone(), + strategy_allocations: svec![ + &setup.env, + Some(StrategyAllocation { + amount: deposit_amount * 2, + strategy_address: enviroment.strategy_contract.address.clone(), + }) + ], + })], + ),) + .into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .invest(&investments); + + setup + .env + .ledger() + .set_timestamp(setup.env.ledger().timestamp() + ONE_YEAR_IN_SECONDS); let token_balance_after_invest = enviroment.token.balance(&enviroment.vault_contract.address); assert_eq!(token_balance_after_invest, 0); - let strategy_balance = enviroment.strategy_contract.balance(&enviroment.vault_contract.address); + let strategy_balance = enviroment + .strategy_contract + .balance(&enviroment.vault_contract.address); assert_eq!(strategy_balance, deposit_amount * 2); -} \ No newline at end of file +} diff --git a/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/mod.rs b/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/mod.rs index 03c5cb2d..787e1d32 100644 --- a/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/mod.rs +++ b/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/mod.rs @@ -1,5 +1,5 @@ mod deposit; -mod withdraw; mod invest; +mod withdraw; -mod fee_performance; \ No newline at end of file +mod fee_performance; diff --git a/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/withdraw.rs b/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/withdraw.rs index 667e1451..1a8df544 100644 --- a/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/withdraw.rs +++ b/apps/contracts/integration-test/src/test/vault_one_hodl_strategy/withdraw.rs @@ -1,5 +1,15 @@ -use crate::{setup::{create_vault_one_asset_hodl_strategy, VAULT_FEE}, test::{IntegrationTest, DEFINDEX_FEE, ONE_YEAR_IN_SECONDS}, vault::{defindex_vault_contract::{AssetInvestmentAllocation, StrategyAllocation}, VaultContractError, MINIMUM_LIQUIDITY}}; -use soroban_sdk::{testutils::{Ledger, MockAuth, MockAuthInvoke}, vec as svec, IntoVal, Vec}; +use crate::{ + setup::{create_vault_one_asset_hodl_strategy, VAULT_FEE}, + test::{IntegrationTest, DEFINDEX_FEE, ONE_YEAR_IN_SECONDS}, + vault::{ + defindex_vault_contract::{AssetInvestmentAllocation, StrategyAllocation}, + VaultContractError, MINIMUM_LIQUIDITY, + }, +}; +use soroban_sdk::{ + testutils::{Ledger, MockAuth, MockAuthInvoke}, + vec as svec, IntoVal, Vec, +}; #[test] fn test_withdraw_no_invest_success() { @@ -11,64 +21,71 @@ fn test_withdraw_no_invest_success() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); let deposit_amount = 10_000_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user.clone(), + user.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); let df_balance = enviroment.vault_contract.balance(&user); assert_eq!(df_balance, deposit_amount - MINIMUM_LIQUIDITY); - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "withdraw", - args: ( - df_balance.clone(), - user.clone() - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .withdraw(&df_balance, &user); + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "withdraw", + args: (df_balance.clone(), user.clone()).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .withdraw(&df_balance, &user); let df_balance = enviroment.vault_contract.balance(&user); assert_eq!(df_balance, 0); @@ -77,7 +94,10 @@ fn test_withdraw_no_invest_success() { assert_eq!(vault_balance_after_withdraw, MINIMUM_LIQUIDITY); let user_balance_after_withdraw = enviroment.token.balance(user); - assert_eq!(user_balance_after_withdraw, user_starting_balance - MINIMUM_LIQUIDITY); + assert_eq!( + user_balance_after_withdraw, + user_starting_balance - MINIMUM_LIQUIDITY + ); let df_balance = enviroment.vault_contract.balance(&user); assert_eq!(df_balance, 0); @@ -96,74 +116,87 @@ fn test_withdraw_partial_success() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); let deposit_amount = 10_000_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user.clone(), + user.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); let df_balance = enviroment.vault_contract.balance(&user); assert_eq!(df_balance, deposit_amount - MINIMUM_LIQUIDITY); let withdraw_amount = df_balance / 2; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "withdraw", - args: ( - withdraw_amount.clone(), - user.clone() - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .withdraw(&withdraw_amount, &user); + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "withdraw", + args: (withdraw_amount.clone(), user.clone()).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .withdraw(&withdraw_amount, &user); let df_balance = enviroment.vault_contract.balance(&user); assert_eq!(df_balance, withdraw_amount); let vault_balance_after_withdraw = enviroment.token.balance(&enviroment.vault_contract.address); - assert_eq!(vault_balance_after_withdraw, deposit_amount - withdraw_amount); + assert_eq!( + vault_balance_after_withdraw, + deposit_amount - withdraw_amount + ); let user_balance_after_withdraw = enviroment.token.balance(user); - assert_eq!(user_balance_after_withdraw, user_starting_balance - (deposit_amount - withdraw_amount)); + assert_eq!( + user_balance_after_withdraw, + user_starting_balance - (deposit_amount - withdraw_amount) + ); } #[test] @@ -176,65 +209,72 @@ fn test_withdraw_insufficient_balance() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); let deposit_amount = 10_000_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user.clone(), + user.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); let df_balance = enviroment.vault_contract.balance(&user); assert_eq!(df_balance, deposit_amount - MINIMUM_LIQUIDITY); let withdraw_amount = df_balance + 1; // Attempt to withdraw more than the balance - let result = enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "withdraw", - args: ( - withdraw_amount.clone(), - user.clone() - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .try_withdraw(&withdraw_amount, &user); + let result = enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "withdraw", + args: (withdraw_amount.clone(), user.clone()).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .try_withdraw(&withdraw_amount, &user); assert_eq!(result, Err(Ok(VaultContractError::InsufficientBalance))); let df_balance = enviroment.vault_contract.balance(&user); @@ -244,7 +284,10 @@ fn test_withdraw_insufficient_balance() { assert_eq!(vault_balance_after_withdraw, deposit_amount); let user_balance_after_withdraw = enviroment.token.balance(user); - assert_eq!(user_balance_after_withdraw, user_starting_balance - deposit_amount); + assert_eq!( + user_balance_after_withdraw, + user_starting_balance - deposit_amount + ); } #[test] @@ -257,46 +300,55 @@ fn test_withdraw_after_invest() { let users = IntegrationTest::generate_random_users(&setup.env, 1); let user = &users[0]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user, &user_starting_balance); let user_balance = enviroment.token.balance(user); assert_eq!(user_balance, user_starting_balance); let deposit_amount = 10_000_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user.clone(), + user.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user, + &false, + ); let user_balance_after_deposit = enviroment.token.balance(user); assert_eq!(user_balance_after_deposit, 0); @@ -319,58 +371,60 @@ fn test_withdraw_after_invest() { }), ]; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &enviroment.manager.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "invest", - args: ( - Vec::from_array(&setup.env,[ - Some( - AssetInvestmentAllocation { - asset: enviroment.token.address.clone(), - strategy_allocations: - svec![&setup.env, - Some(StrategyAllocation { - amount: deposit_amount, - strategy_address: enviroment.strategy_contract.address.clone(), - }) - ] - } - ) - ]), - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .invest(&investments); - - setup.env.ledger().set_timestamp(setup.env.ledger().timestamp() + ONE_YEAR_IN_SECONDS); + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &enviroment.manager.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "invest", + args: (Vec::from_array( + &setup.env, + [Some(AssetInvestmentAllocation { + asset: enviroment.token.address.clone(), + strategy_allocations: svec![ + &setup.env, + Some(StrategyAllocation { + amount: deposit_amount, + strategy_address: enviroment.strategy_contract.address.clone(), + }) + ], + })], + ),) + .into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .invest(&investments); + + setup + .env + .ledger() + .set_timestamp(setup.env.ledger().timestamp() + ONE_YEAR_IN_SECONDS); let token_balance_after_invest = enviroment.token.balance(&enviroment.vault_contract.address); assert_eq!(token_balance_after_invest, 0); - let strategy_balance = enviroment.strategy_contract.balance(&enviroment.vault_contract.address); + let strategy_balance = enviroment + .strategy_contract + .balance(&enviroment.vault_contract.address); assert_eq!(strategy_balance, deposit_amount); - - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "withdraw", - args: ( - df_balance.clone(), - user.clone() - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .withdraw(&df_balance, &user); + + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "withdraw", + args: (df_balance.clone(), user.clone()).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .withdraw(&df_balance, &user); let df_balance = enviroment.vault_contract.balance(&user); - assert_eq!(df_balance, 0); + assert_eq!(df_balance, 0); let token_balance_after_withdraw = enviroment.token.balance(&enviroment.vault_contract.address); assert_eq!(token_balance_after_withdraw, 0); @@ -380,8 +434,10 @@ fn test_withdraw_after_invest() { let user_balance_after_withdraw = enviroment.token.balance(user); assert_eq!(user_balance_after_withdraw, expected_amount); - let strategy_balance = enviroment.strategy_contract.balance(&enviroment.vault_contract.address); - assert_eq!(strategy_balance, MINIMUM_LIQUIDITY); + let strategy_balance = enviroment + .strategy_contract + .balance(&enviroment.vault_contract.address); + assert_eq!(strategy_balance, MINIMUM_LIQUIDITY); let vault_balance_after_withdraw = enviroment.token.balance(&enviroment.vault_contract.address); assert_eq!(vault_balance_after_withdraw, 0); @@ -398,24 +454,30 @@ fn test_withdraw_multiple_users() { let user1 = &users[0]; let user2 = &users[1]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user1, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user1, &user_starting_balance); - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user2, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user2, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user1, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user1, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user2, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user2, &user_starting_balance); let user1_balance = enviroment.token.balance(user1); let user2_balance = enviroment.token.balance(user2); @@ -423,96 +485,104 @@ fn test_withdraw_multiple_users() { assert_eq!(user2_balance, user_starting_balance); let deposit_amount = 10_000_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user1.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user1.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user1.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user1.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user1.clone(), + user1.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user1, &false); - - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user2.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user2.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user1, + &false, + ); + + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user2.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user2.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user2.clone(), + user2.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user2, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user2, + &false, + ); let df_balance_user1 = enviroment.vault_contract.balance(&user1); let df_balance_user2 = enviroment.vault_contract.balance(&user2); assert_eq!(df_balance_user1, deposit_amount - MINIMUM_LIQUIDITY); assert_eq!(df_balance_user2, deposit_amount); - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user1.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "withdraw", - args: ( - df_balance_user1.clone(), - user1.clone() - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .withdraw(&df_balance_user1, &user1); - - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user2.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "withdraw", - args: ( - df_balance_user2.clone(), - user2.clone() - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .withdraw(&df_balance_user2, &user2); + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user1.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "withdraw", + args: (df_balance_user1.clone(), user1.clone()).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .withdraw(&df_balance_user1, &user1); + + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user2.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "withdraw", + args: (df_balance_user2.clone(), user2.clone()).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .withdraw(&df_balance_user2, &user2); let df_balance_user1 = enviroment.vault_contract.balance(&user1); let df_balance_user2 = enviroment.vault_contract.balance(&user2); @@ -524,7 +594,10 @@ fn test_withdraw_multiple_users() { let user1_balance_after_withdraw = enviroment.token.balance(user1); let user2_balance_after_withdraw = enviroment.token.balance(user2); - assert_eq!(user1_balance_after_withdraw, user_starting_balance - MINIMUM_LIQUIDITY); + assert_eq!( + user1_balance_after_withdraw, + user_starting_balance - MINIMUM_LIQUIDITY + ); assert_eq!(user2_balance_after_withdraw, user_starting_balance); let total_supply = enviroment.vault_contract.total_supply(); @@ -542,24 +615,30 @@ fn test_withdraw_after_invest_multiple_users() { let user1 = &users[0]; let user2 = &users[1]; - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user1, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user1, &user_starting_balance); - enviroment.token_admin_client.mock_auths(&[MockAuth { - address: &enviroment.token_admin.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.token.address.clone(), - fn_name: "mint", - args: (user2, user_starting_balance,).into_val(&setup.env), - sub_invokes: &[], - }, - }]).mint(user2, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user1, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user1, &user_starting_balance); + enviroment + .token_admin_client + .mock_auths(&[MockAuth { + address: &enviroment.token_admin.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.token.address.clone(), + fn_name: "mint", + args: (user2, user_starting_balance).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .mint(user2, &user_starting_balance); let user1_balance = enviroment.token.balance(user1); let user2_balance = enviroment.token.balance(user2); @@ -567,61 +646,73 @@ fn test_withdraw_after_invest_multiple_users() { assert_eq!(user2_balance, user_starting_balance); let deposit_amount = 10_000_0_000_000i128; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user1.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user1.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user1.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user1.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user1.clone(), + user1.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user1, &false); - - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user2.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&setup.env,[deposit_amount]), - Vec::from_array(&setup.env,[deposit_amount]), - user2.clone(), - false - ).into_val(&setup.env), - sub_invokes: &[ - MockAuthInvoke { + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user1, + &false, + ); + + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user2.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&setup.env, [deposit_amount]), + Vec::from_array(&setup.env, [deposit_amount]), + user2.clone(), + false, + ) + .into_val(&setup.env), + sub_invokes: &[MockAuthInvoke { contract: &enviroment.token.address.clone(), fn_name: "transfer", args: ( - user2.clone(), + user2.clone(), &enviroment.vault_contract.address.clone(), - deposit_amount - ).into_val(&setup.env), - sub_invokes: &[] - } - ] - }, - }]) - .deposit(&svec![&setup.env, deposit_amount], &svec![&setup.env, deposit_amount], &user2, &false); + deposit_amount, + ) + .into_val(&setup.env), + sub_invokes: &[], + }], + }, + }]) + .deposit( + &svec![&setup.env, deposit_amount], + &svec![&setup.env, deposit_amount], + &user2, + &false, + ); let df_balance_user1 = enviroment.vault_contract.balance(&user1); let df_balance_user2 = enviroment.vault_contract.balance(&user2); @@ -643,70 +734,70 @@ fn test_withdraw_after_invest_multiple_users() { }), ]; - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &enviroment.manager.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "invest", - args: ( - Vec::from_array(&setup.env,[ - Some( - AssetInvestmentAllocation { - asset: enviroment.token.address.clone(), - strategy_allocations: - svec![&setup.env, - Some(StrategyAllocation { - amount: deposit_amount * 2, - strategy_address: enviroment.strategy_contract.address.clone(), - }) - ] - } - ) - ]), - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .invest(&investments); - - setup.env.ledger().set_timestamp(setup.env.ledger().timestamp() + ONE_YEAR_IN_SECONDS); + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &enviroment.manager.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "invest", + args: (Vec::from_array( + &setup.env, + [Some(AssetInvestmentAllocation { + asset: enviroment.token.address.clone(), + strategy_allocations: svec![ + &setup.env, + Some(StrategyAllocation { + amount: deposit_amount * 2, + strategy_address: enviroment.strategy_contract.address.clone(), + }) + ], + })], + ),) + .into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .invest(&investments); + + setup + .env + .ledger() + .set_timestamp(setup.env.ledger().timestamp() + ONE_YEAR_IN_SECONDS); let token_balance_after_invest = enviroment.token.balance(&enviroment.vault_contract.address); assert_eq!(token_balance_after_invest, 0); - let strategy_balance = enviroment.strategy_contract.balance(&enviroment.vault_contract.address); + let strategy_balance = enviroment + .strategy_contract + .balance(&enviroment.vault_contract.address); assert_eq!(strategy_balance, deposit_amount * 2); - - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user1.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "withdraw", - args: ( - df_balance_user1.clone(), - user1.clone() - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .withdraw(&df_balance_user1, &user1); - - enviroment.vault_contract - .mock_auths(&[MockAuth { - address: &user2.clone(), - invoke: &MockAuthInvoke { - contract: &enviroment.vault_contract.address.clone(), - fn_name: "withdraw", - args: ( - df_balance_user2.clone(), - user2.clone() - ).into_val(&setup.env), - sub_invokes: &[] - }, - }]) - .withdraw(&df_balance_user2, &user2); + + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user1.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "withdraw", + args: (df_balance_user1.clone(), user1.clone()).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .withdraw(&df_balance_user1, &user1); + + enviroment + .vault_contract + .mock_auths(&[MockAuth { + address: &user2.clone(), + invoke: &MockAuthInvoke { + contract: &enviroment.vault_contract.address.clone(), + fn_name: "withdraw", + args: (df_balance_user2.clone(), user2.clone()).into_val(&setup.env), + sub_invokes: &[], + }, + }]) + .withdraw(&df_balance_user2, &user2); let df_balance_user1 = enviroment.vault_contract.balance(&user1); let df_balance_user2 = enviroment.vault_contract.balance(&user2); @@ -725,9 +816,11 @@ fn test_withdraw_after_invest_multiple_users() { assert_eq!(user1_balance_after_withdraw, expected_amount_user1); assert_eq!(user2_balance_after_withdraw, expected_amount_user2); - let strategy_balance = enviroment.strategy_contract.balance(&enviroment.vault_contract.address); - assert_eq!(strategy_balance, MINIMUM_LIQUIDITY); + let strategy_balance = enviroment + .strategy_contract + .balance(&enviroment.vault_contract.address); + assert_eq!(strategy_balance, MINIMUM_LIQUIDITY); let vault_balance_after_withdraw = enviroment.token.balance(&enviroment.vault_contract.address); assert_eq!(vault_balance_after_withdraw, 0); -} \ No newline at end of file +} diff --git a/apps/contracts/integration-test/src/token.rs b/apps/contracts/integration-test/src/token.rs index ef729253..d778bd1e 100644 --- a/apps/contracts/integration-test/src/token.rs +++ b/apps/contracts/integration-test/src/token.rs @@ -1,20 +1,27 @@ -use soroban_sdk::{token::{TokenClient as SorobanTokenClient, StellarAssetClient as SorobanTokenAdminClient}, Address, Env}; +use soroban_sdk::{ + token::{StellarAssetClient as SorobanTokenAdminClient, TokenClient as SorobanTokenClient}, + Address, Env, +}; fn create_token_contract<'a>(e: &Env, admin: &Address) -> SorobanTokenClient<'a> { - SorobanTokenClient::new(e, &e.register_stellar_asset_contract_v2(admin.clone()).address()) + SorobanTokenClient::new( + e, + &e.register_stellar_asset_contract_v2(admin.clone()) + .address(), + ) } -fn get_token_admin_client<'a>( - e: &Env, - address: &Address, -) -> SorobanTokenAdminClient<'a> { +fn get_token_admin_client<'a>(e: &Env, address: &Address) -> SorobanTokenAdminClient<'a> { SorobanTokenAdminClient::new(e, address) } -pub fn create_token<'a>(e: &Env, admin: &Address) -> (SorobanTokenClient<'a>, SorobanTokenAdminClient<'a>) { +pub fn create_token<'a>( + e: &Env, + admin: &Address, +) -> (SorobanTokenClient<'a>, SorobanTokenAdminClient<'a>) { let token = create_token_contract(e, admin); - + let token_admin_client = get_token_admin_client(e, &token.address); (token, token_admin_client) -} \ No newline at end of file +} diff --git a/apps/contracts/integration-test/src/vault.rs b/apps/contracts/integration-test/src/vault.rs index 13987ab1..838fab33 100644 --- a/apps/contracts/integration-test/src/vault.rs +++ b/apps/contracts/integration-test/src/vault.rs @@ -1,11 +1,15 @@ // DeFindex Vault Contract pub mod defindex_vault_contract { - soroban_sdk::contractimport!(file = "../target/wasm32-unknown-unknown/release/defindex_vault.optimized.wasm"); + soroban_sdk::contractimport!( + file = "../target/wasm32-unknown-unknown/release/defindex_vault.optimized.wasm" + ); pub type VaultContractClient<'a> = Client<'a>; } -pub use defindex_vault_contract::{AssetStrategySet as VaultAssetStrategySet, Strategy as VaultStrategy, ContractError as VaultContractError}; +pub use defindex_vault_contract::{ + AssetStrategySet as VaultAssetStrategySet, ContractError as VaultContractError, + Strategy as VaultStrategy, +}; pub static MINIMUM_LIQUIDITY: i128 = 1000; - diff --git a/apps/contracts/soroswap/soroswap_aggregator.wasm b/apps/contracts/soroswap/soroswap_aggregator.wasm new file mode 100644 index 00000000..86a3ae0d Binary files /dev/null and b/apps/contracts/soroswap/soroswap_aggregator.wasm differ diff --git a/apps/contracts/soroswap/soroswap_factory.wasm b/apps/contracts/soroswap/soroswap_factory.wasm new file mode 100644 index 00000000..00eded64 Binary files /dev/null and b/apps/contracts/soroswap/soroswap_factory.wasm differ diff --git a/apps/contracts/soroswap/soroswap_pair.wasm b/apps/contracts/soroswap/soroswap_pair.wasm new file mode 100644 index 00000000..132b4181 Binary files /dev/null and b/apps/contracts/soroswap/soroswap_pair.wasm differ diff --git a/apps/contracts/soroswap/soroswap_router.wasm b/apps/contracts/soroswap/soroswap_router.wasm new file mode 100644 index 00000000..bd621c59 Binary files /dev/null and b/apps/contracts/soroswap/soroswap_router.wasm differ diff --git a/apps/contracts/src/count-lines.ts b/apps/contracts/src/count-lines.ts index 565e1e9e..4a213585 100644 --- a/apps/contracts/src/count-lines.ts +++ b/apps/contracts/src/count-lines.ts @@ -7,6 +7,7 @@ function countLinesInFile(filePath: string): number { const lines = content.split('\n'); let lineCount = 0; let inFunctionParams = false; + let inMethodChain = false; let openParens = 0; for (let i = 0; i < lines.length; i++) { @@ -20,6 +21,12 @@ function countLinesInFile(filePath: string): number { continue; } + // Check if this line starts with a dot (method chaining) + if (trimmedLine.startsWith('.')) { + inMethodChain = true; + continue; + } + // Count open and close parentheses if (trimmedLine.includes('(')) { openParens += trimmedLine.split('(').length - 1; @@ -29,14 +36,24 @@ function countLinesInFile(filePath: string): number { openParens -= trimmedLine.split(')').length - 1; if (openParens <= 0) { inFunctionParams = false; - // Only count this as one line if we were in function parameters - lineCount++; + if (!inMethodChain) { + lineCount++; + } continue; } } - // If we're not in function parameters, count normally - if (!inFunctionParams) { + // If line ends with semicolon, it's the end of a statement + if (trimmedLine.endsWith(';')) { + inMethodChain = false; + if (!inFunctionParams) { + lineCount++; + } + continue; + } + + // If we're not in function parameters or method chain, count normally + if (!inFunctionParams && !inMethodChain) { lineCount++; } } diff --git a/apps/contracts/src/test.ts b/apps/contracts/src/test.ts index 3ecec545..ec850b5e 100644 --- a/apps/contracts/src/test.ts +++ b/apps/contracts/src/test.ts @@ -80,16 +80,22 @@ export async function test_factory(addressBook: AddressBook) { }), ]); }); + + const nameSymbol = xdr.ScVal.scvVec([ + nativeToScVal("Test Vault", { type: "string" }), // name + nativeToScVal("DFT-Test-Vault", { type: "string" }), + ]); + const createDeFindexParams: xdr.ScVal[] = [ - new Address(emergencyManager.publicKey()).toScVal(), - new Address(feeReceiver.publicKey()).toScVal(), + new Address(emergencyManager.publicKey()).toScVal(), // emergency_manager: Address, + new Address(feeReceiver.publicKey()).toScVal(), // fee_receiver: Address, nativeToScVal(100, { type: "u32" }), // Setting vault_fee as 100 bps for demonstration - nativeToScVal("Test Vault", { type: "string" }), - nativeToScVal("DFT-Test-Vault", { type: "string" }), - new Address(manager.publicKey()).toScVal(), - xdr.ScVal.scvVec(assetAllocations), - nativeToScVal(randomBytes(32)), + new Address(manager.publicKey()).toScVal(), // manager: Address, + xdr.ScVal.scvVec(assetAllocations), // assets: Vec, + nativeToScVal(randomBytes(32)), // salt: BytesN<32>, + new Address(emergencyManager.publicKey()).toScVal(), // soroswap_router: Address, + nameSymbol, // name_symbol: Vec, ]; const result = await invokeContract( diff --git a/apps/contracts/src/tests/blend/test_vault.ts b/apps/contracts/src/tests/blend/test_vault.ts index e1713e58..c2e52811 100644 --- a/apps/contracts/src/tests/blend/test_vault.ts +++ b/apps/contracts/src/tests/blend/test_vault.ts @@ -97,17 +97,24 @@ export async function testBlendVault(user?: Keypair) { ]); }); + const nameSymbol = xdr.ScVal.scvVec([ + nativeToScVal("BLND Vault", { type: "string" }), // name + nativeToScVal("BLNVLT", { type: "string" }), + ]); + const createDeFindexParams: xdr.ScVal[] = [ new Address(emergencyManager.publicKey()).toScVal(), new Address(feeReceiver.publicKey()).toScVal(), nativeToScVal(100, { type: "u32" }), - nativeToScVal("BLND Vault", { type: "string" }), - nativeToScVal("BLNVLT", { type: "string" }), new Address(manager.publicKey()).toScVal(), xdr.ScVal.scvVec(assetAllocations), nativeToScVal(randomBytes(32)), + new Address(emergencyManager.publicKey()).toScVal(), // soroswap_router: Address, + nameSymbol, // name_symbol: Vec, ]; + + const initialAmount = 100_0_000_000; let blendVaultAddress: string = ""; diff --git a/apps/contracts/src/tests/mainTest.ts b/apps/contracts/src/tests/mainTest.ts index 40f264ee..9bd5242e 100644 --- a/apps/contracts/src/tests/mainTest.ts +++ b/apps/contracts/src/tests/mainTest.ts @@ -1,8 +1,7 @@ import { Address, Asset, Keypair, Networks } from "@stellar/stellar-sdk"; import { AddressBook } from "../utils/address_book.js"; -import { airdropAccount } from "../utils/contract.js"; +import { airdropAccount, invokeCustomContract } from "../utils/contract.js"; import { - ActionType, admin, AssetInvestmentAllocation, CreateVaultParams, @@ -15,9 +14,8 @@ import { Instruction, investVault, manager, - mintToken, - rebalanceVault, withdrawFromVault, + mapInstructionsToParams, } from "./vault.js"; import { checkUserBalance } from "./strategy.js"; import { exit } from "process"; @@ -205,26 +203,30 @@ async function testVaultOneStrategy() { // rebalance vault console.log(purple, "---------------------------------------"); - console.log(purple, "Rebalancing vault"); + console.log(purple, "Rebalancing vault"); console.log(purple, "---------------------------------------"); const rebalanceArgs: Instruction[] = [ { - action: ActionType.Invest, + type: "Invest", strategy: addressBook.getContractId("hodl_strategy"), amount: BigInt(7_0_000), - swap_details_exact_in: undefined, - swap_details_exact_out: undefined, }, { - action: ActionType.Withdraw, + type: "Withdraw", strategy: addressBook.getContractId("hodl_strategy"), amount: BigInt(6_0_00), - swap_details_exact_in: undefined, - swap_details_exact_out: undefined, }, ]; - await rebalanceVault(vaultAddress, rebalanceArgs, manager); + + const mappedParams = mapInstructionsToParams(rebalanceArgs); + + + await invokeCustomContract( + vaultAddress, + "rebalance", + [mappedParams], + manager); console.log(yellow, "---------------------------------------"); console.log(yellow, "Fetching balances"); @@ -417,37 +419,40 @@ async function testVaultTwoStrategies() { console.log(purple, "---------------------------------------"); console.log(purple, "Rebalancing vault"); console.log(purple, "---------------------------------------"); + const rebalanceArgs: Instruction[] = [ - { - action: ActionType.Invest, - strategy: addressBook.getContractId("hodl_strategy"), - amount: BigInt(7_0_000), - swap_details_exact_in: undefined, - swap_details_exact_out: undefined, - }, - { - action: ActionType.Withdraw, - strategy: addressBook.getContractId("hodl_strategy"), - amount: BigInt(6_0_00), - swap_details_exact_in: undefined, - swap_details_exact_out: undefined, - }, - { - action: ActionType.Invest, - strategy: addressBook.getContractId("fixed_apr_strategy"), - amount: BigInt(8_0_000), - swap_details_exact_in: undefined, - swap_details_exact_out: undefined, - }, - { - action: ActionType.Withdraw, - strategy: addressBook.getContractId("fixed_apr_strategy"), - amount: BigInt(3_0_00), - swap_details_exact_in: undefined, - swap_details_exact_out: undefined, - }, + { + type: "Invest", + strategy: addressBook.getContractId("hodl_strategy"), + amount: BigInt(7_000_000), + }, + { + type: "Withdraw", + strategy: addressBook.getContractId("hodl_strategy"), + amount: BigInt(6_000_00), + }, + { + type: "Invest", + strategy: addressBook.getContractId("fixed_apr_strategy"), + amount: BigInt(8_000_000), + }, + { + type: "Withdraw", + strategy: addressBook.getContractId("fixed_apr_strategy"), + amount: BigInt(3_000_00), + }, ]; - await rebalanceVault(vaultAddress, rebalanceArgs, manager); + + const mappedParams = mapInstructionsToParams(rebalanceArgs); + + await invokeCustomContract( + vaultAddress, + "rebalance", + [mappedParams], + manager + ); + + console.log(yellow, "---------------------------------------"); console.log(yellow, "Fetching balances"); console.log(yellow, "---------------------------------------"); diff --git a/apps/contracts/src/tests/vault.ts b/apps/contracts/src/tests/vault.ts index e153a3d6..440de167 100644 --- a/apps/contracts/src/tests/vault.ts +++ b/apps/contracts/src/tests/vault.ts @@ -57,7 +57,7 @@ export async function mintToken( user: Keypair, amount: number) { * @param {xdr.ScVal[]} assetAllocations - The asset allocations for the vault. * @returns {xdr.ScVal[]} An array of ScVal objects representing the parameters. */ -function getCreateDeFindexParams( +function getCreateDeFindexParams( emergencyManager: Keypair, feeReceiver: Keypair, manager: Keypair, @@ -65,15 +65,20 @@ function getCreateDeFindexParams( vaultSymbol: string, assetAllocations: xdr.ScVal[] ): xdr.ScVal[] { + const nameSymbol = xdr.ScVal.scvVec([ + nativeToScVal(vaultName ?? 'TestVault', { type: "string" }), // name + nativeToScVal(vaultSymbol ?? 'TSTV', { type: "string" }), + ]); + return [ new Address(emergencyManager.publicKey()).toScVal(), new Address(feeReceiver.publicKey()).toScVal(), - nativeToScVal(100, { type: "u32" }), - nativeToScVal(vaultName ?? 'TestVault', { type: "string" }), - nativeToScVal(vaultSymbol ?? 'TSTV', { type: "string" }), + nativeToScVal(100, { type: "u32" }),// Setting vault_fee as 100 bps for demonstration new Address(manager.publicKey()).toScVal(), xdr.ScVal.scvVec(assetAllocations), - nativeToScVal(randomBytes(32)), + nativeToScVal(randomBytes(32)), //salt + new Address(emergencyManager.publicKey()).toScVal(), //soroswap_rouer + nameSymbol ]; } @@ -415,198 +420,225 @@ export async function investVault( throw error; } } - -export enum ActionType { - Withdraw = 0, - Invest = 1, - SwapExactIn = 2, - SwapExactOut = 3, - Zapper = 4, - } - -export interface DexDistribution { - parts: u32; - path: Array; - protocol_id: string; - } - -export interface SwapDetailsExactIn { - amount_in: i128; - amount_out_min: i128; - deadline: u64; - distribution: Array; - token_in: string; - token_out: string; -} - - -export interface SwapDetailsExactOut { - amount_in_max: i128; - amount_out: i128; - deadline: u64; - distribution: Array; - token_in: string; - token_out: string; -} export type Option = T | undefined; -export interface Instruction { - action: ActionType; - amount: Option; - strategy: Option; - swap_details_exact_in: Option; - swap_details_exact_out: Option; -} -export async function rebalanceVault(deployedVault: string, instructions: Instruction[], manager: Keypair) { - const mappedInstructions = xdr.ScVal.scvVec( - instructions.map((instruction) => - xdr.ScVal.scvMap([ - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("action"), - val: nativeToScVal(instruction.action, { type: "u32" }), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("amount"), - val: instruction.amount !== undefined - ? nativeToScVal(instruction.amount, { type: "i128" }) - : xdr.ScVal.scvVoid(), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("strategy"), - val: instruction.strategy - ? new Address(instruction.strategy).toScVal() - : xdr.ScVal.scvVoid(), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("swap_details_exact_in"), - val: instruction.swap_details_exact_in - ? xdr.ScVal.scvMap( - mapSwapDetailsExactIn(instruction.swap_details_exact_in) - ) - : xdr.ScVal.scvVec([xdr.ScVal.scvSymbol("None")]), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("swap_details_exact_out"), - val: instruction.swap_details_exact_out - ? xdr.ScVal.scvMap( - mapSwapDetailsExactOut(instruction.swap_details_exact_out) - ) - : xdr.ScVal.scvVec([xdr.ScVal.scvSymbol("None")]), - }), - ]) - ) +// export type Address = string; // Simplified representation of Address as a string +// export type i128 = bigint; // TypeScript equivalent for large integers +// export type u64 = number; // Simplified as a number for UNIX timestamps + +export type Instruction = + | { type: "Withdraw"; strategy: string; amount: i128 } + | { type: "Invest"; strategy: string; amount: i128 } + | { + type: "SwapExactIn"; + token_in: string; + token_out: string; + amount_in: i128; + amount_out_min: i128; + deadline: u64; + } + | { + type: "SwapExactOut"; + token_in: string; + token_out: string; + amount_out: i128; + amount_in_max: i128; + deadline: u64; + }; + +export function mapInstructionsToParams(instructions: Instruction[]): xdr.ScVal { + return xdr.ScVal.scvVec( + instructions.map((instruction) => { + switch (instruction.type) { + case "Invest": + case "Withdraw": + // Handle Invest and Withdraw actions + return xdr.ScVal.scvVec([ + xdr.ScVal.scvSymbol(instruction.type), // "Invest" or "Withdraw" + new Address(instruction.strategy).toScVal(), + nativeToScVal(instruction.amount, { type: "i128" }), // amount + ]); + + case "SwapExactIn": + // Handle SwapExactIn action + return xdr.ScVal.scvVec([ + xdr.ScVal.scvSymbol("SwapExactIn"), + new Address(instruction.token_in).toScVal(), + new Address(instruction.token_out).toScVal(), + nativeToScVal(instruction.amount_in, { type: "i128" }), + nativeToScVal(instruction.amount_out_min, { type: "i128" }), + nativeToScVal(instruction.deadline, { type: "u64" }), + ]); + + case "SwapExactOut": + // Handle SwapExactOut action + return xdr.ScVal.scvVec([ + xdr.ScVal.scvSymbol("SwapExactOut"), + new Address(instruction.token_in).toScVal(), + new Address(instruction.token_out).toScVal(), + nativeToScVal(instruction.amount_out, { type: "i128" }), + nativeToScVal(instruction.amount_in_max, { type: "i128" }), + nativeToScVal(instruction.deadline, { type: "u64" }), + ]); + + default: + throw new Error(`Unsupported action type: ${instruction}`); + } + }) ); - - try { - const investResult = await invokeCustomContract( - deployedVault, - "rebalance", - [mappedInstructions], - manager - ); - console.log("Rebalance successful:", scValToNative(investResult.returnValue)); - return {result: investResult, status: true}; - } catch (error) { - console.error("Rebalance failed:", error); - throw error; - } -} - -// Helper function to map SwapDetailsExactIn -function mapSwapDetailsExactIn(details: SwapDetailsExactIn) { - return [ - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("token_in"), - val: new Address(details.token_in).toScVal(), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("token_out"), - val: new Address(details.token_out).toScVal(), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("amount_in"), - val: nativeToScVal(details.amount_in, { type: "i128" }), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("amount_out_min"), - val: nativeToScVal(details.amount_out_min, { type: "i128" }), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("deadline"), - val: nativeToScVal(details.deadline, { type: "u64" }), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("distribution"), - val: xdr.ScVal.scvVec( - details.distribution.map((d) => - xdr.ScVal.scvMap([ - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("protocol_id"), - val: xdr.ScVal.scvString(d.protocol_id), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("path"), - val: xdr.ScVal.scvVec(d.path.map((address) => new Address(address).toScVal())), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("parts"), - val: nativeToScVal(d.parts, { type: "u32" }), - }), - ]) - ) - ), - }), - ]; -} - -// Helper function to map SwapDetailsExactOut -function mapSwapDetailsExactOut(details: SwapDetailsExactOut) { - return [ - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("token_in"), - val: new Address(details.token_in).toScVal(), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("token_out"), - val: new Address(details.token_out).toScVal(), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("amount_out"), - val: nativeToScVal(details.amount_out, { type: "i128" }), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("amount_in_max"), - val: nativeToScVal(details.amount_in_max, { type: "i128" }), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("deadline"), - val: nativeToScVal(details.deadline, { type: "u64" }), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("distribution"), - val: xdr.ScVal.scvVec( - details.distribution.map((d) => - xdr.ScVal.scvMap([ - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("protocol_id"), - val: xdr.ScVal.scvString(d.protocol_id), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("path"), - val: xdr.ScVal.scvVec(d.path.map((address) => new Address(address).toScVal())), - }), - new xdr.ScMapEntry({ - key: xdr.ScVal.scvSymbol("parts"), - val: nativeToScVal(d.parts, { type: "u32" }), - }), - ]) - ) - ), - }), - ]; } + + +// export async function rebalanceVault(deployedVault: string, instructions: Instruction[], manager: Keypair) { +// const mappedInstructions = xdr.ScVal.scvVec( +// instructions.map((instruction) => +// xdr.ScVal.scvMap([ +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("action"), +// val: nativeToScVal(instruction.action, { type: "u32" }), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("amount"), +// val: instruction.amount !== undefined +// ? nativeToScVal(instruction.amount, { type: "i128" }) +// : xdr.ScVal.scvVoid(), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("strategy"), +// val: instruction.strategy +// ? new Address(instruction.strategy).toScVal() +// : xdr.ScVal.scvVoid(), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("swap_details_exact_in"), +// val: instruction.swap_details_exact_in +// ? xdr.ScVal.scvMap( +// mapSwapDetailsExactIn(instruction.swap_details_exact_in) +// ) +// : xdr.ScVal.scvVec([xdr.ScVal.scvSymbol("None")]), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("swap_details_exact_out"), +// val: instruction.swap_details_exact_out +// ? xdr.ScVal.scvMap( +// mapSwapDetailsExactOut(instruction.swap_details_exact_out) +// ) +// : xdr.ScVal.scvVec([xdr.ScVal.scvSymbol("None")]), +// }), +// ]) +// ) +// ); + +// try { +// const investResult = await invokeCustomContract( +// deployedVault, +// "rebalance", +// [mappedInstructions], +// manager +// ); +// console.log("Rebalance successful:", scValToNative(investResult.returnValue)); +// return {result: investResult, status: true}; +// } catch (error) { +// console.error("Rebalance failed:", error); +// throw error; +// } +// } + +// // Helper function to map SwapDetailsExactIn +// function mapSwapDetailsExactIn(details: SwapDetailsExactIn) { +// return [ +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("token_in"), +// val: new Address(details.token_in).toScVal(), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("token_out"), +// val: new Address(details.token_out).toScVal(), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("amount_in"), +// val: nativeToScVal(details.amount_in, { type: "i128" }), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("amount_out_min"), +// val: nativeToScVal(details.amount_out_min, { type: "i128" }), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("deadline"), +// val: nativeToScVal(details.deadline, { type: "u64" }), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("distribution"), +// val: xdr.ScVal.scvVec( +// details.distribution.map((d) => +// xdr.ScVal.scvMap([ +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("protocol_id"), +// val: xdr.ScVal.scvString(d.protocol_id), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("path"), +// val: xdr.ScVal.scvVec(d.path.map((address) => new Address(address).toScVal())), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("parts"), +// val: nativeToScVal(d.parts, { type: "u32" }), +// }), +// ]) +// ) +// ), +// }), +// ]; +// } + +// // Helper function to map SwapDetailsExactOut +// function mapSwapDetailsExactOut(details: SwapDetailsExactOut) { +// return [ +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("token_in"), +// val: new Address(details.token_in).toScVal(), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("token_out"), +// val: new Address(details.token_out).toScVal(), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("amount_out"), +// val: nativeToScVal(details.amount_out, { type: "i128" }), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("amount_in_max"), +// val: nativeToScVal(details.amount_in_max, { type: "i128" }), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("deadline"), +// val: nativeToScVal(details.deadline, { type: "u64" }), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("distribution"), +// val: xdr.ScVal.scvVec( +// details.distribution.map((d) => +// xdr.ScVal.scvMap([ +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("protocol_id"), +// val: xdr.ScVal.scvString(d.protocol_id), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("path"), +// val: xdr.ScVal.scvVec(d.path.map((address) => new Address(address).toScVal())), +// }), +// new xdr.ScMapEntry({ +// key: xdr.ScVal.scvSymbol("parts"), +// val: nativeToScVal(d.parts, { type: "u32" }), +// }), +// ]) +// ) +// ), +// }), +// ]; +// } export async function fetchCurrentInvestedFunds(deployedVault:string, user:Keypair) { try { diff --git a/apps/contracts/strategies/blend/src/blend_pool.rs b/apps/contracts/strategies/blend/src/blend_pool.rs index 2c7c381a..ac244f6f 100644 --- a/apps/contracts/strategies/blend/src/blend_pool.rs +++ b/apps/contracts/strategies/blend/src/blend_pool.rs @@ -1,11 +1,19 @@ use defindex_strategy_core::StrategyError; -use soroban_sdk::{auth::{ContractContext, InvokerContractAuthEntry, SubContractInvocation}, panic_with_error, token::TokenClient, vec, Address, Env, IntoVal, Symbol, Vec}; - -use crate::{constants::REWARD_THRESHOLD, reserves, soroswap::internal_swap_exact_tokens_for_tokens, storage::{self, Config}}; - -soroban_sdk::contractimport!( - file = "../external_wasms/blend/blend_pool.wasm" - ); +use soroban_sdk::{ + auth::{ContractContext, InvokerContractAuthEntry, SubContractInvocation}, + panic_with_error, + token::TokenClient, + vec, Address, Env, IntoVal, Symbol, Vec, +}; + +use crate::{ + constants::REWARD_THRESHOLD, + reserves, + soroswap::internal_swap_exact_tokens_for_tokens, + storage::{self, Config}, +}; + +soroban_sdk::contractimport!(file = "../external_wasms/blend/blend_pool.wasm"); pub type BlendPoolClient<'a> = Client<'a>; // Define the RequestType enum with explicit u32 values @@ -41,11 +49,14 @@ pub fn supply(e: &Env, from: &Address, amount: &i128, config: &Config) -> i128 { .get(config.reserve_id) .unwrap_or(0); - let requests: Vec = vec![&e, Request { - address: config.asset.clone(), - amount: amount.clone(), - request_type: RequestType::Supply.to_u32(), - }]; + let requests: Vec = vec![ + &e, + Request { + address: config.asset.clone(), + amount: amount.clone(), + request_type: RequestType::Supply.to_u32(), + }, + ]; e.authorize_as_current_contract(vec![ &e, @@ -56,17 +67,19 @@ pub fn supply(e: &Env, from: &Address, amount: &i128, config: &Config) -> i128 { args: ( e.current_contract_address(), config.pool.clone(), - amount.clone()).into_val(e), + amount.clone(), + ) + .into_val(e), }, sub_invocations: vec![&e], }), ]); - + let new_positions = pool_client.submit( &e.current_contract_address(), &e.current_contract_address(), &from, - &requests + &requests, ); // Calculate the amount of bTokens received @@ -86,24 +99,27 @@ pub fn withdraw(e: &Env, to: &Address, amount: &i128, config: &Config) -> (i128, // Get balance pre-withdraw, as the pool can modify the withdrawal amount let pre_withdrawal_balance = TokenClient::new(&e, &config.asset).balance(&to); - let requests: Vec = vec![&e, Request { - address: config.asset.clone(), - amount: amount.clone(), - request_type: RequestType::Withdraw.to_u32(), - }]; + let requests: Vec = vec![ + &e, + Request { + address: config.asset.clone(), + amount: amount.clone(), + request_type: RequestType::Withdraw.to_u32(), + }, + ]; // Execute the withdrawal - the tokens are transferred from the pool to the vault let new_positions = pool_client.submit( &e.current_contract_address(), &e.current_contract_address(), &to, - &requests + &requests, ); // Calculate the amount of tokens withdrawn and bTokens burnt let post_withdrawal_balance = TokenClient::new(&e, &config.asset).balance(&to); let real_amount = post_withdrawal_balance - pre_withdrawal_balance; - + // position entry is deleted if the position is cleared let b_tokens_amount = pre_supply - new_positions.supply.get(config.reserve_id).unwrap_or(0); (real_amount, b_tokens_amount) @@ -116,15 +132,16 @@ pub fn claim(e: &Env, from: &Address, config: &Config) -> i128 { pool_client.claim(from, &vec![&e, 0u32, 1u32, 2u32, 3u32], from) } -pub fn perform_reinvest(e: &Env, config: &Config) -> Result{ +pub fn perform_reinvest(e: &Env, config: &Config) -> Result { // Check the current BLND balance - let blnd_balance = TokenClient::new(e, &config.blend_token).balance(&e.current_contract_address()); + let blnd_balance = + TokenClient::new(e, &config.blend_token).balance(&e.current_contract_address()); // If balance does not exceed threshold, skip harvest if blnd_balance < REWARD_THRESHOLD { return Ok(false); } - + // Swap BLND to the underlying asset let mut swap_path: Vec
= vec![&e]; swap_path.push_back(config.blend_token.clone()); @@ -146,7 +163,7 @@ pub fn perform_reinvest(e: &Env, config: &Config) -> Result .get(1) .ok_or(StrategyError::InvalidArgument)? .into_val(e); - + // Supplying underlying asset into blend pool let b_tokens_minted = supply(&e, &e.current_contract_address(), &amount_out, &config); @@ -154,4 +171,4 @@ pub fn perform_reinvest(e: &Env, config: &Config) -> Result reserves::harvest(&e, reserves, amount_out, b_tokens_minted); Ok(true) -} \ No newline at end of file +} diff --git a/apps/contracts/strategies/blend/src/constants.rs b/apps/contracts/strategies/blend/src/constants.rs index f4ef1ef4..b51522c1 100644 --- a/apps/contracts/strategies/blend/src/constants.rs +++ b/apps/contracts/strategies/blend/src/constants.rs @@ -5,4 +5,4 @@ pub const SCALAR_9: i128 = 1_000_000_000; /// The minimum amount of tokens than can be deposited or withdrawn from the vault pub const MIN_DUST: i128 = 0_0010000; -pub const REWARD_THRESHOLD: i128 = 40_0000000; \ No newline at end of file +pub const REWARD_THRESHOLD: i128 = 40_0000000; diff --git a/apps/contracts/strategies/blend/src/lib.rs b/apps/contracts/strategies/blend/src/lib.rs index 5e121b2a..e4201ddd 100644 --- a/apps/contracts/strategies/blend/src/lib.rs +++ b/apps/contracts/strategies/blend/src/lib.rs @@ -3,7 +3,8 @@ use blend_pool::perform_reinvest; use constants::{MIN_DUST, SCALAR_9}; use reserves::StrategyReserves; use soroban_sdk::{ - contract, contractimpl, token::TokenClient, Address, Env, IntoVal, String, Val, Vec}; + contract, contractimpl, token::TokenClient, Address, Env, IntoVal, String, Val, Vec, +}; mod blend_pool; mod constants; @@ -13,10 +14,7 @@ mod storage; use storage::{extend_instance_ttl, has_config, Config}; -pub use defindex_strategy_core::{ - DeFindexStrategyTrait, - StrategyError, - event}; +pub use defindex_strategy_core::{event, DeFindexStrategyTrait, StrategyError}; pub fn check_nonnegative_amount(amount: i128) -> Result<(), StrategyError> { if amount < 0 { @@ -41,15 +39,27 @@ struct BlendStrategy; #[contractimpl] impl DeFindexStrategyTrait for BlendStrategy { - fn __constructor( - e: Env, - asset: Address, - init_args: Vec, - ) { - let blend_pool_address: Address = init_args.get(0).ok_or(StrategyError::InvalidArgument).unwrap().into_val(&e); - let reserve_id: u32 = init_args.get(1).ok_or(StrategyError::InvalidArgument).unwrap().into_val(&e); - let blend_token: Address = init_args.get(2).ok_or(StrategyError::InvalidArgument).unwrap().into_val(&e); - let soroswap_router: Address = init_args.get(3).ok_or(StrategyError::InvalidArgument).unwrap().into_val(&e); + fn __constructor(e: Env, asset: Address, init_args: Vec) { + let blend_pool_address: Address = init_args + .get(0) + .ok_or(StrategyError::InvalidArgument) + .unwrap() + .into_val(&e); + let reserve_id: u32 = init_args + .get(1) + .ok_or(StrategyError::InvalidArgument) + .unwrap() + .into_val(&e); + let blend_token: Address = init_args + .get(2) + .ok_or(StrategyError::InvalidArgument) + .unwrap() + .into_val(&e); + let soroswap_router: Address = init_args + .get(3) + .ok_or(StrategyError::InvalidArgument) + .unwrap() + .into_val(&e); let config = Config { asset: asset.clone(), @@ -58,7 +68,7 @@ impl DeFindexStrategyTrait for BlendStrategy { blend_token, router: soroswap_router, }; - + storage::set_config(&e, config); } @@ -69,11 +79,7 @@ impl DeFindexStrategyTrait for BlendStrategy { Ok(storage::get_config(&e).asset) } - fn deposit( - e: Env, - amount: i128, - from: Address, - ) -> Result { + fn deposit(e: Env, amount: i128, from: Address) -> Result { check_initialized(&e)?; check_nonnegative_amount(amount)?; extend_instance_ttl(&e); @@ -114,16 +120,16 @@ impl DeFindexStrategyTrait for BlendStrategy { perform_reinvest(&e, &config)?; - event::emit_harvest(&e, String::from_str(&e, STARETEGY_NAME), harvested_blend, from); + event::emit_harvest( + &e, + String::from_str(&e, STARETEGY_NAME), + harvested_blend, + from, + ); Ok(()) } - fn withdraw( - e: Env, - amount: i128, - from: Address, - to: Address, - ) -> Result { + fn withdraw(e: Env, amount: i128, from: Address, to: Address) -> Result { check_initialized(&e)?; check_nonnegative_amount(amount)?; extend_instance_ttl(&e); @@ -132,7 +138,7 @@ impl DeFindexStrategyTrait for BlendStrategy { // protect against rouding of reserve_vault::update_rate, as small amounts // can cause incorrect b_rate calculations due to the pool rounding if amount < MIN_DUST { - return Err(StrategyError::InvalidArgument) //TODO: create a new error type for this + return Err(StrategyError::InvalidArgument); //TODO: create a new error type for this } let reserves = storage::get_strategy_reserves(&e); @@ -141,7 +147,13 @@ impl DeFindexStrategyTrait for BlendStrategy { let (tokens_withdrawn, b_tokens_burnt) = blend_pool::withdraw(&e, &to, &amount, &config); - let vault_shares = reserves::withdraw(&e, reserves.clone(), &from, tokens_withdrawn, b_tokens_burnt); + let vault_shares = reserves::withdraw( + &e, + reserves.clone(), + &from, + tokens_withdrawn, + b_tokens_burnt, + ); let underlying_balance = shares_to_underlying(vault_shares, reserves); event::emit_withdraw(&e, String::from_str(&e, STARETEGY_NAME), amount, from); @@ -149,21 +161,18 @@ impl DeFindexStrategyTrait for BlendStrategy { Ok(underlying_balance) } - fn balance( - e: Env, - from: Address, - ) -> Result { + fn balance(e: Env, from: Address) -> Result { check_initialized(&e)?; extend_instance_ttl(&e); - + // Get the vault's shares let vault_shares = storage::get_vault_shares(&e, &from); - + // Get the strategy's total shares and bTokens let reserves = storage::get_strategy_reserves(&e); - + let underlying_balance = shares_to_underlying(vault_shares, reserves); - + Ok(underlying_balance) } } @@ -178,8 +187,8 @@ fn shares_to_underlying(shares: i128, reserves: StrategyReserves) -> i128 { } // Calculate the bTokens corresponding to the vault's shares let vault_b_tokens = (shares * total_b_tokens) / total_shares; - + // Use the b_rate to convert bTokens to underlying assets (vault_b_tokens * reserves.b_rate) / SCALAR_9 } -mod test; \ No newline at end of file +mod test; diff --git a/apps/contracts/strategies/blend/src/reserves.rs b/apps/contracts/strategies/blend/src/reserves.rs index 9a2fad13..ee814bfc 100644 --- a/apps/contracts/strategies/blend/src/reserves.rs +++ b/apps/contracts/strategies/blend/src/reserves.rs @@ -46,13 +46,10 @@ impl StrategyReserves { pub fn update_rate(&mut self, amount: i128, b_tokens: i128) { // Calculate the new bRate - 9 decimal places of precision // Update the reserve's bRate - let new_rate = amount - .fixed_div_floor(b_tokens, SCALAR_9) - .unwrap(); + let new_rate = amount.fixed_div_floor(b_tokens, SCALAR_9).unwrap(); self.b_rate = new_rate; } - } /// Deposit into the reserve vault. This function expects the deposit to have already been made @@ -73,15 +70,15 @@ pub fn deposit( } reserves.update_rate(underlying_amount, b_tokens_amount); - + let mut vault_shares = storage::get_vault_shares(&e, &from); let share_amount: i128 = reserves.b_tokens_to_shares_down(b_tokens_amount); - + reserves.total_shares += share_amount; reserves.total_b_tokens += b_tokens_amount; vault_shares += share_amount; - + storage::set_strategy_reserves(&e, reserves); storage::set_vault_shares(&e, &from, vault_shares); vault_shares @@ -114,7 +111,7 @@ pub fn withdraw( reserves.total_shares -= share_amount; reserves.total_b_tokens -= b_tokens_amount; - + if share_amount > vault_shares { panic_with_error!(e, StrategyError::InsufficientBalance); } @@ -141,8 +138,8 @@ pub fn harvest( } reserves.update_rate(underlying_amount, b_tokens_amount); - + reserves.total_b_tokens += b_tokens_amount; storage::set_strategy_reserves(&e, reserves); -} \ No newline at end of file +} diff --git a/apps/contracts/strategies/blend/src/soroswap.rs b/apps/contracts/strategies/blend/src/soroswap.rs index 3e8e10fa..fb457479 100644 --- a/apps/contracts/strategies/blend/src/soroswap.rs +++ b/apps/contracts/strategies/blend/src/soroswap.rs @@ -1,5 +1,8 @@ use defindex_strategy_core::StrategyError; -use soroban_sdk::{auth::{ContractContext, InvokerContractAuthEntry, SubContractInvocation}, vec, Address, Env, IntoVal, Symbol, Val, Vec}; +use soroban_sdk::{ + auth::{ContractContext, InvokerContractAuthEntry, SubContractInvocation}, + vec, Address, Env, IntoVal, Symbol, Val, Vec, +}; use crate::storage::Config; @@ -23,7 +26,11 @@ pub fn internal_swap_exact_tokens_for_tokens( let pair_address: Address = e.invoke_contract( &config.router, &Symbol::new(&e, "router_pair_for"), - vec![&e, path.get(0).unwrap().into_val(e), path.get(1).unwrap().into_val(e)] + vec![ + &e, + path.get(0).unwrap().into_val(e), + path.get(1).unwrap().into_val(e), + ], ); e.authorize_as_current_contract(vec![ @@ -35,7 +42,9 @@ pub fn internal_swap_exact_tokens_for_tokens( args: ( e.current_contract_address(), pair_address, - amount_in.clone()).into_val(e), + amount_in.clone(), + ) + .into_val(e), }, sub_invocations: vec![&e], }), @@ -46,4 +55,4 @@ pub fn internal_swap_exact_tokens_for_tokens( &Symbol::new(&e, "swap_exact_tokens_for_tokens"), swap_args, ) -} \ No newline at end of file +} diff --git a/apps/contracts/strategies/blend/src/storage.rs b/apps/contracts/strategies/blend/src/storage.rs index dedd7a4c..8b86049f 100644 --- a/apps/contracts/strategies/blend/src/storage.rs +++ b/apps/contracts/strategies/blend/src/storage.rs @@ -16,7 +16,7 @@ pub struct Config { pub enum DataKey { Config, Reserves, - VaultPos(Address) // Vaults Positions + VaultPos(Address), // Vaults Positions } pub const DAY_IN_LEDGERS: u32 = 17280; @@ -56,12 +56,17 @@ pub fn set_vault_shares(e: &Env, address: &Address, shares: i128) { /// Get the number of strategy shares a user owns. Shares are stored with 7 decimal places of precision. pub fn get_vault_shares(e: &Env, address: &Address) -> i128 { - let result = e.storage().persistent().get::(&DataKey::VaultPos(address.clone())); + let result = e + .storage() + .persistent() + .get::(&DataKey::VaultPos(address.clone())); match result { Some(shares) => { - e.storage() - .persistent() - .extend_ttl(&DataKey::VaultPos(address.clone()), LEDGER_THRESHOLD, LEDGER_BUMP); + e.storage().persistent().extend_ttl( + &DataKey::VaultPos(address.clone()), + LEDGER_THRESHOLD, + LEDGER_BUMP, + ); shares } None => 0, @@ -70,16 +75,18 @@ pub fn get_vault_shares(e: &Env, address: &Address) -> i128 { // Strategy Reserves pub fn set_strategy_reserves(e: &Env, new_reserves: StrategyReserves) { - e.storage().instance().set(&DataKey::Reserves, &new_reserves); + e.storage() + .instance() + .set(&DataKey::Reserves, &new_reserves); } pub fn get_strategy_reserves(e: &Env) -> StrategyReserves { - e.storage().instance().get(&DataKey::Reserves).unwrap_or( - StrategyReserves { + e.storage() + .instance() + .get(&DataKey::Reserves) + .unwrap_or(StrategyReserves { total_shares: 0, total_b_tokens: 0, b_rate: 0, - } - ) + }) } - diff --git a/apps/contracts/strategies/blend/src/test.rs b/apps/contracts/strategies/blend/src/test.rs index 9d4a6952..4eaf84f9 100644 --- a/apps/contracts/strategies/blend/src/test.rs +++ b/apps/contracts/strategies/blend/src/test.rs @@ -2,11 +2,15 @@ extern crate std; use crate::{ - blend_pool::{self, BlendPoolClient, Request, ReserveConfig, ReserveEmissionMetadata}, storage::DAY_IN_LEDGERS, BlendStrategy + blend_pool::{self, BlendPoolClient, Request, ReserveConfig, ReserveEmissionMetadata}, + storage::DAY_IN_LEDGERS, + BlendStrategy, }; use sep_41_token::testutils::MockTokenClient; use soroban_sdk::{ - testutils::{BytesN as _, Ledger as _, LedgerInfo}, token::StellarAssetClient, vec, Address, BytesN, Env, IntoVal, String, Symbol, Val, Vec + testutils::{BytesN as _, Ledger as _, LedgerInfo}, + token::StellarAssetClient, + vec, Address, BytesN, Env, IntoVal, String, Symbol, Val, Vec, }; mod blend_factory_pool { @@ -25,8 +29,21 @@ mod blend_comet { soroban_sdk::contractimport!(file = "../external_wasms/blend/comet.wasm"); } -pub(crate) fn register_blend_strategy(e: &Env, asset: &Address, blend_pool: &Address, reserve_id: &u32, blend_token: &Address, soroswap_router: &Address) -> Address { - let init_args: Vec= vec![e, blend_pool.into_val(e), reserve_id.into_val(e), blend_token.into_val(e), soroswap_router.into_val(e)]; +pub(crate) fn register_blend_strategy( + e: &Env, + asset: &Address, + blend_pool: &Address, + reserve_id: &u32, + blend_token: &Address, + soroswap_router: &Address, +) -> Address { + let init_args: Vec = vec![ + e, + blend_pool.into_val(e), + reserve_id.into_val(e), + blend_token.into_val(e), + soroswap_router.into_val(e), + ]; let args = (asset, init_args); e.register(BlendStrategy, args) @@ -159,9 +176,23 @@ pub(crate) fn create_blend_pool( } /// Create a Blend Strategy -pub(crate) fn create_blend_strategy(e: &Env, underlying_asset: &Address, blend_pool: &Address, reserve_id: &u32, blend_token: &Address, soroswap_router: &Address) -> Address { - let address = register_blend_strategy(e, underlying_asset, blend_pool, reserve_id, blend_token, soroswap_router); - +pub(crate) fn create_blend_strategy( + e: &Env, + underlying_asset: &Address, + blend_pool: &Address, + reserve_id: &u32, + blend_token: &Address, + soroswap_router: &Address, +) -> Address { + let address = register_blend_strategy( + e, + underlying_asset, + blend_pool, + reserve_id, + blend_token, + soroswap_router, + ); + address } @@ -311,7 +342,8 @@ impl<'a> BlendFixture<'a> { .mock_all_auths() .initialize(&blnd, &backstop, &comet); - let backstop_client: blend_backstop::Client<'a> = blend_backstop::Client::new(env, &backstop); + let backstop_client: blend_backstop::Client<'a> = + blend_backstop::Client::new(env, &backstop); backstop_client.mock_all_auths().initialize( &comet, &emitter, diff --git a/apps/contracts/strategies/blend/src/test/blend/mod.rs b/apps/contracts/strategies/blend/src/test/blend/mod.rs index 901248a4..20bf0d43 100644 --- a/apps/contracts/strategies/blend/src/test/blend/mod.rs +++ b/apps/contracts/strategies/blend/src/test/blend/mod.rs @@ -1,2 +1,2 @@ +mod soroswap_setup; mod success; -mod soroswap_setup; \ No newline at end of file diff --git a/apps/contracts/strategies/blend/src/test/blend/soroswap_setup.rs b/apps/contracts/strategies/blend/src/test/blend/soroswap_setup.rs index 0f1535dc..8adfb3c6 100644 --- a/apps/contracts/strategies/blend/src/test/blend/soroswap_setup.rs +++ b/apps/contracts/strategies/blend/src/test/blend/soroswap_setup.rs @@ -1,18 +1,15 @@ -use soroban_sdk::{ - Env, BytesN, Address, - testutils::{Address as _} -}; +use soroban_sdk::{testutils::Address as _, Address, BytesN, Env}; fn pair_contract_wasm(e: &Env) -> BytesN<32> { - soroban_sdk::contractimport!( - file = "../external_wasms/soroswap/soroswap_pair.optimized.wasm" - ); + soroban_sdk::contractimport!(file = "../external_wasms/soroswap/soroswap_pair.optimized.wasm"); e.deployer().upload_contract_wasm(WASM) } // SoroswapFactory Contract mod factory { - soroban_sdk::contractimport!(file = "../external_wasms/soroswap/soroswap_factory.optimized.wasm"); + soroban_sdk::contractimport!( + file = "../external_wasms/soroswap/soroswap_factory.optimized.wasm" + ); pub type SoroswapFactoryClient<'a> = Client<'a>; } use factory::SoroswapFactoryClient; @@ -27,7 +24,9 @@ pub fn create_soroswap_factory<'a>(e: &Env, setter: &Address) -> SoroswapFactory // SoroswapRouter Contract mod router { - soroban_sdk::contractimport!(file = "../external_wasms/soroswap/soroswap_router.optimized.wasm"); + soroban_sdk::contractimport!( + file = "../external_wasms/soroswap/soroswap_router.optimized.wasm" + ); pub type SoroswapRouterClient<'a> = Client<'a>; } pub use router::SoroswapRouterClient; @@ -39,22 +38,29 @@ pub fn create_soroswap_router<'a>(e: &Env, factory: &Address) -> SoroswapRouterC router.initialize(factory); router } - -pub fn create_soroswap_pool<'a>(e: &Env, to: &Address, token_a: &Address, token_b: &Address, amount_a: &i128, amount_b: &i128) -> SoroswapRouterClient<'a> { + +pub fn create_soroswap_pool<'a>( + e: &Env, + to: &Address, + token_a: &Address, + token_b: &Address, + amount_a: &i128, + amount_b: &i128, +) -> SoroswapRouterClient<'a> { let soroswap_admin = Address::generate(&e); let factory = create_soroswap_factory(&e, &soroswap_admin); let router = create_soroswap_router(&e, &factory.address); router.add_liquidity( - token_a, - token_b, - &amount_a, - &amount_b, - &0i128, - &0i128, - &to, - &(e.ledger().timestamp() + 3600) + token_a, + token_b, + &amount_a, + &amount_b, + &0i128, + &0i128, + &to, + &(e.ledger().timestamp() + 3600), ); router -} \ No newline at end of file +} diff --git a/apps/contracts/strategies/blend/src/test/blend/success.rs b/apps/contracts/strategies/blend/src/test/blend/success.rs index 6852aa1d..b4947f2a 100644 --- a/apps/contracts/strategies/blend/src/test/blend/success.rs +++ b/apps/contracts/strategies/blend/src/test/blend/success.rs @@ -3,13 +3,13 @@ use crate::blend_pool::{BlendPoolClient, Request}; use crate::constants::MIN_DUST; use crate::storage::DAY_IN_LEDGERS; use crate::test::blend::soroswap_setup::create_soroswap_pool; +use crate::test::std; use crate::test::{create_blend_pool, create_blend_strategy, BlendFixture, EnvTestUtils}; use crate::BlendStrategyClient; use defindex_strategy_core::StrategyError; use sep_41_token::testutils::MockTokenClient; use soroban_sdk::testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}; use soroban_sdk::{vec, Address, Env, IntoVal, Symbol}; -use crate::test::std; #[test] fn success() { @@ -36,7 +36,14 @@ fn success() { let amount_b = 50000000_0_000_000; blnd_client.mint(&pool_admin, &amount_a); usdc_client.mint(&pool_admin, &amount_b); - let soroswap_router = create_soroswap_pool(&e, &pool_admin, &blnd.address(), &usdc.address(), &amount_a, &amount_b); + let soroswap_router = create_soroswap_pool( + &e, + &pool_admin, + &blnd.address(), + &usdc.address(), + &amount_a, + &amount_b, + ); // End of setting up soroswap pool let blend_fixture = BlendFixture::deploy(&e, &admin, &blnd.address(), &usdc.address()); @@ -46,7 +53,14 @@ fn success() { // emits to each reserve token evently, and starts emissions let pool = create_blend_pool(&e, &blend_fixture, &admin, &usdc_client, &xlm_client); let pool_client = BlendPoolClient::new(&e, &pool); - let strategy = create_blend_strategy(&e, &usdc.address(), &pool, &0u32, &blnd.address(), &soroswap_router.address); + let strategy = create_blend_strategy( + &e, + &usdc.address(), + &pool, + &0u32, + &blnd.address(), + &soroswap_router.address, + ); let strategy_client = BlendStrategyClient::new(&e, &strategy); /* @@ -64,10 +78,9 @@ fn success() { let user_3_balance = usdc_client.balance(&user_3); assert_eq!(user_3_balance, starting_balance); - strategy_client.deposit(&starting_balance, &user_2); // -> verify deposit auth - + assert_eq!( e.auths()[0], ( @@ -76,11 +89,7 @@ fn success() { function: AuthorizedFunction::Contract(( strategy.clone(), Symbol::new(&e, "deposit"), - vec![ - &e, - starting_balance.into_val(&e), - user_2.to_val(), - ] + vec![&e, starting_balance.into_val(&e), user_2.to_val(),] )), sub_invocations: std::vec![AuthorizedInvocation { function: AuthorizedFunction::Contract(( @@ -184,7 +193,8 @@ fn success() { // withdraw_amount = 100_0958904 // -> verify over withdraw fails - let result = strategy_client.try_withdraw(&(withdraw_amount + 100_000_000_0000000), &user_3, &user_3); + let result = + strategy_client.try_withdraw(&(withdraw_amount + 100_000_000_0000000), &user_3, &user_3); assert_eq!(result, Err(Ok(StrategyError::InsufficientBalance))); strategy_client.withdraw(&withdraw_amount, &user_2, &user_2); @@ -238,5 +248,5 @@ fn success() { assert_eq!(usdc_strategy_balance, 0); let user_3_strategy_balance = strategy_client.balance(&user_3); - assert_eq!(user_3_strategy_balance, 1226627059); + assert_eq!(user_3_strategy_balance, 1226627059); } diff --git a/apps/contracts/strategies/core/src/error.rs b/apps/contracts/strategies/core/src/error.rs index c8766095..451c9482 100644 --- a/apps/contracts/strategies/core/src/error.rs +++ b/apps/contracts/strategies/core/src/error.rs @@ -17,4 +17,3 @@ pub enum StrategyError { DeadlineExpired = 421, ExternalError = 422, } - diff --git a/apps/contracts/strategies/core/src/event.rs b/apps/contracts/strategies/core/src/event.rs index 987a590d..6df1e1e7 100644 --- a/apps/contracts/strategies/core/src/event.rs +++ b/apps/contracts/strategies/core/src/event.rs @@ -4,7 +4,7 @@ use soroban_sdk::{contracttype, symbol_short, Address, Env, String}; // DEPOSIT EVENT -#[contracttype] +#[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct DepositEvent { pub amount: i128, @@ -12,29 +12,22 @@ pub struct DepositEvent { } /// Publishes an `DepositEvent` to the event stream. -/// +/// /// # Arguments -/// +/// /// * `e` - An instance of the `Env` struct. /// * `strategy_name` - The name of the strategy. /// * `amount` - The amount of tokens deposited. /// * `from` - The address of the account/vault that deposited the tokens. -pub fn emit_deposit( - e: &Env, - strategy_name: String, - amount: i128, - from: Address, -) { - let event = DepositEvent { - amount, - from, - }; +pub fn emit_deposit(e: &Env, strategy_name: String, amount: i128, from: Address) { + let event = DepositEvent { amount, from }; - e.events().publish((strategy_name, symbol_short!("deposit")), event); -} + e.events() + .publish((strategy_name, symbol_short!("deposit")), event); +} // HARVEST EVENT -#[contracttype] +#[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct HarvestEvent { pub amount: i128, @@ -42,53 +35,39 @@ pub struct HarvestEvent { } /// Publishes an `HarvestEvent` to the event stream. -/// +/// /// # Arguments -/// +/// /// * `e` - An instance of the `Env` struct. /// * `strategy_name` - The name of the strategy. /// * `amount` - The amount of tokens harvested.` /// * `from` - The address of the account/vault that harvested the tokens. -pub fn emit_harvest( - e: &Env, - strategy_name: String, - amount: i128, - from: Address, -) { - let event = HarvestEvent { - amount, - from, - }; +pub fn emit_harvest(e: &Env, strategy_name: String, amount: i128, from: Address) { + let event = HarvestEvent { amount, from }; - e.events().publish((strategy_name, symbol_short!("harvest")), event); + e.events() + .publish((strategy_name, symbol_short!("harvest")), event); } // WITHDRAW EVENT -#[contracttype] +#[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct WithdrawEvent { pub amount: i128, - pub from: Address + pub from: Address, } /// Publishes an `WithdrawEvent` to the event stream. -/// +/// /// # Arguments -/// +/// /// * `e` - An instance of the `Env` struct. /// * `strategy_name` - The name of the strategy. /// * `amount` - The amount of tokens withdrawn. /// * `from` - The address of the account/vault that withdrew the tokens. -pub fn emit_withdraw( - e: &Env, - strategy_name: String, - amount: i128, - from: Address -) { - let event = WithdrawEvent { - amount, - from, - }; +pub fn emit_withdraw(e: &Env, strategy_name: String, amount: i128, from: Address) { + let event = WithdrawEvent { amount, from }; - e.events().publish((strategy_name, symbol_short!("withdraw")), event); -} \ No newline at end of file + e.events() + .publish((strategy_name, symbol_short!("withdraw")), event); +} diff --git a/apps/contracts/strategies/core/src/lib.rs b/apps/contracts/strategies/core/src/lib.rs index e07aabc2..e6659c79 100644 --- a/apps/contracts/strategies/core/src/lib.rs +++ b/apps/contracts/strategies/core/src/lib.rs @@ -10,7 +10,7 @@ pub use error::StrategyError; #[contractclient(name = "DeFindexStrategyClient")] /// Trait that defines the required methods for implementing a DeFindex strategy. -/// +/// /// Each strategy contract must implement this trait to ensure compatibility with the /// DeFindex vault. The trait defines essential functions for initialization, asset management, /// and yield generation, enabling DeFindex to interact with various DeFi strategies @@ -19,22 +19,18 @@ pub trait DeFindexStrategyTrait { /// Initializes the strategy with the given parameters. /// /// It sets up the strategy's underlying asset and any additional parameters required for the strategy. - /// + /// /// # Parameters /// - `env`: The execution environment. /// - `asset`: The address of the underlying asset that this strategy will manage. /// - `init_args`: A vector of additional arguments, which may vary depending on the strategy's requirements (e.g., configurations, addresses). - fn __constructor( - env: Env, - asset: Address, - init_args: Vec, - ); + fn __constructor(env: Env, asset: Address, init_args: Vec); /// Returns the underlying asset address managed by the strategy. /// - /// This function provides the address of the asset that this strategy is managing. It is used + /// This function provides the address of the asset that this strategy is managing. It is used /// by the DeFindex vault to determine which asset is associated with this strategy. - /// + /// /// # Parameters /// - `env`: The execution environment. /// @@ -57,12 +53,8 @@ pub trait DeFindexStrategyTrait { /// - `Err(StrategyError)` if the deposit fails for any reason. /// /// It is very important that the return is the balance of the `from` address - /// in the context of DeFindex. This ensures that the vault can keep track of the strategy's status, - fn deposit( - env: Env, - amount: i128, - from: Address - ) -> Result; + /// in the context of DeFindex. This ensures that the vault can keep track of the strategy's status, + fn deposit(env: Env, amount: i128, from: Address) -> Result; /// Harvests yields generated by the strategy. /// @@ -81,7 +73,7 @@ pub trait DeFindexStrategyTrait { /// Returns the current balance of the underlying asset in the strategy. /// - /// This function provides the current balance of the underlying asset that is managed by + /// This function provides the current balance of the underlying asset that is managed by /// the strategy on behalf of the specified address. It is used to track the assets held in the strategy. /// /// # Parameters @@ -91,15 +83,12 @@ pub trait DeFindexStrategyTrait { /// # Returns /// - `Ok(i128)` containing the balance of the underlying asset. /// - `Err(StrategyError)` if the balance cannot be retrieved. - /// + /// /// It is important to note that the return value should be in terms of the underlying asset /// and not some kind of share or derivative. This ensures that the balance accurately reflects /// the amount of the actual asset managed by the strategy. - fn balance( - env: Env, - from: Address, - ) -> Result; - + fn balance(env: Env, from: Address) -> Result; + /// Withdraws the specified amount of the underlying asset from the strategy. /// /// This function allows the DeFindex vault to withdraw assets from the strategy. @@ -113,13 +102,8 @@ pub trait DeFindexStrategyTrait { /// # Returns /// - `Ok(i128)` containing the balance of the `from` address after the withdraw. /// - `Err(StrategyError)` if the withdrawal fails (e.g., insufficient balance). - /// + /// /// It is very important that the return is the balance of the `from` address - /// in the context of DeFindex. This ensures that the vault can keep track of the strategy's status, - fn withdraw( - env: Env, - amount: i128, - from: Address, - to: Address, - ) -> Result; -} \ No newline at end of file + /// in the context of DeFindex. This ensures that the vault can keep track of the strategy's status, + fn withdraw(env: Env, amount: i128, from: Address, to: Address) -> Result; +} diff --git a/apps/contracts/strategies/fixed_apr/src/balance.rs b/apps/contracts/strategies/fixed_apr/src/balance.rs index 1f5751be..39fa6574 100644 --- a/apps/contracts/strategies/fixed_apr/src/balance.rs +++ b/apps/contracts/strategies/fixed_apr/src/balance.rs @@ -6,9 +6,11 @@ use crate::StrategyError; pub fn read_balance(e: &Env, addr: Address) -> i128 { let key = DataKey::Balance(addr); if let Some(balance) = e.storage().persistent().get::(&key) { - e.storage() - .persistent() - .extend_ttl(&key, INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + e.storage().persistent().extend_ttl( + &key, + INSTANCE_LIFETIME_THRESHOLD, + INSTANCE_BUMP_AMOUNT, + ); balance } else { 0 @@ -26,14 +28,14 @@ fn write_balance(e: &Env, addr: Address, amount: i128) { pub fn receive_balance(e: &Env, addr: Address, amount: i128) { let balance = read_balance(e, addr.clone()); - let new_balance = balance.checked_add(amount) + let new_balance = balance + .checked_add(amount) .expect("Integer overflow occurred while adding balance."); write_balance(e, addr, new_balance); } pub fn spend_balance(e: &Env, addr: Address, amount: i128) -> Result<(), StrategyError> { - let balance = read_balance(e, addr.clone()); if balance < amount { return Err(StrategyError::InsufficientBalance); diff --git a/apps/contracts/strategies/fixed_apr/src/lib.rs b/apps/contracts/strategies/fixed_apr/src/lib.rs index f84c4e03..e4f66bf4 100644 --- a/apps/contracts/strategies/fixed_apr/src/lib.rs +++ b/apps/contracts/strategies/fixed_apr/src/lib.rs @@ -1,7 +1,7 @@ #![no_std] use constants::{MAX_BPS, SECONDS_PER_YEAR}; use soroban_sdk::{ - contract, contractimpl, token::Client as TokenClient, Address, Env, IntoVal, String, Val, Vec + contract, contractimpl, token::Client as TokenClient, Address, Env, IntoVal, String, Val, Vec, }; mod balance; @@ -11,11 +11,11 @@ mod yield_balance; use balance::{read_balance, receive_balance, spend_balance}; use storage::{ - extend_instance_ttl, get_underlying_asset, is_initialized, set_initialized, - set_underlying_asset, set_apr, get_apr, set_last_harvest_time, get_last_harvest_time, + extend_instance_ttl, get_apr, get_last_harvest_time, get_underlying_asset, is_initialized, + set_apr, set_initialized, set_last_harvest_time, set_underlying_asset, }; -pub use defindex_strategy_core::{DeFindexStrategyTrait, StrategyError, event}; +pub use defindex_strategy_core::{event, DeFindexStrategyTrait, StrategyError}; use yield_balance::{read_yield, receive_yield, spend_yield}; pub fn check_nonnegative_amount(amount: i128) -> Result<(), StrategyError> { @@ -41,14 +41,14 @@ struct FixAprStrategy; #[contractimpl] impl DeFindexStrategyTrait for FixAprStrategy { - fn __constructor( - e: Env, - asset: Address, - init_args: Vec, - ) { + fn __constructor(e: Env, asset: Address, init_args: Vec) { // Extract APR from `init_args`, assumed to be the first argument - let apr_bps: u32 = init_args.get(0).ok_or(StrategyError::InvalidArgument).unwrap().into_val(&e); - + let apr_bps: u32 = init_args + .get(0) + .ok_or(StrategyError::InvalidArgument) + .unwrap() + .into_val(&e); + set_initialized(&e); set_underlying_asset(&e, &asset); set_apr(&e, apr_bps); @@ -60,11 +60,7 @@ impl DeFindexStrategyTrait for FixAprStrategy { Ok(get_underlying_asset(&e)) } - fn deposit( - e: Env, - amount: i128, - from: Address, - ) -> Result { + fn deposit(e: Env, amount: i128, from: Address) -> Result { check_initialized(&e)?; check_nonnegative_amount(amount)?; extend_instance_ttl(&e); @@ -79,7 +75,12 @@ impl DeFindexStrategyTrait for FixAprStrategy { receive_balance(&e, from.clone(), amount); set_last_harvest_time(&e, e.ledger().timestamp(), from.clone()); - event::emit_deposit(&e, String::from_str(&e, STRATEGY_NAME), amount, from.clone()); + event::emit_deposit( + &e, + String::from_str(&e, STRATEGY_NAME), + amount, + from.clone(), + ); Ok(read_balance(&e, from)) } @@ -87,54 +88,50 @@ impl DeFindexStrategyTrait for FixAprStrategy { fn harvest(e: Env, from: Address) -> Result<(), StrategyError> { check_initialized(&e)?; extend_instance_ttl(&e); - + let yield_balance = update_yield_balance(&e, &from); if yield_balance == 0 { return Ok(()); } - + // Transfer the reward tokens to the user's balance spend_yield(&e, from.clone(), yield_balance)?; receive_balance(&e, from.clone(), yield_balance); event::emit_harvest(&e, String::from_str(&e, STRATEGY_NAME), yield_balance, from); - + Ok(()) } - fn withdraw( - e: Env, - amount: i128, - from: Address, - to: Address, - ) -> Result { + fn withdraw(e: Env, amount: i128, from: Address, to: Address) -> Result { from.require_auth(); check_initialized(&e)?; check_nonnegative_amount(amount)?; extend_instance_ttl(&e); spend_balance(&e, from.clone(), amount)?; - + let contract_address = e.current_contract_address(); let underlying_asset = get_underlying_asset(&e); TokenClient::new(&e, &underlying_asset).transfer(&contract_address, &to, &amount); - event::emit_withdraw(&e, String::from_str(&e, STRATEGY_NAME), amount, from.clone()); + event::emit_withdraw( + &e, + String::from_str(&e, STRATEGY_NAME), + amount, + from.clone(), + ); Ok(read_balance(&e, from)) } - fn balance( - e: Env, - from: Address, - ) -> Result { + fn balance(e: Env, from: Address) -> Result { check_initialized(&e)?; extend_instance_ttl(&e); Ok(read_balance(&e, from)) } } - fn calculate_yield(user_balance: i128, apr: u32, time_elapsed: u64) -> i128 { // Calculate yield based on the APR, time elapsed, and user's balance let seconds_per_year = SECONDS_PER_YEAR; @@ -165,4 +162,4 @@ fn update_yield_balance(e: &Env, from: &Address) -> i128 { read_yield(e, from.clone()) } -mod test; \ No newline at end of file +mod test; diff --git a/apps/contracts/strategies/fixed_apr/src/storage.rs b/apps/contracts/strategies/fixed_apr/src/storage.rs index 3df9aec5..f43bca4b 100644 --- a/apps/contracts/strategies/fixed_apr/src/storage.rs +++ b/apps/contracts/strategies/fixed_apr/src/storage.rs @@ -31,11 +31,16 @@ pub fn is_initialized(e: &Env) -> bool { // Underlying asset pub fn set_underlying_asset(e: &Env, address: &Address) { - e.storage().instance().set(&DataKey::UnderlyingAsset, &address); + e.storage() + .instance() + .set(&DataKey::UnderlyingAsset, &address); } pub fn get_underlying_asset(e: &Env) -> Address { - e.storage().instance().get(&DataKey::UnderlyingAsset).unwrap() + e.storage() + .instance() + .get(&DataKey::UnderlyingAsset) + .unwrap() } // Apr @@ -49,9 +54,14 @@ pub fn get_apr(e: &Env) -> u32 { // Last harvest time pub fn set_last_harvest_time(e: &Env, timestamp: u64, from: Address) { - e.storage().instance().set(&DataKey::LastHarvestTime(from), ×tamp); + e.storage() + .instance() + .set(&DataKey::LastHarvestTime(from), ×tamp); } pub fn get_last_harvest_time(e: &Env, from: Address) -> u64 { - e.storage().instance().get(&DataKey::LastHarvestTime(from)).unwrap_or(0) -} \ No newline at end of file + e.storage() + .instance() + .get(&DataKey::LastHarvestTime(from)) + .unwrap_or(0) +} diff --git a/apps/contracts/strategies/fixed_apr/src/test.rs b/apps/contracts/strategies/fixed_apr/src/test.rs index a4982da9..4a162f79 100644 --- a/apps/contracts/strategies/fixed_apr/src/test.rs +++ b/apps/contracts/strategies/fixed_apr/src/test.rs @@ -4,23 +4,23 @@ use crate::{FixAprStrategy, FixAprStrategyClient, StrategyError}; use soroban_sdk::token::{StellarAssetClient, TokenClient}; +use soroban_sdk::{testutils::Address as _, Address, Env, IntoVal}; use soroban_sdk::{vec, Val, Vec}; -use soroban_sdk::{ - Env, - Address, - testutils::Address as _, - IntoVal, -}; use std::vec as stdvec; // Base Strategy Contract -pub fn create_fixapr_strategy<'a>(e: &Env, asset: &Address, apr_bps: u32, token: &Address) -> FixAprStrategyClient<'a> { - let init_args: Vec= vec![e, apr_bps.into_val(e)]; +pub fn create_fixapr_strategy<'a>( + e: &Env, + asset: &Address, + apr_bps: u32, + token: &Address, +) -> FixAprStrategyClient<'a> { + let init_args: Vec = vec![e, apr_bps.into_val(e)]; let args = (asset, init_args); let client = FixAprStrategyClient::new(e, &e.register(FixAprStrategy, args)); - + // Mint 100M to the strategy let starting_amount = 100_000_000_000_0_000_000i128; StellarAssetClient::new(e, token).mint(&client.address, &starting_amount); @@ -30,7 +30,11 @@ pub fn create_fixapr_strategy<'a>(e: &Env, asset: &Address, apr_bps: u32, token: // Create Test Token pub(crate) fn create_token_contract<'a>(e: &Env, admin: &Address) -> TokenClient<'a> { - TokenClient::new(e, &e.register_stellar_asset_contract_v2(admin.clone()).address()) + TokenClient::new( + e, + &e.register_stellar_asset_contract_v2(admin.clone()) + .address(), + ) } pub struct FixAprStrategyTest<'a> { @@ -40,19 +44,15 @@ pub struct FixAprStrategyTest<'a> { impl<'a> FixAprStrategyTest<'a> { fn setup() -> Self { - let env = Env::default(); env.mock_all_auths(); let admin = Address::generate(&env); let token = create_token_contract(&env, &admin); - FixAprStrategyTest { - env, - token, - } + FixAprStrategyTest { env, token } } - + pub(crate) fn generate_random_users(e: &Env, users_count: u32) -> stdvec::Vec
{ let mut users = stdvec![]; for _c in 0..users_count { @@ -62,4 +62,4 @@ impl<'a> FixAprStrategyTest<'a> { } } -mod fixed_apr; \ No newline at end of file +mod fixed_apr; diff --git a/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/deposit.rs b/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/deposit.rs index 6903df0e..114d0a7c 100644 --- a/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/deposit.rs +++ b/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/deposit.rs @@ -8,7 +8,8 @@ use soroban_sdk::token::StellarAssetClient; fn deposit_with_negative_amount() { let test = FixAprStrategyTest::setup(); - let strategy = create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); + let strategy = + create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); let users = FixAprStrategyTest::generate_random_users(&test.env, 1); @@ -23,7 +24,8 @@ fn deposit_with_negative_amount() { fn deposit_with_zero_amount() { let test = FixAprStrategyTest::setup(); - let strategy = create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); + let strategy = + create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); let users = FixAprStrategyTest::generate_random_users(&test.env, 1); @@ -36,8 +38,9 @@ fn deposit_with_zero_amount() { #[test] fn deposit() { let test = FixAprStrategyTest::setup(); - - let strategy = create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); + + let strategy = + create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); let users = FixAprStrategyTest::generate_random_users(&test.env, 1); @@ -55,12 +58,14 @@ fn deposit() { fn deposit_with_exceeding_balance() { let test = FixAprStrategyTest::setup(); - let strategy = create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); + let strategy = + create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); let users = FixAprStrategyTest::generate_random_users(&test.env, 1); let amount = 1_000_0_00_000; - StellarAssetClient::new(&test.env, &test.token.address).mint(&users[0], &(&amount - 100_0_000_000)); + StellarAssetClient::new(&test.env, &test.token.address) + .mint(&users[0], &(&amount - 100_0_000_000)); strategy.deposit(&amount, &users[0]); } diff --git a/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/harvest.rs b/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/harvest.rs index 9ca104af..8279d88b 100644 --- a/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/harvest.rs +++ b/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/harvest.rs @@ -1,13 +1,17 @@ use soroban_sdk::{testutils::Ledger, token::StellarAssetClient}; -use crate::{calculate_yield, test::{create_fixapr_strategy, FixAprStrategyTest}}; +use crate::{ + calculate_yield, + test::{create_fixapr_strategy, FixAprStrategyTest}, +}; #[test] fn test_harvest_yields_multiple_users() { let test = FixAprStrategyTest::setup(); let apr = 1000u32; - let strategy = create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); + let strategy = + create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); let users = FixAprStrategyTest::generate_random_users(&test.env, 4); @@ -40,7 +44,9 @@ fn test_harvest_yields_multiple_users() { // Simulate one year passing let one_year_in_seconds = 31_536_000u64; - test.env.ledger().set_timestamp(test.env.ledger().timestamp() + one_year_in_seconds); + test.env + .ledger() + .set_timestamp(test.env.ledger().timestamp() + one_year_in_seconds); // Harvest for each user strategy.harvest(&users[0]); @@ -54,8 +60,20 @@ fn test_harvest_yields_multiple_users() { let user3_expected_reward = calculate_yield(user3_amount, apr, one_year_in_seconds); let user4_expected_reward = calculate_yield(user4_amount, apr, one_year_in_seconds); - assert_eq!(strategy.balance(&users[0]), user1_amount + user1_expected_reward); - assert_eq!(strategy.balance(&users[1]), user2_amount + user2_expected_reward); - assert_eq!(strategy.balance(&users[2]), user3_amount + user3_expected_reward); - assert_eq!(strategy.balance(&users[3]), user4_amount + user4_expected_reward); -} \ No newline at end of file + assert_eq!( + strategy.balance(&users[0]), + user1_amount + user1_expected_reward + ); + assert_eq!( + strategy.balance(&users[1]), + user2_amount + user2_expected_reward + ); + assert_eq!( + strategy.balance(&users[2]), + user3_amount + user3_expected_reward + ); + assert_eq!( + strategy.balance(&users[3]), + user4_amount + user4_expected_reward + ); +} diff --git a/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/initialize.rs b/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/initialize.rs index 6e12d63b..b2d87964 100644 --- a/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/initialize.rs +++ b/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/initialize.rs @@ -6,9 +6,10 @@ use crate::test::{create_fixapr_strategy, FixAprStrategyTest}; fn check_storage() { let test = FixAprStrategyTest::setup(); - let strategy = create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); + let strategy = + create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); // get asset should return underlying asset let underlying_asset = strategy.asset(); assert_eq!(underlying_asset, test.token.address); -} \ No newline at end of file +} diff --git a/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/mod.rs b/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/mod.rs index 8bf6f532..402f7748 100644 --- a/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/mod.rs +++ b/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/mod.rs @@ -1,4 +1,4 @@ mod deposit; mod harvest; mod initialize; -mod withdraw; \ No newline at end of file +mod withdraw; diff --git a/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/withdraw.rs b/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/withdraw.rs index b549d829..9202d151 100644 --- a/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/withdraw.rs +++ b/apps/contracts/strategies/fixed_apr/src/test/fixed_apr/withdraw.rs @@ -8,7 +8,8 @@ use soroban_sdk::token::StellarAssetClient; fn withdraw() { let test = FixAprStrategyTest::setup(); - let strategy = create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); + let strategy = + create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); let users = FixAprStrategyTest::generate_random_users(&test.env, 1); @@ -28,7 +29,8 @@ fn withdraw() { fn withdraw_with_harvest() { let test = FixAprStrategyTest::setup(); - let strategy = create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); + let strategy = + create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); let users = FixAprStrategyTest::generate_random_users(&test.env, 1); @@ -41,7 +43,9 @@ fn withdraw_with_harvest() { // Simulate one year passing let one_year_in_seconds = 31_536_000u64; - test.env.ledger().set_timestamp(test.env.ledger().timestamp() + one_year_in_seconds); + test.env + .ledger() + .set_timestamp(test.env.ledger().timestamp() + one_year_in_seconds); strategy.harvest(&users[0]); @@ -58,7 +62,8 @@ fn withdraw_with_harvest() { fn withdraw_then_harvest_then_withdraw_again() { let test = FixAprStrategyTest::setup(); - let strategy = create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); + let strategy = + create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); let users = FixAprStrategyTest::generate_random_users(&test.env, 1); @@ -68,11 +73,13 @@ fn withdraw_then_harvest_then_withdraw_again() { strategy.deposit(&amount, &users[0]); let user_balance = test.token.balance(&users[0]); assert_eq!(user_balance, 0); - + // Simulate one year passing let one_year_in_seconds = 31_536_000u64; - test.env.ledger().set_timestamp(test.env.ledger().timestamp() + one_year_in_seconds); - + test.env + .ledger() + .set_timestamp(test.env.ledger().timestamp() + one_year_in_seconds); + let user_balance_before_harvest = strategy.balance(&users[0]); assert_eq!(user_balance_before_harvest, amount); @@ -95,7 +102,8 @@ fn withdraw_then_harvest_then_withdraw_again() { fn withdraw_with_no_balance() { let test = FixAprStrategyTest::setup(); - let strategy = create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); + let strategy = + create_fixapr_strategy(&test.env, &test.token.address, 1000u32, &test.token.address); let users = FixAprStrategyTest::generate_random_users(&test.env, 1); @@ -103,4 +111,4 @@ fn withdraw_with_no_balance() { let result = strategy.try_withdraw(&amount, &users[0], &users[0]); assert_eq!(result, Err(Ok(StrategyError::InsufficientBalance))); -} \ No newline at end of file +} diff --git a/apps/contracts/strategies/fixed_apr/src/yield_balance.rs b/apps/contracts/strategies/fixed_apr/src/yield_balance.rs index bf60f929..3f74b5b5 100644 --- a/apps/contracts/strategies/fixed_apr/src/yield_balance.rs +++ b/apps/contracts/strategies/fixed_apr/src/yield_balance.rs @@ -6,9 +6,11 @@ use crate::StrategyError; pub fn read_yield(e: &Env, addr: Address) -> i128 { let key = DataKey::YieldBalance(addr); if let Some(balance) = e.storage().persistent().get::(&key) { - e.storage() - .persistent() - .extend_ttl(&key, INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + e.storage().persistent().extend_ttl( + &key, + INSTANCE_LIFETIME_THRESHOLD, + INSTANCE_BUMP_AMOUNT, + ); balance } else { 0 @@ -26,14 +28,14 @@ fn write_yield(e: &Env, addr: Address, amount: i128) { pub fn receive_yield(e: &Env, addr: Address, amount: i128) { let balance = read_yield(e, addr.clone()); - let new_balance = balance.checked_add(amount) + let new_balance = balance + .checked_add(amount) .expect("Integer overflow occurred while adding balance."); write_yield(e, addr, new_balance); } pub fn spend_yield(e: &Env, addr: Address, amount: i128) -> Result<(), StrategyError> { - let balance = read_yield(e, addr.clone()); if balance < amount { return Err(StrategyError::InsufficientBalance); diff --git a/apps/contracts/strategies/hodl/src/balance.rs b/apps/contracts/strategies/hodl/src/balance.rs index 1f5751be..39fa6574 100644 --- a/apps/contracts/strategies/hodl/src/balance.rs +++ b/apps/contracts/strategies/hodl/src/balance.rs @@ -6,9 +6,11 @@ use crate::StrategyError; pub fn read_balance(e: &Env, addr: Address) -> i128 { let key = DataKey::Balance(addr); if let Some(balance) = e.storage().persistent().get::(&key) { - e.storage() - .persistent() - .extend_ttl(&key, INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + e.storage().persistent().extend_ttl( + &key, + INSTANCE_LIFETIME_THRESHOLD, + INSTANCE_BUMP_AMOUNT, + ); balance } else { 0 @@ -26,14 +28,14 @@ fn write_balance(e: &Env, addr: Address, amount: i128) { pub fn receive_balance(e: &Env, addr: Address, amount: i128) { let balance = read_balance(e, addr.clone()); - let new_balance = balance.checked_add(amount) + let new_balance = balance + .checked_add(amount) .expect("Integer overflow occurred while adding balance."); write_balance(e, addr, new_balance); } pub fn spend_balance(e: &Env, addr: Address, amount: i128) -> Result<(), StrategyError> { - let balance = read_balance(e, addr.clone()); if balance < amount { return Err(StrategyError::InsufficientBalance); diff --git a/apps/contracts/strategies/hodl/src/lib.rs b/apps/contracts/strategies/hodl/src/lib.rs index 06b184ee..17bfd35d 100644 --- a/apps/contracts/strategies/hodl/src/lib.rs +++ b/apps/contracts/strategies/hodl/src/lib.rs @@ -1,32 +1,16 @@ #![no_std] use soroban_sdk::{ - contract, - contractimpl, - Address, - Env, - String, - token::Client as TokenClient, - Val, - Vec}; + contract, contractimpl, token::Client as TokenClient, Address, Env, String, Val, Vec, +}; mod balance; mod storage; -use balance::{ - read_balance, - receive_balance, - spend_balance}; +use balance::{read_balance, receive_balance, spend_balance}; -use storage::{ - extend_instance_ttl, - get_underlying_asset, - set_underlying_asset -}; +use storage::{extend_instance_ttl, get_underlying_asset, set_underlying_asset}; -pub use defindex_strategy_core::{ - DeFindexStrategyTrait, - StrategyError, - event}; +pub use defindex_strategy_core::{event, DeFindexStrategyTrait, StrategyError}; pub fn check_nonnegative_amount(amount: i128) -> Result<(), StrategyError> { if amount < 0 { @@ -43,11 +27,7 @@ struct HodlStrategy; #[contractimpl] impl DeFindexStrategyTrait for HodlStrategy { - fn __constructor( - e: Env, - asset: Address, - _init_args: Vec, - ) { + fn __constructor(e: Env, asset: Address, _init_args: Vec) { set_underlying_asset(&e, &asset); } @@ -57,22 +37,23 @@ impl DeFindexStrategyTrait for HodlStrategy { Ok(get_underlying_asset(&e)) } - fn deposit( - e: Env, - amount: i128, - from: Address, - ) -> Result { + fn deposit(e: Env, amount: i128, from: Address) -> Result { check_nonnegative_amount(amount)?; extend_instance_ttl(&e); from.require_auth(); let contract_address = e.current_contract_address(); - + let underlying_asset = get_underlying_asset(&e); TokenClient::new(&e, &underlying_asset).transfer(&from, &contract_address, &amount); receive_balance(&e, from.clone(), amount); - event::emit_deposit(&e, String::from_str(&e, STARETEGY_NAME), amount, from.clone()); + event::emit_deposit( + &e, + String::from_str(&e, STARETEGY_NAME), + amount, + from.clone(), + ); Ok(read_balance(&e, from)) } @@ -84,34 +65,31 @@ impl DeFindexStrategyTrait for HodlStrategy { Ok(()) } - fn withdraw( - e: Env, - amount: i128, - from: Address, - to: Address, - ) -> Result { + fn withdraw(e: Env, amount: i128, from: Address, to: Address) -> Result { from.require_auth(); check_nonnegative_amount(amount)?; extend_instance_ttl(&e); spend_balance(&e, from.clone(), amount)?; - + let contract_address = e.current_contract_address(); let underlying_asset = get_underlying_asset(&e); TokenClient::new(&e, &underlying_asset).transfer(&contract_address, &to, &amount); - event::emit_withdraw(&e, String::from_str(&e, STARETEGY_NAME), amount, from.clone()); + event::emit_withdraw( + &e, + String::from_str(&e, STARETEGY_NAME), + amount, + from.clone(), + ); Ok(read_balance(&e, from)) } - fn balance( - e: Env, - from: Address, - ) -> Result { + fn balance(e: Env, from: Address) -> Result { extend_instance_ttl(&e); Ok(read_balance(&e, from)) } } -mod test; \ No newline at end of file +mod test; diff --git a/apps/contracts/strategies/hodl/src/storage.rs b/apps/contracts/strategies/hodl/src/storage.rs index 362f34c3..e807dcf8 100644 --- a/apps/contracts/strategies/hodl/src/storage.rs +++ b/apps/contracts/strategies/hodl/src/storage.rs @@ -1,11 +1,11 @@ -use soroban_sdk::{contracttype, Env, Address}; +use soroban_sdk::{contracttype, Address, Env}; #[derive(Clone)] #[contracttype] pub enum DataKey { UnderlyingAsset, - Balance(Address) + Balance(Address), } const DAY_IN_LEDGERS: u32 = 17280; @@ -20,9 +20,14 @@ pub fn extend_instance_ttl(e: &Env) { // Underlying asset pub fn set_underlying_asset(e: &Env, address: &Address) { - e.storage().instance().set(&DataKey::UnderlyingAsset, &address); + e.storage() + .instance() + .set(&DataKey::UnderlyingAsset, &address); } pub fn get_underlying_asset(e: &Env) -> Address { - e.storage().instance().get(&DataKey::UnderlyingAsset).unwrap() -} \ No newline at end of file + e.storage() + .instance() + .get(&DataKey::UnderlyingAsset) + .unwrap() +} diff --git a/apps/contracts/strategies/hodl/src/test.rs b/apps/contracts/strategies/hodl/src/test.rs index 3a590e07..d4705d71 100644 --- a/apps/contracts/strategies/hodl/src/test.rs +++ b/apps/contracts/strategies/hodl/src/test.rs @@ -1,18 +1,14 @@ #![cfg(test)] use crate::{HodlStrategy, HodlStrategyClient, StrategyError}; -use soroban_sdk::token::{TokenClient, StellarAssetClient}; +use soroban_sdk::token::{StellarAssetClient, TokenClient}; +use soroban_sdk::{testutils::Address as _, Address, Env}; use soroban_sdk::{vec, Val, Vec}; -use soroban_sdk::{ - Env, - Address, - testutils::Address as _, -}; // Base Strategy Contract pub fn create_hodl_strategy<'a>(e: &Env, asset: &Address) -> HodlStrategyClient<'a> { - let init_args: Vec= vec![e]; + let init_args: Vec = vec![e]; let args = (asset, init_args); HodlStrategyClient::new(e, &e.register(HodlStrategy, args)) @@ -20,7 +16,11 @@ pub fn create_hodl_strategy<'a>(e: &Env, asset: &Address) -> HodlStrategyClient< // Create Test Token pub(crate) fn create_token_contract<'a>(e: &Env, admin: &Address) -> TokenClient<'a> { - TokenClient::new(e, &e.register_stellar_asset_contract_v2(admin.clone()).address()) + TokenClient::new( + e, + &e.register_stellar_asset_contract_v2(admin.clone()) + .address(), + ) } pub struct HodlStrategyTest<'a> { @@ -32,7 +32,6 @@ pub struct HodlStrategyTest<'a> { impl<'a> HodlStrategyTest<'a> { fn setup() -> Self { - let env = Env::default(); env.mock_all_auths(); @@ -53,7 +52,7 @@ impl<'a> HodlStrategyTest<'a> { user1, } } - + // pub(crate) fn generate_random_users(e: &Env, users_count: u32) -> vec::Vec
{ // let mut users = vec![]; // for _c in 0..users_count { @@ -63,4 +62,4 @@ impl<'a> HodlStrategyTest<'a> { // } } -mod hodl; \ No newline at end of file +mod hodl; diff --git a/apps/contracts/strategies/hodl/src/test/hodl/deposit.rs b/apps/contracts/strategies/hodl/src/test/hodl/deposit.rs index 7b8ddfc6..5fb86990 100644 --- a/apps/contracts/strategies/hodl/src/test/hodl/deposit.rs +++ b/apps/contracts/strategies/hodl/src/test/hodl/deposit.rs @@ -47,7 +47,6 @@ fn deposit_and_withdrawal_flow() { let user_balance_on_strategy = strategy.balance(&test.user); assert_eq!(user_balance_on_strategy, amount); - let amount_to_withdraw = 100_000; // Withdrawing token from the strategy to user strategy.withdraw(&amount_to_withdraw, &test.user, &test.user); @@ -68,7 +67,6 @@ fn deposit_and_withdrawal_flow() { let amount_to_withdraw = 200_000; let result = strategy.try_withdraw(&amount_to_withdraw, &test.user, &test.user); assert_eq!(result, Err(Ok(StrategyError::InsufficientBalance))); - } #[test] @@ -95,9 +93,8 @@ fn deposit_from_a_withdrawal_from_b() { let user_balance_on_strategy = strategy.balance(&test.user); assert_eq!(user_balance_on_strategy, amount); - let amount_to_withdraw = 100_000; // Withdrawing token from the strategy to user let result = strategy.try_withdraw(&amount_to_withdraw, &test.user1, &test.user1); assert_eq!(result, Err(Ok(StrategyError::InsufficientBalance))); -} \ No newline at end of file +} diff --git a/apps/contracts/strategies/hodl/src/test/hodl/events.rs b/apps/contracts/strategies/hodl/src/test/hodl/events.rs index db0ab5aa..b00070fd 100644 --- a/apps/contracts/strategies/hodl/src/test/hodl/events.rs +++ b/apps/contracts/strategies/hodl/src/test/hodl/events.rs @@ -1,7 +1,6 @@ - -use soroban_sdk::{symbol_short, testutils::Events, vec, IntoVal}; -use crate::test::{create_hodl_strategy, HodlStrategyTest}; use crate::event::{DepositEvent, HarvestEvent, WithdrawEvent}; +use crate::test::{create_hodl_strategy, HodlStrategyTest}; +use soroban_sdk::{symbol_short, testutils::Events, vec, IntoVal}; #[test] fn deposit() { @@ -20,7 +19,7 @@ fn deposit() { assert_eq!( vec![&test.env, deposit_event.clone()], vec![ - &test.env, + &test.env, ( strategy.address.clone(), ("HodlStrategy", symbol_short!("deposit")).into_val(&test.env), @@ -48,7 +47,7 @@ fn withdraw() { assert_eq!( vec![&test.env, withdraw_event.clone()], vec![ - &test.env, + &test.env, ( strategy.address.clone(), ("HodlStrategy", symbol_short!("withdraw")).into_val(&test.env), @@ -56,13 +55,10 @@ fn withdraw() { ) ] ); - - - } #[test] -fn harvest(){ +fn harvest() { let test = HodlStrategyTest::setup(); let strategy = create_hodl_strategy(&test.env, &test.token.address); @@ -79,7 +75,7 @@ fn harvest(){ assert_eq!( vec![&test.env, harvest_event.clone()], vec![ - &test.env, + &test.env, ( strategy.address.clone(), ("HodlStrategy", symbol_short!("harvest")).into_val(&test.env), @@ -87,4 +83,4 @@ fn harvest(){ ) ] ); -} \ No newline at end of file +} diff --git a/apps/contracts/strategies/hodl/src/test/hodl/mod.rs b/apps/contracts/strategies/hodl/src/test/hodl/mod.rs index 6fb18b06..b2d95126 100644 --- a/apps/contracts/strategies/hodl/src/test/hodl/mod.rs +++ b/apps/contracts/strategies/hodl/src/test/hodl/mod.rs @@ -1,3 +1,3 @@ mod deposit; mod events; -mod withdraw; \ No newline at end of file +mod withdraw; diff --git a/apps/contracts/strategies/hodl/src/test/hodl/withdraw.rs b/apps/contracts/strategies/hodl/src/test/hodl/withdraw.rs index 973e3f35..67a2c51b 100644 --- a/apps/contracts/strategies/hodl/src/test/hodl/withdraw.rs +++ b/apps/contracts/strategies/hodl/src/test/hodl/withdraw.rs @@ -30,7 +30,6 @@ fn withdraw() { let user_balance_on_strategy = strategy.balance(&test.user); assert_eq!(user_balance_on_strategy, amount); - let amount_to_withdraw = 100_000; // Withdrawing token from the strategy to user strategy.withdraw(&amount_to_withdraw, &test.user, &test.user); @@ -51,5 +50,4 @@ fn withdraw() { let amount_to_withdraw = user_balance + 1; let result = strategy.try_withdraw(&amount_to_withdraw, &test.user, &test.user); assert_eq!(result, Err(Ok(StrategyError::InsufficientBalance))); - } diff --git a/apps/contracts/strategies/soroswap/src/lib.rs b/apps/contracts/strategies/soroswap/src/lib.rs index 2c883b45..0c9bfd7f 100644 --- a/apps/contracts/strategies/soroswap/src/lib.rs +++ b/apps/contracts/strategies/soroswap/src/lib.rs @@ -1,17 +1,20 @@ #![no_std] use soroban_sdk::{ - auth::{ContractContext, InvokerContractAuthEntry, SubContractInvocation}, contract, contractimpl, vec, Address, Env, IntoVal, String, Symbol, Val, Vec}; + auth::{ContractContext, InvokerContractAuthEntry, SubContractInvocation}, + contract, contractimpl, vec, Address, Env, IntoVal, String, Symbol, Val, Vec, +}; -mod storage; -mod soroswap_router; mod soroswap_pair; +mod soroswap_router; +mod storage; +use defindex_strategy_core::{DeFindexStrategyTrait, StrategyError}; +use soroswap_pair::SoroswapPairClient; +use soroswap_router::SoroswapRouterClient; use storage::{ - extend_instance_ttl, get_soroswap_router_address, has_soroswap_router_address, set_soroswap_router_address + extend_instance_ttl, get_soroswap_router_address, has_soroswap_router_address, + set_soroswap_router_address, }; -use soroswap_router::SoroswapRouterClient; -use soroswap_pair::SoroswapPairClient; -use defindex_strategy_core::{DeFindexStrategyTrait, StrategyError}; pub fn check_nonnegative_amount(amount: i128) -> Result<(), StrategyError> { if amount < 0 { @@ -34,13 +37,13 @@ struct SoroswapAdapter; #[contractimpl] impl DeFindexStrategyTrait for SoroswapAdapter { - fn __constructor( - e: Env, - _asset: Address, - init_args: Vec, - ) { - let protocol_address = init_args.get(0).ok_or(StrategyError::InvalidArgument).unwrap().into_val(&e); - + fn __constructor(e: Env, _asset: Address, init_args: Vec) { + let protocol_address = init_args + .get(0) + .ok_or(StrategyError::InvalidArgument) + .unwrap() + .into_val(&e); + set_soroswap_router_address(&e, protocol_address); } @@ -52,11 +55,7 @@ impl DeFindexStrategyTrait for SoroswapAdapter { Ok(protocol_address) } - fn deposit( - e: Env, - amount: i128, - from: Address, - ) -> Result { + fn deposit(e: Env, amount: i128, from: Address) -> Result { from.require_auth(); check_initialized(&e)?; check_nonnegative_amount(amount)?; @@ -64,15 +63,24 @@ impl DeFindexStrategyTrait for SoroswapAdapter { // let usdc_address = Address::from_string(&String::from_str(&e, "CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75")); // let xlm_address = Address::from_string(&String::from_str(&e, "CAS3J7GYLGXMF6TDJBBYYSE3HQ6BBSMLNUQ34T6TZMYMW2EVH34XOWMA")); - let usdc_address = Address::from_string(&String::from_str(&e, "CCKW6SMINDG6TUWJROIZ535EW2ZUJQEDGSKNIK3FBK26PAMBZDVK2BZA")); - let xlm_address = Address::from_string(&String::from_str(&e, "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC")); - + let usdc_address = Address::from_string(&String::from_str( + &e, + "CCKW6SMINDG6TUWJROIZ535EW2ZUJQEDGSKNIK3FBK26PAMBZDVK2BZA", + )); + let xlm_address = Address::from_string(&String::from_str( + &e, + "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC", + )); + // Setting up Soroswap router client let soroswap_router_address = get_soroswap_router_address(&e); let soroswap_router_client = SoroswapRouterClient::new(&e, &soroswap_router_address); - + // let pair_address = Address::from_string(&String::from_str(&e, "CAM7DY53G63XA4AJRS24Z6VFYAFSSF76C3RZ45BE5YU3FQS5255OOABP")); - let pair_address = Address::from_string(&String::from_str(&e, "CAAXGP7LTPV4A57LSKDWTSPPJUGFGNU34KQ3FYIPYUUP2SLFGVMTYKYU")); + let pair_address = Address::from_string(&String::from_str( + &e, + "CAAXGP7LTPV4A57LSKDWTSPPJUGFGNU34KQ3FYIPYUUP2SLFGVMTYKYU", + )); // let pair_address = soroswap_router_client.router_pair_for(&usdc_address, &xlm_address); let swap_amount = amount.checked_div(2).unwrap(); @@ -88,14 +96,14 @@ impl DeFindexStrategyTrait for SoroswapAdapter { e.authorize_as_current_contract(vec![ &e, - InvokerContractAuthEntry::Contract( SubContractInvocation { + InvokerContractAuthEntry::Contract(SubContractInvocation { context: ContractContext { contract: usdc_address.clone(), fn_name: Symbol::new(&e, "transfer"), args: swap_args.clone(), }, - sub_invocations: vec![&e] - }) + sub_invocations: vec![&e], + }), ]); let swap_result = soroswap_router_client.swap_exact_tokens_for_tokens( @@ -130,28 +138,32 @@ impl DeFindexStrategyTrait for SoroswapAdapter { Ok(()) } - fn withdraw( - e: Env, - _amount: i128, - from: Address, - _to: Address, - ) -> Result { + fn withdraw(e: Env, _amount: i128, from: Address, _to: Address) -> Result { from.require_auth(); check_initialized(&e)?; extend_instance_ttl(&e); // let usdc_address = Address::from_string(&String::from_str(&e, "CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75")); // let xlm_address = Address::from_string(&String::from_str(&e, "CAS3J7GYLGXMF6TDJBBYYSE3HQ6BBSMLNUQ34T6TZMYMW2EVH34XOWMA")); - let usdc_address = Address::from_string(&String::from_str(&e, "CCKW6SMINDG6TUWJROIZ535EW2ZUJQEDGSKNIK3FBK26PAMBZDVK2BZA")); - let xlm_address = Address::from_string(&String::from_str(&e, "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC")); - + let usdc_address = Address::from_string(&String::from_str( + &e, + "CCKW6SMINDG6TUWJROIZ535EW2ZUJQEDGSKNIK3FBK26PAMBZDVK2BZA", + )); + let xlm_address = Address::from_string(&String::from_str( + &e, + "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC", + )); + // Setting up Soroswap router client let soroswap_router_address = get_soroswap_router_address(&e); let soroswap_router_client = SoroswapRouterClient::new(&e, &soroswap_router_address); - + // let pair_address = Address::from_string(&String::from_str(&e, "CAM7DY53G63XA4AJRS24Z6VFYAFSSF76C3RZ45BE5YU3FQS5255OOABP")); - let pair_address = Address::from_string(&String::from_str(&e, "CAAXGP7LTPV4A57LSKDWTSPPJUGFGNU34KQ3FYIPYUUP2SLFGVMTYKYU")); - + let pair_address = Address::from_string(&String::from_str( + &e, + "CAAXGP7LTPV4A57LSKDWTSPPJUGFGNU34KQ3FYIPYUUP2SLFGVMTYKYU", + )); + let soroswap_pair_client = SoroswapPairClient::new(&e, &pair_address); let lp_balance = soroswap_pair_client.balance(&from); @@ -162,14 +174,14 @@ impl DeFindexStrategyTrait for SoroswapAdapter { e.authorize_as_current_contract(vec![ &e, - InvokerContractAuthEntry::Contract( SubContractInvocation { + InvokerContractAuthEntry::Contract(SubContractInvocation { context: ContractContext { contract: pair_address.clone(), fn_name: Symbol::new(&e, "transfer"), args: swap_args.clone(), }, - sub_invocations: vec![&e] - }) + sub_invocations: vec![&e], + }), ]); // Remove liquidity @@ -200,51 +212,51 @@ impl DeFindexStrategyTrait for SoroswapAdapter { Ok(total_swapped_amount) } - fn balance( - e: Env, - from: Address, - ) -> Result { + fn balance(e: Env, from: Address) -> Result { // Constants const SCALE: i128 = 10_000_000; // A scaling factor to maintain precision within 7 decimals - + // Should get pair reserves // let pair_address = Address::from_string(&String::from_str(&e, "CAM7DY53G63XA4AJRS24Z6VFYAFSSF76C3RZ45BE5YU3FQS5255OOABP")); - let pair_address = Address::from_string(&String::from_str(&e, "CAAXGP7LTPV4A57LSKDWTSPPJUGFGNU34KQ3FYIPYUUP2SLFGVMTYKYU")); + let pair_address = Address::from_string(&String::from_str( + &e, + "CAAXGP7LTPV4A57LSKDWTSPPJUGFGNU34KQ3FYIPYUUP2SLFGVMTYKYU", + )); let soroswap_pair_client = SoroswapPairClient::new(&e, &pair_address); - + // Get the reserves from the pair let (reserve_usdc, reserve_xlm) = soroswap_pair_client.get_reserves(); - + // Get the total supply of LP tokens and the user's LP token balance let total_lp_tokens = soroswap_pair_client.total_supply(); let user_lp_tokens = soroswap_pair_client.balance(&from); - + // Ensure no division by zero if total_lp_tokens == 0 { return Err(StrategyError::NegativeNotAllowed); } - + // Calculate the user's share of the pool as a scaled integer let user_share = (user_lp_tokens as i128 * SCALE) / total_lp_tokens as i128; - + // Calculate the user's share of each reserve let user_usdc_share = (reserve_usdc as i128 * user_share) / SCALE; let user_xlm_share = (reserve_xlm as i128 * user_share) / SCALE; - + // Ensure no division by zero in price calculation if reserve_xlm == 0 { return Err(StrategyError::NegativeNotAllowed); } - + // Calculate the price of XLM in USDC as a scaled integer let xlm_price_in_usdc = (reserve_usdc as i128 * SCALE) / reserve_xlm as i128; - + // Convert the user's XLM share to USDC let user_xlm_in_usdc = (user_xlm_share * xlm_price_in_usdc) / SCALE; - + // Calculate the total USDC value let total_usdc_value = user_usdc_share + user_xlm_in_usdc; - + Ok(total_usdc_value) } } diff --git a/apps/contracts/strategies/soroswap/src/soroswap_pair.rs b/apps/contracts/strategies/soroswap/src/soroswap_pair.rs index a89a797e..4455b9ac 100644 --- a/apps/contracts/strategies/soroswap/src/soroswap_pair.rs +++ b/apps/contracts/strategies/soroswap/src/soroswap_pair.rs @@ -1,4 +1,2 @@ -soroban_sdk::contractimport!( - file = "../external_wasms/soroswap/soroswap_pair.optimized.wasm" -); -pub type SoroswapPairClient<'a> = Client<'a>; \ No newline at end of file +soroban_sdk::contractimport!(file = "../external_wasms/soroswap/soroswap_pair.optimized.wasm"); +pub type SoroswapPairClient<'a> = Client<'a>; diff --git a/apps/contracts/strategies/soroswap/src/soroswap_router.rs b/apps/contracts/strategies/soroswap/src/soroswap_router.rs index d2b3253a..27a2adaa 100644 --- a/apps/contracts/strategies/soroswap/src/soroswap_router.rs +++ b/apps/contracts/strategies/soroswap/src/soroswap_router.rs @@ -1,4 +1,2 @@ -soroban_sdk::contractimport!( - file = "../external_wasms/soroswap/soroswap_router.optimized.wasm" -); -pub type SoroswapRouterClient<'a> = Client<'a>; \ No newline at end of file +soroban_sdk::contractimport!(file = "../external_wasms/soroswap/soroswap_router.optimized.wasm"); +pub type SoroswapRouterClient<'a> = Client<'a>; diff --git a/apps/contracts/strategies/soroswap/src/storage.rs b/apps/contracts/strategies/soroswap/src/storage.rs index 7e954516..16674b61 100644 --- a/apps/contracts/strategies/soroswap/src/storage.rs +++ b/apps/contracts/strategies/soroswap/src/storage.rs @@ -1,4 +1,4 @@ -use soroban_sdk::{contracttype, Env, Address}; +use soroban_sdk::{contracttype, Address, Env}; #[derive(Clone)] #[contracttype] @@ -23,9 +23,14 @@ pub fn has_soroswap_router_address(e: &Env) -> bool { // Soroswap Router Address pub fn set_soroswap_router_address(e: &Env, address: Address) { - e.storage().instance().set(&DataKey::SoroswapRouterAddress, &address); + e.storage() + .instance() + .set(&DataKey::SoroswapRouterAddress, &address); } pub fn get_soroswap_router_address(e: &Env) -> Address { - e.storage().instance().get(&DataKey::SoroswapRouterAddress).unwrap() -} \ No newline at end of file + e.storage() + .instance() + .get(&DataKey::SoroswapRouterAddress) + .unwrap() +} diff --git a/apps/contracts/strategies/xycloans/src/lib.rs b/apps/contracts/strategies/xycloans/src/lib.rs index bdd005d1..f7c4f98b 100644 --- a/apps/contracts/strategies/xycloans/src/lib.rs +++ b/apps/contracts/strategies/xycloans/src/lib.rs @@ -1,16 +1,18 @@ #![no_std] -mod storage; mod soroswap_router; +mod storage; mod xycloans_pool; +use defindex_strategy_core::{DeFindexStrategyTrait, StrategyError}; use soroban_sdk::{contract, contractimpl, Address, Env, IntoVal, Val, Vec}; +use soroswap_router::{get_amount_out, get_reserves, swap}; use storage::{ - extend_instance_ttl, get_pool_token, get_token_in, get_xycloans_pool_address, set_soroswap_router_address, set_pool_token, set_token_in, set_xycloans_pool_address, set_soroswap_factory_address, get_soroswap_factory_address + extend_instance_ttl, get_pool_token, get_soroswap_factory_address, get_token_in, + get_xycloans_pool_address, set_pool_token, set_soroswap_factory_address, + set_soroswap_router_address, set_token_in, set_xycloans_pool_address, }; -use soroswap_router::{get_amount_out, get_reserves, swap}; use xycloans_pool::XycloansPoolClient; -use defindex_strategy_core::{StrategyError, DeFindexStrategyTrait}; pub fn check_nonnegative_amount(amount: i128) -> Result<(), StrategyError> { if amount < 0 { @@ -27,17 +29,33 @@ struct XycloansAdapter; #[contractimpl] impl DeFindexStrategyTrait for XycloansAdapter { - fn __constructor( - e: Env, - _asset: Address, - init_args: Vec, - ) { - let soroswap_router_address = init_args.get(0).ok_or(StrategyError::InvalidArgument).unwrap().into_val(&e); - let soroswap_factory_address = init_args.get(1).ok_or(StrategyError::InvalidArgument).unwrap().into_val(&e); - let xycloans_pool_address = init_args.get(2).ok_or(StrategyError::InvalidArgument).unwrap().into_val(&e); - let pool_token = init_args.get(3).ok_or(StrategyError::InvalidArgument).unwrap().into_val(&e); - let token_in = init_args.get(4).ok_or(StrategyError::InvalidArgument).unwrap().into_val(&e); - + fn __constructor(e: Env, _asset: Address, init_args: Vec) { + let soroswap_router_address = init_args + .get(0) + .ok_or(StrategyError::InvalidArgument) + .unwrap() + .into_val(&e); + let soroswap_factory_address = init_args + .get(1) + .ok_or(StrategyError::InvalidArgument) + .unwrap() + .into_val(&e); + let xycloans_pool_address = init_args + .get(2) + .ok_or(StrategyError::InvalidArgument) + .unwrap() + .into_val(&e); + let pool_token = init_args + .get(3) + .ok_or(StrategyError::InvalidArgument) + .unwrap() + .into_val(&e); + let token_in = init_args + .get(4) + .ok_or(StrategyError::InvalidArgument) + .unwrap() + .into_val(&e); + set_soroswap_router_address(&e, soroswap_router_address); set_soroswap_factory_address(&e, soroswap_factory_address); set_xycloans_pool_address(&e, xycloans_pool_address); @@ -51,11 +69,7 @@ impl DeFindexStrategyTrait for XycloansAdapter { Ok(get_token_in(&e)) } - fn deposit( - e: Env, - amount: i128, - from: Address, - ) -> Result { + fn deposit(e: Env, amount: i128, from: Address) -> Result { check_nonnegative_amount(amount)?; extend_instance_ttl(&e); from.require_auth(); @@ -79,18 +93,13 @@ impl DeFindexStrategyTrait for XycloansAdapter { Ok(()) } - fn withdraw( - e: Env, - _amount: i128, - from: Address, - _to: Address, - ) -> Result { + fn withdraw(e: Env, _amount: i128, from: Address, _to: Address) -> Result { from.require_auth(); extend_instance_ttl(&e); let xycloans_address = get_xycloans_pool_address(&e); let xycloans_pool_client = XycloansPoolClient::new(&e, &xycloans_address); - + let shares: i128 = xycloans_pool_client.shares(&from); xycloans_pool_client.withdraw(&from, &shares); @@ -109,39 +118,37 @@ impl DeFindexStrategyTrait for XycloansAdapter { Ok(result) } - fn balance( - e: Env, - from: Address, - ) -> Result { - + fn balance(e: Env, from: Address) -> Result { let xycloans_address = get_xycloans_pool_address(&e); let xycloans_pool_client = XycloansPoolClient::new(&e, &xycloans_address); - + let shares: i128 = xycloans_pool_client.shares(&from); let matured: i128 = xycloans_pool_client.matured(&from); - + let total: i128 = shares.checked_add(matured).unwrap(); // If total is zero, return it if total == 0 { return Ok(total); } - + // XLM TO USDC QUOTE from SOROSWAP let soroswap_factory = get_soroswap_factory_address(&e); let pool_token = get_pool_token(&e); let token_in = get_token_in(&e); - + // Setting up Soroswap router client let (reserve_0, reserve_1) = get_reserves( e.clone(), soroswap_factory.clone(), pool_token.clone(), token_in.clone(), - ).map_err(|_| StrategyError::ProtocolAddressNotFound)?; - - let amount_out = get_amount_out(total, reserve_0, reserve_1).map_err(|_| StrategyError::ExternalError)?; - + ) + .map_err(|_| StrategyError::ProtocolAddressNotFound)?; + + let amount_out = get_amount_out(total, reserve_0, reserve_1) + .map_err(|_| StrategyError::ExternalError)?; + Ok(amount_out) } -} \ No newline at end of file +} diff --git a/apps/contracts/strategies/xycloans/src/soroswap_router.rs b/apps/contracts/strategies/xycloans/src/soroswap_router.rs index d2fd2e26..0a876ad4 100644 --- a/apps/contracts/strategies/xycloans/src/soroswap_router.rs +++ b/apps/contracts/strategies/xycloans/src/soroswap_router.rs @@ -1,18 +1,14 @@ +use crate::storage::{get_soroswap_factory_address, get_soroswap_router_address}; use soroban_sdk::auth::{ContractContext, InvokerContractAuthEntry, SubContractInvocation}; use soroban_sdk::crypto::Hash; use soroban_sdk::{vec, Address, Env, IntoVal, Symbol, Val, Vec}; use soroban_sdk::{xdr::ToXdr, Bytes}; -use crate::storage::{get_soroswap_factory_address, get_soroswap_router_address}; -soroban_sdk::contractimport!( - file = "../external_wasms/soroswap/soroswap_router.optimized.wasm" -); +soroban_sdk::contractimport!(file = "../external_wasms/soroswap/soroswap_router.optimized.wasm"); pub type SoroswapRouterClient<'a> = Client<'a>; mod pair { - soroban_sdk::contractimport!( - file = "../external_wasms/soroswap/soroswap_pair.optimized.wasm" - ); + soroban_sdk::contractimport!(file = "../external_wasms/soroswap/soroswap_pair.optimized.wasm"); } use pair::Client as SoroswapPairClient; @@ -48,7 +44,10 @@ fn pair_salt(e: &Env, token_a: Address, token_b: Address) -> Hash<32> { /// # Returns /// /// Returns `Result<(Address, Address), SoroswapLibraryError>` where `Ok` contains a tuple with the sorted token addresses, and `Err` indicates an error such as identical tokens. -pub fn sort_tokens(token_a: Address, token_b: Address) -> Result<(Address, Address), SoroswapLibraryError> { +pub fn sort_tokens( + token_a: Address, + token_b: Address, +) -> Result<(Address, Address), SoroswapLibraryError> { if token_a == token_b { return Err(SoroswapLibraryError::SortIdenticalTokens); } @@ -73,7 +72,12 @@ pub fn sort_tokens(token_a: Address, token_b: Address) -> Result<(Address, Addre /// # Returns /// /// Returns `Result` where `Ok` contains the deterministic address for the pair, and `Err` indicates an error such as identical tokens or an issue with sorting. -pub fn pair_for(e: Env, factory: Address, token_a: Address, token_b: Address) -> Result { +pub fn pair_for( + e: Env, + factory: Address, + token_a: Address, + token_b: Address, +) -> Result { let (token_0, token_1) = sort_tokens(token_a, token_b)?; let salt = pair_salt(&e, token_0, token_1); let deployer_with_address = e.deployer().with_address(factory.clone(), salt); @@ -93,17 +97,22 @@ pub fn pair_for(e: Env, factory: Address, token_a: Address, token_b: Address) -> /// # Returns /// /// Returns `Result<(i128, i128), SoroswapLibraryError>` where `Ok` contains a tuple of sorted reserves, and `Err` indicates an error such as identical tokens or an issue with sorting. -pub fn get_reserves(e: Env,factory: Address, token_a: Address, token_b: Address) -> Result<(i128,i128), SoroswapLibraryError>{ - let (token_0,token_1) = sort_tokens(token_a.clone(), token_b.clone())?; +pub fn get_reserves( + e: Env, + factory: Address, + token_a: Address, + token_b: Address, +) -> Result<(i128, i128), SoroswapLibraryError> { + let (token_0, token_1) = sort_tokens(token_a.clone(), token_b.clone())?; let pair_address = pair_for(e.clone(), factory, token_0.clone(), token_1.clone())?; let pair_client = SoroswapPairClient::new(&e, &pair_address); let (reserve_0, reserve_1) = pair_client.get_reserves(); - - let (reserve_a, reseve_b) = - if token_a == token_0 { - (reserve_0, reserve_1) - } else { - (reserve_1, reserve_0) }; + + let (reserve_a, reseve_b) = if token_a == token_0 { + (reserve_0, reserve_1) + } else { + (reserve_1, reserve_0) + }; Ok((reserve_a, reseve_b)) } @@ -119,40 +128,52 @@ pub fn get_reserves(e: Env,factory: Address, token_a: Address, token_b: Address) /// # Returns /// /// Returns `Result` where `Ok` contains the calculated maximum output amount, and `Err` indicates an error such as insufficient input amount or liquidity. -pub fn get_amount_out(amount_in: i128, reserve_in: i128, reserve_out: i128) -> Result { - if amount_in <= 0 { - return Err(SoroswapLibraryError::InsufficientInputAmount); - } - if reserve_in <= 0 || reserve_out <= 0 { - return Err(SoroswapLibraryError::InsufficientLiquidity); - } +pub fn get_amount_out( + amount_in: i128, + reserve_in: i128, + reserve_out: i128, +) -> Result { + if amount_in <= 0 { + return Err(SoroswapLibraryError::InsufficientInputAmount); + } + if reserve_in <= 0 || reserve_out <= 0 { + return Err(SoroswapLibraryError::InsufficientLiquidity); + } - let fee = (amount_in.checked_mul(3).unwrap()).checked_ceiling_div(1000).unwrap(); + let fee = (amount_in.checked_mul(3).unwrap()) + .checked_ceiling_div(1000) + .unwrap(); - let amount_in_less_fee = amount_in.checked_sub(fee).unwrap(); - let numerator = amount_in_less_fee.checked_mul(reserve_out).unwrap(); + let amount_in_less_fee = amount_in.checked_sub(fee).unwrap(); + let numerator = amount_in_less_fee.checked_mul(reserve_out).unwrap(); - let denominator = reserve_in.checked_add(amount_in_less_fee).unwrap(); + let denominator = reserve_in.checked_add(amount_in_less_fee).unwrap(); - Ok(numerator.checked_div(denominator).unwrap()) + Ok(numerator.checked_div(denominator).unwrap()) } pub trait CheckedCeilingDiv { - fn checked_ceiling_div(self, divisor: i128) -> Option; + fn checked_ceiling_div(self, divisor: i128) -> Option; } impl CheckedCeilingDiv for i128 { - fn checked_ceiling_div(self, divisor: i128) -> Option { - let result = self.checked_div(divisor)?; - if self % divisor != 0 { - result.checked_add(1) - } else { - Some(result) - } - } + fn checked_ceiling_div(self, divisor: i128) -> Option { + let result = self.checked_div(divisor)?; + if self % divisor != 0 { + result.checked_add(1) + } else { + Some(result) + } + } } -pub fn swap(e: &Env, from: &Address, token_in: &Address, token_out: &Address, amount_in: &i128) -> i128 { +pub fn swap( + e: &Env, + from: &Address, + token_in: &Address, + token_out: &Address, + amount_in: &i128, +) -> i128 { // Setting up Soroswap router client let soroswap_router_address = get_soroswap_router_address(e); let soroswap_router_client = SoroswapRouterClient::new(e, &soroswap_router_address); @@ -160,10 +181,10 @@ pub fn swap(e: &Env, from: &Address, token_in: &Address, token_out: &Address, am // This could be hardcoded to perform less instructions let soroswap_pair_address = get_soroswap_factory_address(e); let pair_address = pair_for( - e.clone(), - soroswap_pair_address.clone(), - token_out.clone(), - token_in.clone() + e.clone(), + soroswap_pair_address.clone(), + token_out.clone(), + token_in.clone(), ); let mut path: Vec
= Vec::new(e); @@ -177,14 +198,14 @@ pub fn swap(e: &Env, from: &Address, token_in: &Address, token_out: &Address, am e.authorize_as_current_contract(vec![ &e, - InvokerContractAuthEntry::Contract( SubContractInvocation { + InvokerContractAuthEntry::Contract(SubContractInvocation { context: ContractContext { contract: token_in.clone(), fn_name: Symbol::new(&e, "transfer"), args: args.clone(), }, - sub_invocations: vec![&e] - }) + sub_invocations: vec![&e], + }), ]); // let swap_amount = amount_in/2; @@ -200,4 +221,4 @@ pub fn swap(e: &Env, from: &Address, token_in: &Address, token_out: &Address, am let total_swapped_amount = res.last().unwrap_or(0); total_swapped_amount -} \ No newline at end of file +} diff --git a/apps/contracts/strategies/xycloans/src/storage.rs b/apps/contracts/strategies/xycloans/src/storage.rs index 19decb51..77dee633 100644 --- a/apps/contracts/strategies/xycloans/src/storage.rs +++ b/apps/contracts/strategies/xycloans/src/storage.rs @@ -1,4 +1,4 @@ -use soroban_sdk::{contracttype, Env, Address}; +use soroban_sdk::{contracttype, Address, Env}; #[derive(Clone)] #[contracttype] @@ -8,7 +8,7 @@ enum DataKey { SoroswapFactoryAddress, XycloansPoolAddress, Token0, - Token1 + Token1, } const DAY_IN_LEDGERS: u32 = 17280; @@ -23,29 +23,44 @@ pub fn extend_instance_ttl(e: &Env) { // Soroswap Router Address pub fn set_soroswap_router_address(e: &Env, address: Address) { - e.storage().instance().set(&DataKey::SoroswapRouterAddress, &address); + e.storage() + .instance() + .set(&DataKey::SoroswapRouterAddress, &address); } pub fn get_soroswap_router_address(e: &Env) -> Address { - e.storage().instance().get(&DataKey::SoroswapRouterAddress).unwrap() + e.storage() + .instance() + .get(&DataKey::SoroswapRouterAddress) + .unwrap() } // Soroswap Factory Address pub fn set_soroswap_factory_address(e: &Env, address: Address) { - e.storage().instance().set(&DataKey::SoroswapFactoryAddress, &address); + e.storage() + .instance() + .set(&DataKey::SoroswapFactoryAddress, &address); } pub fn get_soroswap_factory_address(e: &Env) -> Address { - e.storage().instance().get(&DataKey::SoroswapFactoryAddress).unwrap() + e.storage() + .instance() + .get(&DataKey::SoroswapFactoryAddress) + .unwrap() } // Xycloans Pool Address pub fn set_xycloans_pool_address(e: &Env, address: Address) { - e.storage().instance().set(&DataKey::XycloansPoolAddress, &address); + e.storage() + .instance() + .set(&DataKey::XycloansPoolAddress, &address); } pub fn get_xycloans_pool_address(e: &Env) -> Address { - e.storage().instance().get(&DataKey::XycloansPoolAddress).unwrap() + e.storage() + .instance() + .get(&DataKey::XycloansPoolAddress) + .unwrap() } // Tokens @@ -63,4 +78,4 @@ pub fn set_token_in(e: &Env, address: Address) { pub fn get_token_in(e: &Env) -> Address { e.storage().instance().get(&DataKey::Token1).unwrap() -} \ No newline at end of file +} diff --git a/apps/contracts/strategies/xycloans/src/xycloans_pool.rs b/apps/contracts/strategies/xycloans/src/xycloans_pool.rs index c5e8a8b9..2e39dce6 100644 --- a/apps/contracts/strategies/xycloans/src/xycloans_pool.rs +++ b/apps/contracts/strategies/xycloans/src/xycloans_pool.rs @@ -1,4 +1,2 @@ -soroban_sdk::contractimport!( - file = "../external_wasms/xycloans/xycloans_pool.wasm" -); -pub type XycloansPoolClient<'a> = Client<'a>; \ No newline at end of file +soroban_sdk::contractimport!(file = "../external_wasms/xycloans/xycloans_pool.wasm"); +pub type XycloansPoolClient<'a> = Client<'a>; diff --git a/apps/contracts/vault/Cargo.toml b/apps/contracts/vault/Cargo.toml index a2c4b93c..19f5f414 100755 --- a/apps/contracts/vault/Cargo.toml +++ b/apps/contracts/vault/Cargo.toml @@ -15,6 +15,7 @@ soroban-sdk = { workspace = true } soroban-token-sdk = { workspace = true } defindex-strategy-core = { workspace = true } common = { workspace = true } +soroswap-library = { workspace = true } [dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } diff --git a/apps/contracts/vault/src/aggregator.rs b/apps/contracts/vault/src/aggregator.rs index 6923e188..ed9aa85b 100644 --- a/apps/contracts/vault/src/aggregator.rs +++ b/apps/contracts/vault/src/aggregator.rs @@ -1,21 +1,15 @@ -use soroban_sdk::{vec, Address, Env, IntoVal, Symbol, Val, Vec}; +use soroban_sdk::{ + auth::{ContractContext, InvokerContractAuthEntry, SubContractInvocation}, + vec, Address, Env, IntoVal, Symbol, Val, Vec, +}; +use soroswap_library::{get_amount_in, get_reserves_with_pair}; use crate::{ - models::DexDistribution, - storage::{get_assets, get_factory}, + // models::DexDistribution, + storage::{get_assets, get_soroswap_router}, ContractError, }; -fn fetch_aggregator_address(e: &Env) -> Address { - let factory_address = get_factory(e); - - e.invoke_contract( - &factory_address, - &Symbol::new(&e, "aggregator"), - Vec::new(&e), - ) -} - fn is_supported_asset(e: &Env, token: &Address) -> bool { let assets = get_assets(e); assets.iter().any(|asset| &asset.address == token) @@ -27,30 +21,53 @@ pub fn internal_swap_exact_tokens_for_tokens( token_out: &Address, amount_in: &i128, amount_out_min: &i128, - distribution: &Vec, deadline: &u64, ) -> Result<(), ContractError> { - let aggregator_address = fetch_aggregator_address(e); - // Check if both tokens are supported by the vault if !is_supported_asset(e, token_in) || !is_supported_asset(e, token_out) { return Err(ContractError::UnsupportedAsset); } + let swap_args: Vec = vec![ + e, + amount_in.into_val(e), + amount_out_min.into_val(e), + vec![e, token_in.to_val(), token_out.to_val()].into_val(e), // path + e.current_contract_address().to_val(), + deadline.into_val(e), + ]; - let mut swap_args: Vec = vec![&e]; - swap_args.push_back(token_in.to_val()); - swap_args.push_back(token_out.to_val()); - swap_args.push_back(amount_in.into_val(e)); - swap_args.push_back(amount_out_min.into_val(e)); - swap_args.push_back(distribution.into_val(e)); - swap_args.push_back(e.current_contract_address().to_val()); - swap_args.push_back(deadline.into_val(e)); + let soroswap_router = get_soroswap_router(e); - e.invoke_contract( - &aggregator_address, + let pair_address: Address = e.invoke_contract( + &soroswap_router, + &Symbol::new(&e, "router_pair_for"), + vec![e, token_in.to_val(), token_out.to_val()], + ); + + e.authorize_as_current_contract(vec![ + &e, + InvokerContractAuthEntry::Contract(SubContractInvocation { + context: ContractContext { + contract: token_in.clone(), + fn_name: Symbol::new(&e, "transfer"), + args: ( + e.current_contract_address(), + pair_address.clone(), + amount_in.clone(), + ) + .into_val(e), + }, + sub_invocations: vec![&e], + }), + ]); + + let _result: Vec = e.invoke_contract( + &get_soroswap_router(e), &Symbol::new(&e, "swap_exact_tokens_for_tokens"), swap_args, - ) + ); + Ok(()) + // TODO: Do something with the result } pub fn internal_swap_tokens_for_exact_tokens( @@ -59,28 +76,56 @@ pub fn internal_swap_tokens_for_exact_tokens( token_out: &Address, amount_out: &i128, amount_in_max: &i128, - distribution: &Vec, deadline: &u64, ) -> Result<(), ContractError> { - let aggregator_address = fetch_aggregator_address(e); - // Check if both tokens are supported by the vault if !is_supported_asset(e, token_in) || !is_supported_asset(e, token_out) { return Err(ContractError::UnsupportedAsset); } + let soroswap_router = get_soroswap_router(e); + let pair_address: Address = e.invoke_contract( + &soroswap_router, + &Symbol::new(&e, "router_pair_for"), + vec![e, token_in.to_val(), token_out.to_val()], + ); + let (reserve_in, reserve_out) = get_reserves_with_pair( + e.clone(), + pair_address.clone(), + token_in.clone(), + token_out.clone(), + )?; + let amount_in = get_amount_in(amount_out.clone(), reserve_in, reserve_out); + + let swap_args: Vec = vec![ + e, + amount_out.into_val(e), + amount_in_max.into_val(e), + vec![e, token_in.to_val(), token_out.to_val()].into_val(e), // path + e.current_contract_address().to_val(), + deadline.into_val(e), + ]; - let mut swap_args: Vec = vec![&e]; - swap_args.push_back(token_in.to_val()); - swap_args.push_back(token_out.to_val()); - swap_args.push_back(amount_out.into_val(e)); - swap_args.push_back(amount_in_max.into_val(e)); - swap_args.push_back(distribution.into_val(e)); - swap_args.push_back(e.current_contract_address().to_val()); - swap_args.push_back(deadline.into_val(e)); + e.authorize_as_current_contract(vec![ + &e, + InvokerContractAuthEntry::Contract(SubContractInvocation { + context: ContractContext { + contract: token_in.clone(), + fn_name: Symbol::new(&e, "transfer"), + args: ( + e.current_contract_address(), + pair_address.clone(), + amount_in.clone(), + ) + .into_val(e), + }, + sub_invocations: vec![&e], + }), + ]); - e.invoke_contract( - &aggregator_address, + let _result: Vec = e.invoke_contract( + &get_soroswap_router(e), &Symbol::new(&e, "swap_tokens_for_exact_tokens"), swap_args, - ) + ); + Ok(()) } diff --git a/apps/contracts/vault/src/constants.rs b/apps/contracts/vault/src/constants.rs index c5f2495d..17e30b9e 100644 --- a/apps/contracts/vault/src/constants.rs +++ b/apps/contracts/vault/src/constants.rs @@ -1 +1 @@ -pub(crate) const MAX_BPS: i128 = 10_000; \ No newline at end of file +pub(crate) const MAX_BPS: i128 = 10_000; diff --git a/apps/contracts/vault/src/deposit.rs b/apps/contracts/vault/src/deposit.rs index 7046bcd7..28ea4021 100644 --- a/apps/contracts/vault/src/deposit.rs +++ b/apps/contracts/vault/src/deposit.rs @@ -1,12 +1,12 @@ use common::models::AssetStrategySet; -use soroban_sdk::{panic_with_error, token::TokenClient, Address, Env, Vec, Map}; +use soroban_sdk::{panic_with_error, token::TokenClient, Address, Env, Map, Vec}; use crate::{ + models::CurrentAssetInvestmentAllocation, storage::get_assets, token::{internal_mint, VaultToken}, utils::{calculate_deposit_amounts_and_shares_to_mint, check_nonnegative_amount}, ContractError, MINIMUM_LIQUIDITY, - models::CurrentAssetInvestmentAllocation, }; /// Common logic for processing deposits. @@ -31,21 +31,18 @@ pub fn process_deposit( let total_supply = VaultToken::total_supply(e.clone()); let (amounts, shares_to_mint) = if assets_length == 1 { - calculate_single_asset_shares( - e, - amounts_desired, - &total_managed_funds, - total_supply)? + calculate_single_asset_shares(e, amounts_desired, &total_managed_funds, total_supply)? } else { if total_supply == 0 { (amounts_desired.clone(), amounts_desired.iter().sum()) } else { calculate_deposit_amounts_and_shares_to_mint( - &e, - &assets, + &e, + &assets, &total_managed_funds, - amounts_desired, - amounts_min)? + amounts_desired, + amounts_min, + )? } }; @@ -83,7 +80,8 @@ fn calculate_single_asset_shares( .checked_div( total_managed_funds .get(get_assets(&e).get(0).unwrap().address.clone()) - .unwrap().total_amount, + .unwrap() + .total_amount, ) .unwrap_or_else(|| panic_with_error!(&e, ContractError::ArithmeticError)) }; @@ -111,4 +109,4 @@ fn mint_shares( internal_mint(e.clone(), from, shares_to_mint); } Ok(()) -} \ No newline at end of file +} diff --git a/apps/contracts/vault/src/error.rs b/apps/contracts/vault/src/error.rs index d1a56c69..c975c618 100644 --- a/apps/contracts/vault/src/error.rs +++ b/apps/contracts/vault/src/error.rs @@ -1,4 +1,5 @@ use soroban_sdk::{self, contracterror}; +use soroswap_library::SoroswapLibraryError; #[contracterror] #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] @@ -26,7 +27,6 @@ pub enum ContractError { AmountOverTotalSupply = 124, NoInstructions = 125, - // Arithmetic Errors (12x) ArithmeticError = 120, Overflow = 121, @@ -45,4 +45,16 @@ pub enum ContractError { // Asset Errors (15x) AssetNotFound = 150, NoAssetsProvided = 151, + + // Add mappings for SoroswapLibraryError + LibrarySortIdenticalTokens = 190, +} + +impl From for ContractError { + fn from(err: SoroswapLibraryError) -> Self { + match err { + SoroswapLibraryError::SortIdenticalTokens => ContractError::LibrarySortIdenticalTokens, + _ => panic!("Unhandled SoroswapLibraryError variant: {:?}", err), + } + } } diff --git a/apps/contracts/vault/src/events.rs b/apps/contracts/vault/src/events.rs index e0b554d0..d502a931 100644 --- a/apps/contracts/vault/src/events.rs +++ b/apps/contracts/vault/src/events.rs @@ -172,17 +172,12 @@ pub(crate) fn emit_emergency_manager_changed_event(e: &Env, new_emergency_manage #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct FeesDistributedEvent { - pub distributed_fees: Vec<(Address, i128)> + pub distributed_fees: Vec<(Address, i128)>, } /// Publishes an `EmergencyManagerChangedEvent` to the event stream. -pub(crate) fn emit_fees_distributed_event( - e: &Env, - distributed_fees: Vec<(Address, i128)>, -) { - let event = FeesDistributedEvent { - distributed_fees, - }; +pub(crate) fn emit_fees_distributed_event(e: &Env, distributed_fees: Vec<(Address, i128)>) { + let event = FeesDistributedEvent { distributed_fees }; e.events() .publish(("DeFindexVault", symbol_short!("dfees")), event); diff --git a/apps/contracts/vault/src/funds.rs b/apps/contracts/vault/src/funds.rs index bf8b6102..fad7f162 100644 --- a/apps/contracts/vault/src/funds.rs +++ b/apps/contracts/vault/src/funds.rs @@ -1,14 +1,14 @@ use soroban_sdk::token::TokenClient; use soroban_sdk::{Address, Env, Map, Vec}; -use common::models::AssetStrategySet; -use crate::models::{StrategyAllocation, CurrentAssetInvestmentAllocation}; +use crate::models::{CurrentAssetInvestmentAllocation, StrategyAllocation}; use crate::storage::{get_assets, get_report, get_vault_fee, set_report}; use crate::strategies::get_strategy_client; +use common::models::AssetStrategySet; /// Retrieves the idle funds for a given asset. -/// -/// Idle funds represent the balance of the asset that is held by the current contract +/// +/// Idle funds represent the balance of the asset that is held by the current contract /// but not actively allocated to any strategies. /// /// # Arguments @@ -22,9 +22,9 @@ pub fn fetch_idle_funds_for_asset(e: &Env, asset: &Address) -> i128 { } /// Retrieves the total funds invested in a specified strategy, excluding any locked fees. -/// -/// This function performs a cross-contract call to the strategy to fetch the current balance -/// of the investment. It then subtracts any locked fees from the total to provide an accurate +/// +/// This function performs a cross-contract call to the strategy to fetch the current balance +/// of the investment. It then subtracts any locked fees from the total to provide an accurate /// representation of the funds that are actively invested and available to the user. /// /// # Arguments @@ -43,14 +43,15 @@ pub fn fetch_strategy_invested_funds(e: &Env, strategy_address: &Address, lock_f report.lock_fee(get_vault_fee(e)); set_report(e, strategy_address, &report); } - strategy_invested_funds.checked_sub(report.locked_fee).unwrap_or(0) + strategy_invested_funds + .checked_sub(report.locked_fee) + .unwrap_or(0) } - -/// Calculates the total funds invested in strategies for a given asset and +/// Calculates the total funds invested in strategies for a given asset and /// provides a detailed breakdown of allocations. /// -/// This function aggregates the balances of all strategies linked to the specified +/// This function aggregates the balances of all strategies linked to the specified /// asset and returns both the total invested amount and a detailed allocation. /// /// # Arguments @@ -61,7 +62,11 @@ pub fn fetch_strategy_invested_funds(e: &Env, strategy_address: &Address, lock_f /// A tuple containing: /// * `i128`: The total funds invested across all strategies. /// * `Vec`: A vector with the allocation details for each strategy. -pub fn fetch_invested_funds_for_asset(e: &Env, asset_strategy_set: &AssetStrategySet, lock_fees: bool) -> (i128, Vec){ +pub fn fetch_invested_funds_for_asset( + e: &Env, + asset_strategy_set: &AssetStrategySet, + lock_fees: bool, +) -> (i128, Vec) { let mut invested_funds = 0; let mut strategy_allocations: Vec = Vec::new(e); for strategy in asset_strategy_set.strategies.iter() { @@ -73,7 +78,7 @@ pub fn fetch_invested_funds_for_asset(e: &Env, asset_strategy_set: &AssetStrateg }); } (invested_funds, strategy_allocations) -} +} /// Fetches the total managed funds for all assets. This includes both idle and invested funds. /// It returns a map where the key is the asset's address and the value is the total managed balance @@ -84,12 +89,16 @@ pub fn fetch_invested_funds_for_asset(e: &Env, asset_strategy_set: &AssetStrateg /// /// # Returns /// * A map where each entry represents an asset's address and its total managed balance. -pub fn fetch_total_managed_funds(e: &Env, lock_fees: bool) -> Map { +pub fn fetch_total_managed_funds( + e: &Env, + lock_fees: bool, +) -> Map { let assets = get_assets(e); let mut map: Map = Map::new(e); for asset in assets { let idle_amount = fetch_idle_funds_for_asset(e, &asset.address); - let (invested_amount, strategy_allocations) = fetch_invested_funds_for_asset(e, &asset, lock_fees); + let (invested_amount, strategy_allocations) = + fetch_invested_funds_for_asset(e, &asset, lock_fees); let total_amount = idle_amount + invested_amount; map.set( asset.address.clone(), @@ -106,13 +115,12 @@ pub fn fetch_total_managed_funds(e: &Env, lock_fees: bool) -> Map Map { let assets = get_assets(e); let mut map: Map = Map::new(e); for asset in assets { - map.set(asset.address.clone(), fetch_idle_funds_for_asset(e, &asset.address)); + map.set( + asset.address.clone(), + fetch_idle_funds_for_asset(e, &asset.address), + ); } map } @@ -143,10 +154,7 @@ pub fn fetch_current_invested_funds(e: &Env, lock_fees: bool) -> Map = Map::new(e); for asset in assets { let (invested_funds, _) = fetch_invested_funds_for_asset(e, &asset, lock_fees); - map.set( - asset.address.clone(), - invested_funds - ); + map.set(asset.address.clone(), invested_funds); } map } diff --git a/apps/contracts/vault/src/interface.rs b/apps/contracts/vault/src/interface.rs index 1e0fc9a7..3b25f2fd 100644 --- a/apps/contracts/vault/src/interface.rs +++ b/apps/contracts/vault/src/interface.rs @@ -1,7 +1,9 @@ use soroban_sdk::{Address, Env, Map, String, Vec}; use crate::{ - models::{AssetInvestmentAllocation, CurrentAssetInvestmentAllocation, Instruction}, report::Report, ContractError + models::{AssetInvestmentAllocation, CurrentAssetInvestmentAllocation, Instruction}, + report::Report, + ContractError, }; use common::models::AssetStrategySet; @@ -20,6 +22,7 @@ pub trait VaultTrait { /// - `defindex_protocol_receiver`: Address receiving DeFindex’s protocol-wide fee in basis points. /// - `defindex_protocol_rate`: DeFindex’s protocol fee percentage in basis points. /// - `factory`: Factory contract address for deployment linkage. + /// - `soroswap_router`: Address of the Soroswap Router /// - `vault_name`: Name of the vault token to be displayed in metadata. /// - `vault_symbol`: Symbol representing the vault’s token. /// @@ -32,7 +35,7 @@ pub trait VaultTrait { /// - `ContractError::StrategyDoesNotSupportAsset`: If a strategy within an asset does not support the asset’s contract. /// fn __constructor( - e: Env, + e: Env, assets: Vec, manager: Address, emergency_manager: Address, @@ -41,15 +44,15 @@ pub trait VaultTrait { defindex_protocol_receiver: Address, defindex_protocol_rate: u32, factory: Address, - vault_name: String, - vault_symbol: String, + soroswap_router: Address, + name_symbol: Vec, ); /// Handles user deposits into the DeFindex Vault. /// /// This function processes a deposit by transferring each specified asset amount from the user's address to - /// the vault, allocating assets according to the vault's defined strategy ratios, and minting dfTokens that - /// represent the user's proportional share in the vault. The `amounts_desired` and `amounts_min` vectors should + /// the vault, allocating assets according to the vault's defined strategy ratios, and minting dfTokens that + /// represent the user's proportional share in the vault. The `amounts_desired` and `amounts_min` vectors should /// align with the vault's asset order to ensure correct allocation. /// /// # Parameters @@ -198,10 +201,9 @@ pub trait VaultTrait { /// * `Map` - A map of asset addresses to their total idle amounts. fn fetch_current_idle_funds(e: &Env) -> Map; - // Calculates the corresponding amounts of each asset per a given number of vault shares. - /// This function extends the contract's time-to-live and calculates how much of each asset corresponds - /// per the provided number of vault shares (`vault_shares`). It provides proportional allocations for each asset + /// This function extends the contract's time-to-live and calculates how much of each asset corresponds + /// per the provided number of vault shares (`vault_shares`). It provides proportional allocations for each asset /// in the vault relative to the specified shares. /// /// # Arguments @@ -210,8 +212,11 @@ pub trait VaultTrait { /// /// # Returns /// * `Map` - A map containing each asset address and its corresponding proportional amount. - fn get_asset_amounts_per_shares(e: Env, vault_shares: i128) -> Result, ContractError>; - + fn get_asset_amounts_per_shares( + e: Env, + vault_shares: i128, + ) -> Result, ContractError>; + fn get_fees(e: Env) -> (u32, u32); /// Reports the gains or losses for all strategies in the vault based on their current balances. @@ -222,10 +227,9 @@ pub trait VaultTrait { /// # Arguments /// * `e` - A reference to the environment. /// - /// # Returns + /// # Returns /// * `Result, ContractError>` - A vector of tuples containing the strategy address, current balance, and the gain or loss. fn report(e: Env) -> Result, ContractError>; - } pub trait AdminInterfaceTrait { @@ -301,7 +305,7 @@ pub trait VaultManagementTrait { /// /// # Arguments /// * `e` - The current environment reference. - /// * `asset_investments` - A vector of optional `AssetInvestmentAllocation` structures, where each element + /// * `asset_investments` - A vector of optional `AssetInvestmentAllocation` structures, where each element /// represents an allocation for a specific asset. The vector must match the number of vault assets in length. /// /// # Returns @@ -323,8 +327,9 @@ pub trait VaultManagementTrait { /// /// # Security /// - Only addresses with the `Manager` role can call this function, ensuring restricted access to managing investments. - fn invest(e: Env, - asset_investments: Vec> + fn invest( + e: Env, + asset_investments: Vec>, ) -> Result<(), ContractError>; /// Rebalances the vault by executing a series of instructions. diff --git a/apps/contracts/vault/src/investment.rs b/apps/contracts/vault/src/investment.rs index 2be58326..fd5d0421 100644 --- a/apps/contracts/vault/src/investment.rs +++ b/apps/contracts/vault/src/investment.rs @@ -1,7 +1,7 @@ -use soroban_sdk::{Env, Vec, panic_with_error, Map, Address}; +use soroban_sdk::{panic_with_error, Address, Env, Map, Vec}; use crate::{ - models::{AssetInvestmentAllocation, StrategyAllocation, CurrentAssetInvestmentAllocation}, + models::{AssetInvestmentAllocation, CurrentAssetInvestmentAllocation, StrategyAllocation}, strategies::invest_in_strategy, utils::check_nonnegative_amount, ContractError, @@ -9,24 +9,24 @@ use crate::{ use common::models::AssetStrategySet; /// Executes investment allocations for a set of assets based on the provided investment strategies. -/// -/// This function ensures that the specified assets and strategies match the contract's known configuration, -/// then validates and processes the investment allocations for each asset and its strategies. It assumes -/// that the caller is responsible for ensuring the correctness of investment ratios and does not check the +/// +/// This function ensures that the specified assets and strategies match the contract's known configuration, +/// then validates and processes the investment allocations for each asset and its strategies. It assumes +/// that the caller is responsible for ensuring the correctness of investment ratios and does not check the /// current state of the strategies or existing investments. /// /// # Arguments /// * `e` - The current environment reference. -/// * `assets` - A vector of `AssetStrategySet` representing the assets and their associated strategies +/// * `assets` - A vector of `AssetStrategySet` representing the assets and their associated strategies /// managed by this vault. /// * `asset_investments` - A vector of optional investment allocations for each asset. /// /// # Returns -/// * `Result<(), ContractError>` - Returns `Ok(())` if all investments are successful, or an appropriate +/// * `Result<(), ContractError>` - Returns `Ok(())` if all investments are successful, or an appropriate /// `ContractError` if validation or execution fails. /// /// # Function Details -/// 1. **Iterates Over Asset Investments**: Loops through each asset's investment allocation, processing only +/// 1. **Iterates Over Asset Investments**: Loops through each asset's investment allocation, processing only /// defined allocations. /// 2. **Validation**: /// - Confirms that the asset's address matches the expected address in the allocation. @@ -43,17 +43,17 @@ use common::models::AssetStrategySet; /// /// # Notes /// - The function relies on the assets being ordered consistently with the investment allocations. -/// - It allows the caller to update investment ratios freely, without verifying the current state of investments +/// - It allows the caller to update investment ratios freely, without verifying the current state of investments /// or strategies. pub fn check_and_execute_investments( - e: &Env, + e: &Env, assets: &Vec, - asset_investments: &Vec> + asset_investments: &Vec>, ) -> Result<(), ContractError> { - // Iterate over each asset investment allocation for (i, asset_investment_opt) in asset_investments.iter().enumerate() { - if let Some(asset_investment) = asset_investment_opt { // Proceed only if allocation is defined + if let Some(asset_investment) = asset_investment_opt { + // Proceed only if allocation is defined let asset = assets.get(i as u32).unwrap(); // Verify the asset address matches the specified investment allocation @@ -67,7 +67,9 @@ pub fn check_and_execute_investments( } // Process each defined strategy investment for the current asset - for (j, strategy_investment_opt) in asset_investment.strategy_allocations.iter().enumerate() { + for (j, strategy_investment_opt) in + asset_investment.strategy_allocations.iter().enumerate() + { if let Some(strategy_investment) = strategy_investment_opt { // Validate amount is non-negative check_nonnegative_amount(strategy_investment.amount)?; @@ -82,8 +84,9 @@ pub fn check_and_execute_investments( invest_in_strategy( &e, &asset.address, - &strategy.address, - &strategy_investment.amount)?; + &strategy.address, + &strategy_investment.amount, + )?; } } } @@ -92,10 +95,10 @@ pub fn check_and_execute_investments( } /// Generates investment allocations for a set of assets and their associated strategies. -/// -/// This function calculates the distribution of funds across strategies for each asset based -/// on the current state of strategy investments. The allocations are returned as a vector, -/// where each entry corresponds to an asset's investment allocation or `None` if no allocation +/// +/// This function calculates the distribution of funds across strategies for each asset based +/// on the current state of strategy investments. The allocations are returned as a vector, +/// where each entry corresponds to an asset's investment allocation or `None` if no allocation /// is required. /// /// # Arguments @@ -105,7 +108,7 @@ pub fn check_and_execute_investments( /// - `amounts` - A vector of amounts representing the funds to be allocated for each asset. /// /// # Returns -/// - `Ok(Vec>)` - A vector of investment allocations where each entry +/// - `Ok(Vec>)` - A vector of investment allocations where each entry /// represents an asset's strategy allocations. If an asset does not require allocation, its entry is `None`. /// - `Err(ContractError)` - If any errors occur during the allocation process, such as invalid data or calculations. /// @@ -134,7 +137,7 @@ pub fn generate_investment_allocations( for (i, amount) in amounts.iter().enumerate() { let asset = assets.get(i as u32).unwrap(); - + let current_asset_allocation = total_managed_funds.get(asset.address.clone()).unwrap(); let asset_invested_funds = current_asset_allocation.invested_amount; @@ -142,8 +145,8 @@ pub fn generate_investment_allocations( // if the amount already invested in the asset is 0, // this means that there is no previous investment in the asset, so we can just // invest, and we need to wait for the manager to execute a manual investment of the idle assets - // on the strategies. - if amount >0 && asset_invested_funds >0 { + // on the strategies. + if amount > 0 && asset_invested_funds > 0 { // here the asset will be distributed amont the different strategies considering the current raio // of investment in each strategy. let mut strategy_allocations = Vec::new(&e); @@ -170,16 +173,14 @@ pub fn generate_investment_allocations( remaining_amount -= invest_amount; // Add the strategy allocation - strategy_allocations.push_back( - if invest_amount > 0 { - Some(StrategyAllocation { - strategy_address: strategy.address.clone(), - amount: invest_amount, - }) - } else { - None - }, - ); + strategy_allocations.push_back(if invest_amount > 0 { + Some(StrategyAllocation { + strategy_address: strategy.address.clone(), + amount: invest_amount, + }) + } else { + None + }); } // Add the asset investment allocation @@ -187,14 +188,9 @@ pub fn generate_investment_allocations( asset: asset.address.clone(), strategy_allocations, })); - - - - } - else { + } else { asset_investments.push_back(None); // No investments to be executed for this asset } - } Ok(asset_investments) } diff --git a/apps/contracts/vault/src/lib.rs b/apps/contracts/vault/src/lib.rs index bde29238..903909a8 100755 --- a/apps/contracts/vault/src/lib.rs +++ b/apps/contracts/vault/src/lib.rs @@ -2,9 +2,7 @@ use constants::MAX_BPS; use report::Report; use soroban_sdk::{ - contract, contractimpl, panic_with_error, - token::TokenClient, - Address, Env, Map, String, Vec, + contract, contractimpl, panic_with_error, token::TokenClient, Address, Env, Map, String, Vec, }; use soroban_token_sdk::metadata::TokenMetadata; @@ -28,27 +26,23 @@ mod utils; use access::{AccessControl, AccessControlTrait, RolesDataKey}; use aggregator::{internal_swap_exact_tokens_for_tokens, internal_swap_tokens_for_exact_tokens}; use deposit::process_deposit; -use funds::{fetch_current_idle_funds, fetch_current_invested_funds, fetch_total_managed_funds}; +use funds::{fetch_current_idle_funds, fetch_current_invested_funds, fetch_total_managed_funds}; use interface::{AdminInterfaceTrait, VaultManagementTrait, VaultTrait}; use investment::{check_and_execute_investments, generate_investment_allocations}; -use models::{ - Instruction, OptionalSwapDetailsExactIn, - OptionalSwapDetailsExactOut, CurrentAssetInvestmentAllocation, - ActionType, AssetInvestmentAllocation, -}; +use models::{AssetInvestmentAllocation, CurrentAssetInvestmentAllocation, Instruction}; use storage::{ - extend_instance_ttl, get_assets, get_defindex_protocol_fee_rate, get_defindex_protocol_fee_receiver, get_report, get_vault_fee, set_asset, set_defindex_protocol_fee_rate, set_defindex_protocol_fee_receiver, set_factory, set_report, set_total_assets, set_vault_fee + extend_instance_ttl, get_assets, get_defindex_protocol_fee_rate, + get_defindex_protocol_fee_receiver, get_report, get_vault_fee, set_asset, + set_defindex_protocol_fee_rate, set_defindex_protocol_fee_receiver, set_factory, set_report, + set_soroswap_router, set_total_assets, set_vault_fee, }; use strategies::{ - get_strategy_asset, get_strategy_client, - get_strategy_struct, invest_in_strategy, pause_strategy, unpause_strategy, - unwind_from_strategy, + get_strategy_asset, get_strategy_client, get_strategy_struct, invest_in_strategy, + pause_strategy, unpause_strategy, unwind_from_strategy, }; use token::{internal_burn, write_metadata}; use utils::{ - calculate_asset_amounts_per_vault_shares, - check_initialized, - check_nonnegative_amount, + calculate_asset_amounts_per_vault_shares, check_initialized, check_nonnegative_amount, }; use common::models::AssetStrategySet; @@ -76,6 +70,7 @@ impl VaultTrait for DeFindexVault { /// - `vault_fee`: Vault-specific fee percentage in basis points (typically set at 0-2% APR). /// - `defindex_protocol_receiver`: Address receiving DeFindex’s protocol-wide fee in basis points (0.5% APR). /// - `factory`: Factory contract address for deployment linkage. + /// - `soroswap_router`: Address of the Soroswap router /// - `vault_name`: Name of the vault token to be displayed in metadata. /// - `vault_symbol`: Symbol representing the vault’s token. /// @@ -97,8 +92,8 @@ impl VaultTrait for DeFindexVault { defindex_protocol_receiver: Address, defindex_protocol_rate: u32, factory: Address, - vault_name: String, - vault_symbol: String, + soroswap_router: Address, + name_symbol: Vec, ) { let access_control = AccessControl::new(&e); @@ -106,6 +101,9 @@ impl VaultTrait for DeFindexVault { access_control.set_role(&RolesDataKey::VaultFeeReceiver, &vault_fee_receiver); access_control.set_role(&RolesDataKey::Manager, &manager); + let vault_name = name_symbol.get(0).unwrap(); + let vault_symbol = name_symbol.get(1).unwrap(); + // Set Vault Fee (in basis points) set_vault_fee(&e, &vault_fee); @@ -116,6 +114,9 @@ impl VaultTrait for DeFindexVault { // Set the factory address set_factory(&e, &factory); + // Set soroswap router + set_soroswap_router(&e, &soroswap_router); + // Store Assets Objects let total_assets = assets.len(); @@ -205,27 +206,22 @@ impl VaultTrait for DeFindexVault { let assets = get_assets(&e); - let (amounts, shares_to_mint) = - process_deposit( - &e, - &assets, - &total_managed_funds, - &amounts_desired, - &amounts_min, - &from)?; + let (amounts, shares_to_mint) = process_deposit( + &e, + &assets, + &total_managed_funds, + &amounts_desired, + &amounts_min, + &from, + )?; events::emit_deposit_event(&e, from, amounts.clone(), shares_to_mint.clone()); if invest { - let asset_investments = generate_investment_allocations( - &e, - &assets, - &total_managed_funds, - &amounts, - )?; + let asset_investments = + generate_investment_allocations(&e, &assets, &total_managed_funds, &amounts)?; check_and_execute_investments(&e, &assets, &asset_investments)?; } Ok((amounts, shares_to_mint)) - } /// Handles the withdrawal process for a specified number of vault shares. @@ -263,37 +259,33 @@ impl VaultTrait for DeFindexVault { /// - Implement minimum amounts for withdrawals to ensure compliance with potential restrictions. /// - Replace the returned vector with the original `asset_withdrawal_amounts` map for better structure. /// - avoid the usage of a Map, choose between using map or vector - fn withdraw( - e: Env, - withdraw_shares: i128, - from: Address, - ) -> Result, ContractError> { + fn withdraw(e: Env, withdraw_shares: i128, from: Address) -> Result, ContractError> { extend_instance_ttl(&e); check_initialized(&e)?; check_nonnegative_amount(withdraw_shares)?; from.require_auth(); - + // Calculate the withdrawal amounts for each asset based on the share amounts let total_managed_funds = fetch_total_managed_funds(&e, true); - let asset_withdrawal_amounts = calculate_asset_amounts_per_vault_shares( - &e, - withdraw_shares, - &total_managed_funds, - )?; - + let asset_withdrawal_amounts = + calculate_asset_amounts_per_vault_shares(&e, withdraw_shares, &total_managed_funds)?; + // Burn the shares after calculating the withdrawal amounts // This will panic with error if the user does not have enough balance internal_burn(e.clone(), from.clone(), withdraw_shares); - + let assets = get_assets(&e); // Use assets for iteration order - // Loop through each asset to handle the withdrawal + // Loop through each asset to handle the withdrawal let mut withdrawn_amounts: Vec = Vec::new(&e); - for asset in assets.iter() { // Use assets instead of asset_withdrawal_amounts + for asset in assets.iter() { + // Use assets instead of asset_withdrawal_amounts let asset_address = &asset.address; - if let Some(requested_withdrawal_amount) = asset_withdrawal_amounts.get(asset_address.clone()) { + if let Some(requested_withdrawal_amount) = + asset_withdrawal_amounts.get(asset_address.clone()) + { let asset_allocation = total_managed_funds .get(asset_address.clone()) .unwrap_or_else(|| panic_with_error!(&e, ContractError::WrongAmountsLength)); @@ -309,26 +301,33 @@ impl VaultTrait for DeFindexVault { withdrawn_amounts.push_back(requested_withdrawal_amount); } else { let mut cumulative_amount_for_asset = idle_funds; - let remaining_amount_to_unwind = requested_withdrawal_amount - .checked_sub(idle_funds) - .unwrap(); + let remaining_amount_to_unwind = + requested_withdrawal_amount.checked_sub(idle_funds).unwrap(); let total_invested_amount = asset_allocation.invested_amount; - for (i, strategy_allocation) in asset_allocation.strategy_allocations.iter().enumerate() { - let strategy_amount_to_unwind: i128 = if i == (asset_allocation.strategy_allocations.len() as usize) - 1 { - requested_withdrawal_amount - .checked_sub(cumulative_amount_for_asset) - .unwrap() - } else { - remaining_amount_to_unwind - .checked_mul(strategy_allocation.amount) - .and_then(|result| result.checked_div(total_invested_amount)) - .unwrap_or(0) - }; + for (i, strategy_allocation) in + asset_allocation.strategy_allocations.iter().enumerate() + { + let strategy_amount_to_unwind: i128 = + if i == (asset_allocation.strategy_allocations.len() as usize) - 1 { + requested_withdrawal_amount + .checked_sub(cumulative_amount_for_asset) + .unwrap() + } else { + remaining_amount_to_unwind + .checked_mul(strategy_allocation.amount) + .and_then(|result| result.checked_div(total_invested_amount)) + .unwrap_or(0) + }; if strategy_amount_to_unwind > 0 { - unwind_from_strategy(&e, &strategy_allocation.strategy_address, &strategy_amount_to_unwind, &e.current_contract_address())?; + unwind_from_strategy( + &e, + &strategy_allocation.strategy_address, + &strategy_amount_to_unwind, + &e.current_contract_address(), + )?; cumulative_amount_for_asset += strategy_amount_to_unwind; } } @@ -345,11 +344,10 @@ impl VaultTrait for DeFindexVault { } } - // TODO: Add minimuim amounts for withdrawn_amounts // TODO: Return the asset_withdrawal_amounts Map instead of a vec events::emit_withdraw_event(&e, from, withdraw_shares, withdrawn_amounts.clone()); - + Ok(withdrawn_amounts) } @@ -391,7 +389,12 @@ impl VaultTrait for DeFindexVault { let strategy_balance = strategy_client.balance(&e.current_contract_address()); if strategy_balance > 0 { - let mut report = unwind_from_strategy(&e, &strategy_address, &strategy_balance, &e.current_contract_address())?; + let mut report = unwind_from_strategy( + &e, + &strategy_address, + &strategy_balance, + &e.current_contract_address(), + )?; report.reset(); set_report(&e, &strategy_address, &report); //TODO: Should we check if the idle funds are corresponding to the strategy balance withdrawed? @@ -523,8 +526,8 @@ impl VaultTrait for DeFindexVault { } // Calculates the corresponding amounts of each asset per a given number of vault shares. - /// This function extends the contract's time-to-live and calculates how much of each asset corresponds - /// per the provided number of vault shares (`vault_shares`). It provides proportional allocations for each asset + /// This function extends the contract's time-to-live and calculates how much of each asset corresponds + /// per the provided number of vault shares (`vault_shares`). It provides proportional allocations for each asset /// in the vault relative to the specified shares. /// /// # Arguments @@ -533,11 +536,18 @@ impl VaultTrait for DeFindexVault { /// /// # Returns /// * `Map` - A map containing each asset address and its corresponding proportional amount. - fn get_asset_amounts_per_shares(e: Env, vault_shares: i128) -> Result, ContractError> { + fn get_asset_amounts_per_shares( + e: Env, + vault_shares: i128, + ) -> Result, ContractError> { extend_instance_ttl(&e); let total_managed_funds = fetch_total_managed_funds(&e, true); - Ok(calculate_asset_amounts_per_vault_shares(&e, vault_shares, &total_managed_funds)?) + Ok(calculate_asset_amounts_per_vault_shares( + &e, + vault_shares, + &total_managed_funds, + )?) } /// Retrieves the current fee rates for the vault and the DeFindex protocol. @@ -570,12 +580,13 @@ impl VaultTrait for DeFindexVault { for asset in assets.iter() { for strategy in asset.strategies.iter() { let strategy_client = get_strategy_client(&e, strategy.address.clone()); - let strategy_invested_funds = strategy_client.balance(&e.current_contract_address()); + let strategy_invested_funds = + strategy_client.balance(&e.current_contract_address()); let mut report = get_report(&e, &strategy.address); report.report(strategy_invested_funds); set_report(&e, &strategy.address, &report); - + reports.push_back(report); } } @@ -729,22 +740,11 @@ impl VaultManagementTrait for DeFindexVault { } // Check and execute investments for each asset allocation - check_and_execute_investments( - &e, - &assets, - &asset_investments)?; + check_and_execute_investments(&e, &assets, &asset_investments)?; Ok(()) } - /// Rebalances the vault by executing a series of instructions. - /// - /// # Arguments: - /// * `e` - The environment. - /// * `instructions` - A vector of `Instruction` structs representing actions (withdraw, invest, swap, zapper) to be taken. - /// - /// # Returns: - /// * `Result<(), ContractError>` - Ok if successful, otherwise returns a ContractError. fn rebalance(e: Env, instructions: Vec) -> Result<(), ContractError> { extend_instance_ttl(&e); check_initialized(&e)?; @@ -757,51 +757,54 @@ impl VaultManagementTrait for DeFindexVault { } for instruction in instructions.iter() { - match instruction.action { - ActionType::Withdraw => match (&instruction.strategy, &instruction.amount) { - (Some(strategy_address), Some(amount)) => { - unwind_from_strategy(&e, strategy_address, amount, &e.current_contract_address())?; - } - _ => return Err(ContractError::MissingInstructionData), - }, - ActionType::Invest => match (&instruction.strategy, &instruction.amount) { - (Some(strategy_address), Some(amount)) => { - let asset_address = get_strategy_asset(&e, strategy_address)?; - invest_in_strategy(&e, &asset_address.address, strategy_address, amount)?; - } - _ => return Err(ContractError::MissingInstructionData), - }, - ActionType::SwapExactIn => match &instruction.swap_details_exact_in { - OptionalSwapDetailsExactIn::Some(swap_details) => { - internal_swap_exact_tokens_for_tokens( - &e, - &swap_details.token_in, - &swap_details.token_out, - &swap_details.amount_in, - &swap_details.amount_out_min, - &swap_details.distribution, - &swap_details.deadline, - )?; - } - _ => return Err(ContractError::MissingInstructionData), - }, - ActionType::SwapExactOut => match &instruction.swap_details_exact_out { - OptionalSwapDetailsExactOut::Some(swap_details) => { - internal_swap_tokens_for_exact_tokens( - &e, - &swap_details.token_in, - &swap_details.token_out, - &swap_details.amount_out, - &swap_details.amount_in_max, - &swap_details.distribution, - &swap_details.deadline, - )?; - } - _ => return Err(ContractError::MissingInstructionData), - }, - ActionType::Zapper => { - // TODO: Implement Zapper instructions + match instruction { + Instruction::Withdraw(strategy_address, amount) => { + unwind_from_strategy( + &e, + &strategy_address, + &amount, + &e.current_contract_address(), + )?; + } + Instruction::Invest(strategy_address, amount) => { + let asset_address = get_strategy_asset(&e, &strategy_address)?; + invest_in_strategy(&e, &asset_address.address, &strategy_address, &amount)?; + } + Instruction::SwapExactIn( + token_in, + token_out, + amount_in, + amount_out_min, + deadline, + ) => { + internal_swap_exact_tokens_for_tokens( + &e, + &token_in, + &token_out, + &amount_in, + &amount_out_min, + &deadline, + )?; } + Instruction::SwapExactOut( + token_in, + token_out, + amount_out, + amount_in_max, + deadline, + ) => { + internal_swap_tokens_for_exact_tokens( + &e, + &token_in, + &token_out, + &amount_out, + &amount_in_max, + &deadline, + )?; + } // Zapper instruction is omitted for now + // Instruction::Zapper(instructions) => { + // // TODO: Implement Zapper instructions + // } } } @@ -847,7 +850,7 @@ impl VaultManagementTrait for DeFindexVault { reports.push_back(report); } } - }; + } Ok(reports) } @@ -911,17 +914,25 @@ impl VaultManagementTrait for DeFindexVault { if report.locked_fee > 0 { // Calculate shares for each receiver based on their fee proportion - let numerator = report.locked_fee - .checked_mul(defindex_fee as i128) - .unwrap(); + let numerator = report.locked_fee.checked_mul(defindex_fee as i128).unwrap(); let defindex_fee_amount = numerator.checked_div(MAX_BPS).unwrap(); let vault_fee_amount = report.locked_fee - defindex_fee_amount; report.prev_balance = report.prev_balance - report.locked_fee; - unwind_from_strategy(&e, &strategy.address, &defindex_fee_amount, &defindex_protocol_receiver)?; - unwind_from_strategy(&e, &strategy.address, &vault_fee_amount, &vault_fee_receiver)?; + unwind_from_strategy( + &e, + &strategy.address, + &defindex_fee_amount, + &defindex_protocol_receiver, + )?; + unwind_from_strategy( + &e, + &strategy.address, + &vault_fee_amount, + &vault_fee_receiver, + )?; total_fees_distributed += report.locked_fee; report.locked_fee = 0; set_report(&e, &strategy.address, &report); @@ -931,7 +942,7 @@ impl VaultManagementTrait for DeFindexVault { if total_fees_distributed > 0 { distributed_fees.push_back((asset.address.clone(), total_fees_distributed)); } - }; + } events::emit_fees_distributed_event(&e, distributed_fees.clone()); diff --git a/apps/contracts/vault/src/models.rs b/apps/contracts/vault/src/models.rs index c2f1d7b7..0565278c 100644 --- a/apps/contracts/vault/src/models.rs +++ b/apps/contracts/vault/src/models.rs @@ -1,4 +1,4 @@ -use soroban_sdk::{contracttype, Address, String, Vec}; +use soroban_sdk::{contracttype, Address, Vec}; // Investment Allocation in Strategies #[contracttype] @@ -25,70 +25,33 @@ pub struct AssetInvestmentAllocation { pub asset: Address, pub strategy_allocations: Vec>, } -// -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Instruction { - pub action: ActionType, - pub strategy: Option
, - pub amount: Option, - pub swap_details_exact_in: OptionalSwapDetailsExactIn, - pub swap_details_exact_out: OptionalSwapDetailsExactOut, - // pub zapper_instructions: Option>, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq, Copy)] -pub enum ActionType { - Withdraw = 0, - Invest = 1, - SwapExactIn = 2, - SwapExactOut = 3, - Zapper = 4, -} #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] -pub struct SwapDetailsExactIn { - pub token_in: Address, - pub token_out: Address, - pub amount_in: i128, - pub amount_out_min: i128, - pub distribution: Vec, - pub deadline: u64, -} +pub enum Instruction { + /// Withdraw funds from a strategy. + Withdraw(Address, i128), // (strategy, amount) -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct SwapDetailsExactOut { - pub token_in: Address, - pub token_out: Address, - pub amount_out: i128, - pub amount_in_max: i128, - pub distribution: Vec, - pub deadline: u64, -} + /// Invest funds into a strategy. + Invest(Address, i128), // (strategy, amount) -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct DexDistribution { - pub protocol_id: String, - pub path: Vec
, - pub parts: u32, -} + /// Perform a swap with an exact input amount. + SwapExactIn( + Address, // token_in + Address, // token_out + i128, // amount_in + i128, // amount_out_min + u64, // deadline + ), -// Workaround for Option as it is not supported by the contracttype macro -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum OptionalSwapDetailsExactIn { - Some(SwapDetailsExactIn), - None, -} - -// Workaround for Option as it is not supported by the contracttype macro -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum OptionalSwapDetailsExactOut { - Some(SwapDetailsExactOut), - None, + /// Perform a swap with an exact output amount. + SwapExactOut( + Address, // token_in + Address, // token_out + i128, // amount_out + i128, // amount_in_max + u64, // deadline + ), + // /// Placeholder for zap operations (commented for future use). + // Zapper(Vec), // instructions } diff --git a/apps/contracts/vault/src/report.rs b/apps/contracts/vault/src/report.rs index e0f0e212..f8410366 100644 --- a/apps/contracts/vault/src/report.rs +++ b/apps/contracts/vault/src/report.rs @@ -13,15 +13,13 @@ pub struct Report { impl Report { pub fn lock_fee(&mut self, fee_rate: u32) { let gains_or_losses = self.gains_or_losses; - let numerator = gains_or_losses - .checked_mul(fee_rate as i128) - .unwrap(); + let numerator = gains_or_losses.checked_mul(fee_rate as i128).unwrap(); let total_fee = numerator.checked_div(MAX_BPS).unwrap(); self.locked_fee += total_fee; self.gains_or_losses = 0; } - + pub fn release_fee(&mut self, e: &Env, amount: i128) { if self.locked_fee < amount { panic_with_error!(e, ContractError::InsufficientManagedFunds); @@ -36,7 +34,7 @@ impl Report { } else { self.prev_balance }; - + let gains_or_losses = current_balance - prev_balance; self.gains_or_losses += gains_or_losses; self.prev_balance = current_balance; @@ -47,4 +45,4 @@ impl Report { self.gains_or_losses = 0; self.locked_fee = 0; } -} \ No newline at end of file +} diff --git a/apps/contracts/vault/src/storage.rs b/apps/contracts/vault/src/storage.rs index 565af938..2e9a2c63 100644 --- a/apps/contracts/vault/src/storage.rs +++ b/apps/contracts/vault/src/storage.rs @@ -16,41 +16,33 @@ pub fn extend_instance_ttl(e: &Env) { .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); } - #[derive(Clone)] #[contracttype] enum DataKey { + TotalAssets, // Total number of tokens AssetStrategySet(u32), // AssetStrategySet Addresse by index - TotalAssets, // Total number of tokens DeFindexProtocolFeeReceiver, + DeFindexFactory, + LastFeeAssessment, + VaultFee, + SoroswapRouter, DeFindexProtocolFeeRate, Factory, - VaultFee, - Report(Address) + Report(Address), } -// Assets Management +// AssetStrategySet(index) pub fn set_asset(e: &Env, index: u32, asset: &AssetStrategySet) { e.storage() .instance() .set(&DataKey::AssetStrategySet(index), asset); } - pub fn get_asset(e: &Env, index: u32) -> AssetStrategySet { e.storage() .instance() .get(&DataKey::AssetStrategySet(index)) .unwrap() } - -pub fn set_total_assets(e: &Env, n: u32) { - e.storage().instance().set(&DataKey::TotalAssets, &n); -} - -pub fn get_total_assets(e: &Env) -> u32 { - e.storage().instance().get(&DataKey::TotalAssets).unwrap() -} - pub fn get_assets(e: &Env) -> Vec { let total_assets = get_total_assets(e); let mut assets = Vec::new(e); @@ -59,6 +51,13 @@ pub fn get_assets(e: &Env) -> Vec { } assets } +pub fn set_total_assets(e: &Env, n: u32) { + e.storage().instance().set(&DataKey::TotalAssets, &n); +} + +pub fn get_total_assets(e: &Env) -> u32 { + e.storage().instance().get(&DataKey::TotalAssets).unwrap() +} // DeFindex Fee Receiver pub fn set_defindex_protocol_fee_receiver(e: &Env, address: &Address) { @@ -88,34 +87,43 @@ pub fn get_defindex_protocol_fee_rate(e: &Env) -> u32 { .unwrap() } - // DeFindex Factory pub fn set_factory(e: &Env, address: &Address) { - e.storage().instance().set(&DataKey::Factory, address); -} - -pub fn get_factory(e: &Env) -> Address { - e.storage().instance().get(&DataKey::Factory).unwrap() + e.storage() + .instance() + .set(&DataKey::DeFindexFactory, address); } -// Vault Share -pub fn set_vault_fee(e: &Env, vault_fee: &u32) { +// Soroswap Router +pub fn set_soroswap_router(e: &Env, address: &Address) { e.storage() .instance() - .set(&DataKey::VaultFee, vault_fee); + .set(&DataKey::SoroswapRouter, address); } -pub fn get_vault_fee(e: &Env) -> u32 { +pub fn get_soroswap_router(e: &Env) -> Address { e.storage() .instance() - .get(&DataKey::VaultFee) + .get(&DataKey::SoroswapRouter) .unwrap() } + +// Vault Share +pub fn set_vault_fee(e: &Env, vault_fee: &u32) { + e.storage().instance().set(&DataKey::VaultFee, vault_fee); +} + +pub fn get_vault_fee(e: &Env) -> u32 { + e.storage().instance().get(&DataKey::VaultFee).unwrap() +} + // Strategy Previous Balance pub fn set_report(e: &Env, strategy_address: &Address, report: &Report) { let key = DataKey::Report(strategy_address.clone()); - e.storage().persistent().set::(&key, report); + e.storage() + .persistent() + .set::(&key, report); e.storage() .persistent() .extend_ttl(&key, LEDGER_THRESHOLD, LEDGER_BUMP); @@ -131,6 +139,10 @@ pub fn get_report(e: &Env, strategy_address: &Address) -> Report { .extend_ttl(&key, LEDGER_THRESHOLD, LEDGER_BUMP); report } - None => Report { prev_balance: 0, gains_or_losses: 0, locked_fee: 0 }, + None => Report { + prev_balance: 0, + gains_or_losses: 0, + locked_fee: 0, + }, } -} \ No newline at end of file +} diff --git a/apps/contracts/vault/src/strategies.rs b/apps/contracts/vault/src/strategies.rs index c649937d..11cb267b 100644 --- a/apps/contracts/vault/src/strategies.rs +++ b/apps/contracts/vault/src/strategies.rs @@ -1,6 +1,6 @@ use defindex_strategy_core::DeFindexStrategyClient; -use soroban_sdk::{Address, Env, vec, IntoVal, Symbol}; use soroban_sdk::auth::{ContractContext, InvokerContractAuthEntry, SubContractInvocation}; +use soroban_sdk::{vec, Address, Env, IntoVal, Symbol}; use crate::report::Report; use crate::storage::{get_report, set_report}; @@ -140,7 +140,7 @@ pub fn unwind_from_strategy( report.report(result); set_report(e, strategy_address, &report); Ok(report) - }, + } Ok(Err(_)) | Err(_) => Err(ContractError::StrategyWithdrawError), } } @@ -165,8 +165,9 @@ pub fn invest_in_strategy( args: ( e.current_contract_address(), strategy_address, - amount.clone()).into_val(e), - + amount.clone(), + ) + .into_val(e), }, sub_invocations: vec![&e], }), diff --git a/apps/contracts/vault/src/test.rs b/apps/contracts/vault/src/test.rs index 86554c0e..bc1ec29b 100755 --- a/apps/contracts/vault/src/test.rs +++ b/apps/contracts/vault/src/test.rs @@ -1,12 +1,16 @@ #![cfg(test)] extern crate std; -use soroban_sdk::token::{ - StellarAssetClient as SorobanTokenAdminClient, TokenClient as SorobanTokenClient, +use soroban_sdk::{ + testutils::{Address as _, MockAuth, MockAuthInvoke}, + token::{StellarAssetClient as SorobanTokenAdminClient, TokenClient as SorobanTokenClient}, + vec as sorobanvec, Address, Env, IntoVal, String, Val, Vec, }; -use soroban_sdk::Val; -use soroban_sdk::{testutils::Address as _, vec as sorobanvec, Address, Env, String, Vec}; use std::vec; +use soroswap_setup::{ + create_soroswap_factory, create_soroswap_pool, create_soroswap_router, SoroswapRouterClient, +}; + // DeFindex Hodl Strategy Contract pub mod hodl_strategy { soroban_sdk::contractimport!( @@ -17,7 +21,7 @@ pub mod hodl_strategy { use hodl_strategy::HodlStrategyClient; pub fn create_hodl_strategy<'a>(e: &Env, asset: &Address) -> HodlStrategyClient<'a> { - let init_args: Vec= sorobanvec![e]; + let init_args: Vec = sorobanvec![e]; let args = (asset, init_args); HodlStrategyClient::new(e, &e.register(hodl_strategy::WASM, args)) } @@ -41,30 +45,26 @@ pub fn create_defindex_vault<'a>( defindex_protocol_receiver: Address, defindex_protocol_rate: u32, factory: Address, - vault_name: String, - vault_symbol: String, + soroswap_router: Address, + name_symbol: Vec, ) -> DeFindexVaultClient<'a> { - let args = (assets, manager, emergency_manager, vault_fee_receiver, vault_fee, defindex_protocol_receiver, defindex_protocol_rate, factory, vault_name, vault_symbol); + let args = ( + assets, + manager, + emergency_manager, + vault_fee_receiver, + vault_fee, + defindex_protocol_receiver, + defindex_protocol_rate, + factory, + soroswap_router, + name_symbol, + ); let address = &e.register(defindex_vault::WASM, args); let client = DeFindexVaultClient::new(e, address); client } -// DeFindex Factory Contract -// pub mod defindex_factory { -// soroban_sdk::contractimport!(file = "../target/wasm32-unknown-unknown/release/defindex_factory.optimized.wasm"); -// pub type DeFindexFactoryClient<'a> = Client<'a>; -// } -// use defindex_factory::DeFindexFactoryClient; - -// fn create_defindex_factory<'a>( -// e: & Env -// ) -> DeFindexFactoryClient<'a> { -// let address = &e.register_contract_wasm(None, defindex_factory::WASM); -// let client = DeFindexFactoryClient::new(e, address); -// client -// } - // Create Test Token pub(crate) fn create_token_contract<'a>(e: &Env, admin: &Address) -> SorobanTokenClient<'a> { SorobanTokenClient::new( @@ -81,43 +81,66 @@ pub(crate) fn get_token_admin_client<'a>( SorobanTokenAdminClient::new(e, address) } -pub(crate) fn create_strategy_params_token0(test: &DeFindexVaultTest) -> Vec { +pub(crate) fn create_strategy_params_token_0(test: &DeFindexVaultTest) -> Vec { sorobanvec![ - &test.env, + &test.env, Strategy { name: String::from_str(&test.env, "Strategy 1"), - address: test.strategy_client_token0.address.clone(), + address: test.strategy_client_token_0.address.clone(), paused: false, } ] } -pub(crate) fn create_strategy_params_token1(test: &DeFindexVaultTest) -> Vec { +pub(crate) fn create_strategy_params_token_1(test: &DeFindexVaultTest) -> Vec { sorobanvec![ &test.env, Strategy { name: String::from_str(&test.env, "Strategy 1"), - address: test.strategy_client_token1.address.clone(), + address: test.strategy_client_token_1.address.clone(), paused: false, } ] } +pub fn mock_mint( + env: &Env, + token_admin_client: &SorobanTokenAdminClient, + token_admin: &Address, + to: &Address, + amount: &i128, +) { + token_admin_client + .mock_auths(&[MockAuth { + address: &token_admin, + invoke: &MockAuthInvoke { + contract: &token_admin_client.address.clone(), + fn_name: "mint", + args: sorobanvec![&env, to.into_val(env), amount.into_val(env)], + sub_invokes: &[], + }, + }]) + .mint(&to, &amount); +} + pub struct DeFindexVaultTest<'a> { env: Env, defindex_factory: Address, - token0_admin_client: SorobanTokenAdminClient<'a>, - token0: SorobanTokenClient<'a>, - token0_admin: Address, - token1_admin_client: SorobanTokenAdminClient<'a>, - token1: SorobanTokenClient<'a>, - token1_admin: Address, + token_0_admin_client: SorobanTokenAdminClient<'a>, + token_0: SorobanTokenClient<'a>, + token_0_admin: Address, + token_1_admin_client: SorobanTokenAdminClient<'a>, + token_1: SorobanTokenClient<'a>, + token_1_admin: Address, emergency_manager: Address, vault_fee_receiver: Address, defindex_protocol_receiver: Address, manager: Address, - strategy_client_token0: HodlStrategyClient<'a>, - strategy_client_token1: HodlStrategyClient<'a>, + strategy_client_token_0: HodlStrategyClient<'a>, + strategy_client_token_1: HodlStrategyClient<'a>, + soroswap_router: SoroswapRouterClient<'a>, + // soroswap_factory: SoroswapFactoryClient<'a>, + // soroswap_pair: Address, } impl<'a> DeFindexVaultTest<'a> { @@ -133,37 +156,77 @@ impl<'a> DeFindexVaultTest<'a> { let defindex_protocol_receiver = Address::generate(&env); let manager = Address::generate(&env); - let token0_admin = Address::generate(&env); - let token0 = create_token_contract(&env, &token0_admin); + let token_0_admin = Address::generate(&env); + let token_0 = create_token_contract(&env, &token_0_admin); + + let token_1_admin = Address::generate(&env); + let token_1 = create_token_contract(&env, &token_1_admin); - let token1_admin = Address::generate(&env); - let token1 = create_token_contract(&env, &token1_admin); + let token_0_admin_client = get_token_admin_client(&env, &token_0.address.clone()); + let token_1_admin_client = get_token_admin_client(&env, &token_1.address.clone()); - let token0_admin_client = get_token_admin_client(&env, &token0.address.clone()); - let token1_admin_client = get_token_admin_client(&env, &token1.address.clone()); + // token_1_admin_client.mint(to, amount); - // token1_admin_client.mint(to, amount); + let strategy_client_token_0 = create_hodl_strategy(&env, &token_0.address); + let strategy_client_token_1 = create_hodl_strategy(&env, &token_1.address); - let strategy_client_token0 = create_hodl_strategy(&env, &token0.address); - let strategy_client_token1 = create_hodl_strategy(&env, &token1.address); + // Soroswap Setup + let soroswap_admin = Address::generate(&env); + + let amount_0: i128 = 1_000_000_000_000_000_000; + let amount_1: i128 = 4_000_000_000_000_000_000; + + mock_mint( + &env, + &token_0_admin_client, + &token_0_admin, + &soroswap_admin, + &amount_0, + ); + mock_mint( + &env, + &token_1_admin_client, + &token_1_admin, + &soroswap_admin, + &amount_1, + ); + + let soroswap_factory = create_soroswap_factory(&env, &soroswap_admin); + let soroswap_router = create_soroswap_router(&env, &soroswap_factory.address); env.budget().reset_unlimited(); - + + create_soroswap_pool( + &env, + &soroswap_router, + &soroswap_admin, + &token_0.address, + &token_1.address, + &amount_0, + &amount_1, + ); + // let soroswap_pair = soroswap_factory.get_pair(&token_0.address, &token_1.address); + + env.budget().reset_unlimited(); + DeFindexVaultTest { env, defindex_factory, - token0_admin_client, - token0, - token0_admin, - token1_admin_client, - token1, - token1_admin, + token_0_admin_client, + token_0, + token_0_admin, + token_1_admin_client, + token_1, + token_1_admin, emergency_manager, vault_fee_receiver, defindex_protocol_receiver, manager, - strategy_client_token0, - strategy_client_token1, + strategy_client_token_0, + strategy_client_token_1, + soroswap_router, + // soroswap_factory, + // soroswap_pair, } } @@ -176,4 +239,5 @@ impl<'a> DeFindexVaultTest<'a> { } } +mod soroswap_setup; mod vault; diff --git a/apps/contracts/vault/src/test/soroswap_setup.rs b/apps/contracts/vault/src/test/soroswap_setup.rs new file mode 100644 index 00000000..82c7971d --- /dev/null +++ b/apps/contracts/vault/src/test/soroswap_setup.rs @@ -0,0 +1,128 @@ +use soroban_sdk::{ + testutils::{MockAuth, MockAuthInvoke}, + vec, Address, BytesN, Env, IntoVal, +}; + +fn pair_contract_wasm(e: &Env) -> BytesN<32> { + soroban_sdk::contractimport!(file = "../soroswap/soroswap_pair.wasm"); + e.deployer().upload_contract_wasm(WASM) +} + +// SoroswapFactory Contract +mod factory { + soroban_sdk::contractimport!(file = "../soroswap/soroswap_factory.wasm"); + pub type SoroswapFactoryClient<'a> = Client<'a>; +} +pub use factory::SoroswapFactoryClient; + +pub fn create_soroswap_factory<'a>(e: &Env, setter: &Address) -> SoroswapFactoryClient<'a> { + let pair_hash = pair_contract_wasm(&e); + let factory_address = &e.register(factory::WASM, ()); + let factory = SoroswapFactoryClient::new(e, factory_address); + factory.initialize(&setter, &pair_hash); + factory +} + +// SoroswapRouter Contract +mod router { + soroban_sdk::contractimport!(file = "../soroswap/soroswap_router.wasm"); + pub type SoroswapRouterClient<'a> = Client<'a>; +} +pub use router::SoroswapRouterClient; + +// SoroswapRouter Contract +pub fn create_soroswap_router<'a>(e: &Env, factory: &Address) -> SoroswapRouterClient<'a> { + let router_address = &e.register(router::WASM, ()); + let router = SoroswapRouterClient::new(e, router_address); + router.initialize(factory); + router +} + +pub fn create_soroswap_pool<'a>( + e: &Env, + router: &SoroswapRouterClient, + to: &Address, + token_a: &Address, + token_b: &Address, + amount_a: &i128, + amount_b: &i128, +) -> (i128, i128, i128) { + let pair_address = router.router_pair_for(token_a, token_b); + router + .mock_auths(&[MockAuth { + address: &to, + invoke: &MockAuthInvoke { + contract: &router.address.clone(), + fn_name: "add_liquidity", + args: vec![ + &e, + token_a.into_val(e), + token_b.into_val(e), + amount_a.into_val(e), + amount_b.into_val(e), + 0i128.into_val(e), + 0i128.into_val(e), + to.into_val(e), + (e.ledger().timestamp() + 3600).into_val(e), + ], + sub_invokes: &[ + MockAuthInvoke { + contract: &token_a.clone(), + fn_name: "transfer", + args: vec![ + &e, + to.into_val(e), + pair_address.into_val(e), + amount_a.into_val(e), + ], + sub_invokes: &[], + }, + MockAuthInvoke { + contract: &token_b.clone(), + fn_name: "transfer", + args: vec![ + &e, + to.into_val(e), + pair_address.into_val(e), + amount_b.into_val(e), + ], + sub_invokes: &[], + }, + ], + }, + }]) + .add_liquidity( + token_a, + token_b, + &amount_a, + &amount_b, + &0i128, + &0i128, + &to, + &(e.ledger().timestamp() + 3600), + ) +} + +// // SoroswapRouter Contract +// mod aggregator { +// soroban_sdk::contractimport!(file = "../soroswap/soroswap_aggregator.wasm"); +// pub type SoroswapAggregatorClient<'a> = Client<'a>; +// } +// pub use aggregator::{SoroswapAggregatorClient, Adapter}; + +// pub fn create_soroswap_aggregator<'a>(e: &Env, admin: &Address, router: &Address) -> SoroswapAggregatorClient<'a> { +// let aggregator_address = &e.register(aggregator::WASM, ()); +// let aggregator = SoroswapAggregatorClient::new(e, aggregator_address); + +// let adapter_vec = vec![ +// e, +// Adapter { +// protocol_id: String::from_str(e, "soroswap"), +// address: router.clone(), +// paused: false, +// } +// ]; + +// aggregator.initialize(&admin, &adapter_vec); +// aggregator +// } diff --git a/apps/contracts/vault/src/test/vault/admin.rs b/apps/contracts/vault/src/test/vault/admin.rs index 19938fd9..28070953 100644 --- a/apps/contracts/vault/src/test/vault/admin.rs +++ b/apps/contracts/vault/src/test/vault/admin.rs @@ -4,7 +4,8 @@ use soroban_sdk::{ }; use crate::test::{ - create_defindex_vault, create_strategy_params_token0, create_strategy_params_token1, defindex_vault::AssetStrategySet, DeFindexVaultTest + create_defindex_vault, create_strategy_params_token_0, create_strategy_params_token_1, + defindex_vault::AssetStrategySet, DeFindexVaultTest, }; extern crate alloc; @@ -13,18 +14,18 @@ use alloc::vec; #[test] fn set_new_fee_receiver_by_fee_receiver() { let test = DeFindexVaultTest::setup(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); + let strategy_params_token_1 = create_strategy_params_token_1(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -38,8 +39,12 @@ fn set_new_fee_receiver_by_fee_receiver() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let fee_receiver_role = defindex_contract.get_fee_receiver(); assert_eq!(fee_receiver_role, test.vault_fee_receiver); @@ -79,20 +84,20 @@ fn set_new_fee_receiver_by_fee_receiver() { #[test] fn set_new_fee_receiver_by_manager() { let test = DeFindexVaultTest::setup(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); - // let tokens: Vec
= sorobanvec![&test.env, test.token0.address.clone(), test.token1.address.clone()]; + let strategy_params_token_0 = create_strategy_params_token_0(&test); + let strategy_params_token_1 = create_strategy_params_token_1(&test); + // let tokens: Vec
= sorobanvec![&test.env, test.token_0.address.clone(), test.token_1.address.clone()]; // let ratios: Vec = sorobanvec![&test.env, 1, 1]; let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -106,8 +111,12 @@ fn set_new_fee_receiver_by_manager() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let fee_receiver_role = defindex_contract.get_fee_receiver(); assert_eq!(fee_receiver_role, test.vault_fee_receiver); @@ -145,20 +154,20 @@ fn set_new_fee_receiver_by_manager() { #[should_panic(expected = "HostError: Error(Contract, #130)")] // Unauthorized fn set_new_fee_receiver_by_emergency_manager() { let test = DeFindexVaultTest::setup(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); - // let tokens: Vec
= sorobanvec![&test.env, test.token0.address.clone(), test.token1.address.clone()]; + let strategy_params_token_0 = create_strategy_params_token_0(&test); + let strategy_params_token_1 = create_strategy_params_token_1(&test); + // let tokens: Vec
= sorobanvec![&test.env, test.token_0.address.clone(), test.token_1.address.clone()]; // let ratios: Vec = sorobanvec![&test.env, 1, 1]; let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -172,34 +181,37 @@ fn set_new_fee_receiver_by_emergency_manager() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let fee_receiver_role = defindex_contract.get_fee_receiver(); assert_eq!(fee_receiver_role, test.vault_fee_receiver); let users = DeFindexVaultTest::generate_random_users(&test.env, 1); // Now Emergency Manager is setting the new fee receiver - defindex_contract - .set_fee_receiver(&test.emergency_manager, &users[0]); + defindex_contract.set_fee_receiver(&test.emergency_manager, &users[0]); } #[test] #[should_panic(expected = "HostError: Error(Contract, #130)")] // Unauthorized fn set_new_fee_receiver_invalid_sender() { let test = DeFindexVaultTest::setup(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); + let strategy_params_token_1 = create_strategy_params_token_1(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -213,32 +225,35 @@ fn set_new_fee_receiver_invalid_sender() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let fee_receiver_role = defindex_contract.get_fee_receiver(); assert_eq!(fee_receiver_role, test.vault_fee_receiver); let users = DeFindexVaultTest::generate_random_users(&test.env, 1); // Trying to set the new fee receiver with an invalid sender - defindex_contract - .set_fee_receiver(&users[0], &users[0]); + defindex_contract.set_fee_receiver(&users[0], &users[0]); } #[test] fn set_new_manager_by_manager() { let test = DeFindexVaultTest::setup(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); + let strategy_params_token_1 = create_strategy_params_token_1(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -252,8 +267,12 @@ fn set_new_manager_by_manager() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let manager_role = defindex_contract.get_manager(); assert_eq!(manager_role, test.manager); diff --git a/apps/contracts/vault/src/test/vault/budget.rs b/apps/contracts/vault/src/test/vault/budget.rs index 06dfdef3..3c28fece 100644 --- a/apps/contracts/vault/src/test/vault/budget.rs +++ b/apps/contracts/vault/src/test/vault/budget.rs @@ -1,266 +1,231 @@ extern crate std; -use crate:: - test::{ - create_defindex_vault, - create_strategy_params_token0, - create_strategy_params_token1, +use crate::test::{ + create_defindex_vault, create_strategy_params_token_0, create_strategy_params_token_1, defindex_vault::{ - ActionType, - AssetInvestmentAllocation, - AssetStrategySet, - Instruction, - OptionalSwapDetailsExactIn, - OptionalSwapDetailsExactOut, - StrategyAllocation, - }, DeFindexVaultTest - - }; -use soroban_sdk::{String, Vec, vec as sorobanvec}; + AssetInvestmentAllocation, AssetStrategySet, Instruction, StrategyAllocation, + }, + DeFindexVaultTest, +}; +use soroban_sdk::{vec as sorobanvec, String, Vec}; #[test] fn budget() { - let test = DeFindexVaultTest::setup(); - - test.env.budget().reset_unlimited(); - - test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); - - let assets: Vec = sorobanvec![ - &test.env, - AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() - }, - AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() - } - ]; + let test = DeFindexVaultTest::setup(); + + test.env.budget().reset_unlimited(); + + 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); + + 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 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(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + &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 mem = test.env.budget().memory_bytes_cost(); + let cpu = test.env.budget().cpu_instruction_cost(); + std::println!( + "create_defindex_vault() | cpu: {}, mem: {}", + cpu, + mem + ); + + test.env.budget().reset_unlimited(); + + // deposit + let amount0 = 5_0_000_000i128; + let amount1 = 4_0_000_000i128; + + let users = DeFindexVaultTest::generate_random_users(&test.env, 2); + + test.token_0_admin_client.mint(&users[0], &99987654321i128); + test.token_1_admin_client.mint(&users[0], &99987654321i128); + + let _ = defindex_contract.deposit( + &sorobanvec![&test.env, amount0, amount1], + &sorobanvec![&test.env, amount0, amount1], + &users[0], + &false, + ); + + let mem = test.env.budget().memory_bytes_cost(); + let cpu = test.env.budget().cpu_instruction_cost(); + std::println!( + "deposit() | cpu: {}, mem: {}", + cpu, + mem + ); + + test.env.budget().reset_unlimited(); + // deposit + let amount0 = 5_0_000_000i128; + let amount1 = 4_0_000_000i128; + + let users = DeFindexVaultTest::generate_random_users(&test.env, 2); + + test.token_0_admin_client.mint(&users[0], &99987654321i128); + test.token_1_admin_client.mint(&users[0], &99987654321i128); + + let _ = defindex_contract.deposit( + &sorobanvec![&test.env, amount0, amount1], + &sorobanvec![&test.env, amount0, amount1], + &users[0], + &true, ); - let mem = test.env.budget().memory_bytes_cost(); - let cpu = test.env.budget().cpu_instruction_cost(); - std::println!("create_defindex_vault() | cpu: {}, mem: {}", cpu, mem); - - test.env.budget().reset_unlimited(); - - // deposit - let amount0 = 5_0_000_000i128; - let amount1 = 4_0_000_000i128; - - - let users = DeFindexVaultTest::generate_random_users(&test.env, 2); - - test.token0_admin_client.mint(&users[0], &99987654321i128); - test.token1_admin_client.mint(&users[0], &99987654321i128); - - let _ = defindex_contract.deposit( - &sorobanvec![&test.env, amount0, amount1], - &sorobanvec![&test.env, amount0, amount1], - &users[0], - &false, - ); - - let mem = test.env.budget().memory_bytes_cost(); - let cpu = test.env.budget().cpu_instruction_cost(); - std::println!("deposit() | cpu: {}, mem: {}", cpu, mem); - - test.env.budget().reset_unlimited(); - // deposit - let amount0 = 5_0_000_000i128; - let amount1 = 4_0_000_000i128; - - - let users = DeFindexVaultTest::generate_random_users(&test.env, 2); - - test.token0_admin_client.mint(&users[0], &99987654321i128); - test.token1_admin_client.mint(&users[0], &99987654321i128); - - let _ = defindex_contract.deposit( - &sorobanvec![&test.env, amount0, amount1], - &sorobanvec![&test.env, amount0, amount1], - &users[0], - &true, - ); - - let mem = test.env.budget().memory_bytes_cost(); - let cpu = test.env.budget().cpu_instruction_cost(); - std::println!("deposit_and_invest() | cpu: {}, mem: {}", cpu, mem); - - test.env.budget().reset_unlimited(); - - // withdraw - let _ = defindex_contract.withdraw( - &5_0_000i128, - &users[0], - ); - - let mem = test.env.budget().memory_bytes_cost(); - let cpu = test.env.budget().cpu_instruction_cost(); - std::println!("withdraw() | cpu: {}, mem: {}", cpu, mem); - - test.env.budget().reset_unlimited(); - - // invest - let asset_investments = sorobanvec![ - &test.env, - Some(AssetInvestmentAllocation { - asset: test.token0.address.clone(), - strategy_allocations: sorobanvec![ - &test.env, - Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 100, - }), - ]}), - Some(AssetInvestmentAllocation { - asset: test.token1.address.clone(), - strategy_allocations: sorobanvec![ + + let mem = test.env.budget().memory_bytes_cost(); + let cpu = test.env.budget().cpu_instruction_cost(); + std::println!("deposit_and_invest() | cpu: {}, mem: {}", cpu, mem); + + test.env.budget().reset_unlimited(); + + // withdraw + let _ = defindex_contract.withdraw(&5_0_000i128, &users[0]); + + let mem = test.env.budget().memory_bytes_cost(); + let cpu = test.env.budget().cpu_instruction_cost(); + std::println!( + "withdraw() | cpu: {}, mem: {}", + cpu, + mem + ); + + test.env.budget().reset_unlimited(); + + // invest + let asset_investments = sorobanvec![ &test.env, - Some(StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), - amount: 200, + 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: 100, + }), + ] }), - ]})]; + 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: 200, + }), + ] + }) + ]; - let _ = defindex_contract.invest( - &asset_investments, - ); - let mem = test.env.budget().memory_bytes_cost(); - let cpu = test.env.budget().cpu_instruction_cost(); - std::println!("invest() | cpu: {}, mem: {}", cpu, mem); + let _ = defindex_contract.invest(&asset_investments); + let mem = test.env.budget().memory_bytes_cost(); + let cpu = test.env.budget().cpu_instruction_cost(); + std::println!( + "invest() | cpu: {}, mem: {}", + cpu, + mem + ); - test.env.budget().reset_unlimited(); + test.env.budget().reset_unlimited(); - // rebalance withdraw - let withdraw_instructions = sorobanvec![ + // rebalance withdraw + let withdraw_instructions = sorobanvec![ &test.env, - Instruction { - action: ActionType::Withdraw, - strategy: Some(test.strategy_client_token0.address.clone()), - amount: Some(100), - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, + Instruction::Withdraw(test.strategy_client_token_0.address.clone(), 100), ]; - let _ = defindex_contract.rebalance(&withdraw_instructions); - let mem = test.env.budget().memory_bytes_cost(); - let cpu = test.env.budget().cpu_instruction_cost(); - std::println!("rebalance_withdraw() | cpu: {}, mem: {}", cpu, mem); + let _ = defindex_contract.rebalance(&withdraw_instructions); + let mem = test.env.budget().memory_bytes_cost(); + let cpu = test.env.budget().cpu_instruction_cost(); + std::println!( + "rebalance_withdraw() | cpu: {}, mem: {}", + cpu, + mem + ); + + test.env.budget().reset_unlimited(); - test.env.budget().reset_unlimited(); + // rebalance invest - // rebalance invest - - let invest_instructions = sorobanvec![ + let invest_instructions = sorobanvec![ &test.env, - Instruction { - action: ActionType::Invest, - strategy: Some(test.strategy_client_token0.address.clone()), - amount: Some(100), - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, + Instruction::Invest(test.strategy_client_token_0.address.clone(), 100), ]; - let _ = defindex_contract.rebalance(&invest_instructions); - let mem = test.env.budget().memory_bytes_cost(); - let cpu = test.env.budget().cpu_instruction_cost(); - std::println!("rebalance_invest() | cpu: {}, mem: {}", cpu, mem); - test.env.budget().reset_unlimited(); + let _ = defindex_contract.rebalance(&invest_instructions); + let mem = test.env.budget().memory_bytes_cost(); + let cpu = test.env.budget().cpu_instruction_cost(); + std::println!( + "rebalance_invest() | cpu: {}, mem: {}", + cpu, + mem + ); + + test.env.budget().reset_unlimited(); - //Rebalance with several instructions one strategy + //Rebalance with several instructions one strategy - let several_instructions_one_strategy = sorobanvec![ + let several_instructions_one_strategy = sorobanvec![ &test.env, - Instruction { - action: ActionType::Invest, - strategy: Some(test.strategy_client_token0.address.clone()), - amount: Some(100), - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, - Instruction { - action: ActionType::Invest, - strategy: Some(test.strategy_client_token0.address.clone()), - amount: Some(100), - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, - Instruction { - action: ActionType::Invest, - strategy: Some(test.strategy_client_token0.address.clone()), - amount: Some(100), - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, - Instruction { - action: ActionType::Invest, - strategy: Some(test.strategy_client_token0.address.clone()), - amount: Some(100), - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, + Instruction::Invest(test.strategy_client_token_0.address.clone(), 100), + Instruction::Invest(test.strategy_client_token_0.address.clone(), 100), + Instruction::Invest(test.strategy_client_token_0.address.clone(), 100), + Instruction::Invest(test.strategy_client_token_0.address.clone(), 100), ]; - let _ = defindex_contract.rebalance(&several_instructions_one_strategy); - let mem = test.env.budget().memory_bytes_cost(); - let cpu = test.env.budget().cpu_instruction_cost(); - std::println!("rebalance_invest_several_instructions_one_strategy() | cpu: {}, mem: {}", cpu, mem); - test.env.budget().reset_unlimited(); + let _ = defindex_contract.rebalance(&several_instructions_one_strategy); + let mem = test.env.budget().memory_bytes_cost(); + let cpu = test.env.budget().cpu_instruction_cost(); + std::println!( + "rebalance_invest_several_instructions_one_strategy() | cpu: {}, mem: {}", + cpu, + mem + ); + + test.env.budget().reset_unlimited(); - // Rebalance several instructions two strategies + // Rebalance several instructions two strategies - let several_instructions_two_strategy = sorobanvec![ + let several_instructions_two_strategy = sorobanvec![ &test.env, - Instruction { - action: ActionType::Invest, - strategy: Some(test.strategy_client_token1.address.clone()), - amount: Some(100), - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, - Instruction { - action: ActionType::Invest, - strategy: Some(test.strategy_client_token1.address.clone()), - amount: Some(100), - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, - Instruction { - action: ActionType::Invest, - strategy: Some(test.strategy_client_token0.address.clone()), - amount: Some(100), - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, - Instruction { - action: ActionType::Invest, - strategy: Some(test.strategy_client_token0.address.clone()), - amount: Some(100), - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, + Instruction::Invest(test.strategy_client_token_1.address.clone(), 100), + Instruction::Invest(test.strategy_client_token_1.address.clone(), 100), + Instruction::Invest(test.strategy_client_token_0.address.clone(), 100), + Instruction::Invest(test.strategy_client_token_0.address.clone(), 100), ]; - let _ = defindex_contract.rebalance(&several_instructions_two_strategy); - let mem = test.env.budget().memory_bytes_cost(); - let cpu = test.env.budget().cpu_instruction_cost(); - std::println!("rebalance_invest_several_instructions_two_strategy() | cpu: {}, mem: {}", cpu, mem); - test.env.budget().reset_unlimited(); + let _ = defindex_contract.rebalance(&several_instructions_two_strategy); + let mem = test.env.budget().memory_bytes_cost(); + let cpu = test.env.budget().cpu_instruction_cost(); + std::println!( + "rebalance_invest_several_instructions_two_strategy() | cpu: {}, mem: {}", + cpu, + mem + ); + test.env.budget().reset_unlimited(); } diff --git a/apps/contracts/vault/src/test/vault/deposit.rs b/apps/contracts/vault/src/test/vault/deposit.rs index 72f1fd82..e2d8c3ca 100644 --- a/apps/contracts/vault/src/test/vault/deposit.rs +++ b/apps/contracts/vault/src/test/vault/deposit.rs @@ -1,27 +1,30 @@ use soroban_sdk::{vec as sorobanvec, InvokeError, Map, String, Vec}; -use crate::test::defindex_vault::{AssetStrategySet, ContractError, CurrentAssetInvestmentAllocation, StrategyAllocation}; +use crate::test::defindex_vault::{ + AssetStrategySet, ContractError, CurrentAssetInvestmentAllocation, StrategyAllocation, +}; use crate::test::{ - create_defindex_vault, create_strategy_params_token0, create_strategy_params_token1, DeFindexVaultTest + create_defindex_vault, create_strategy_params_token_0, create_strategy_params_token_1, + DeFindexVaultTest, }; #[test] fn amounts_desired_less_length() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + 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.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -35,8 +38,12 @@ fn amounts_desired_less_length() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount = 1000i128; @@ -57,15 +64,15 @@ fn amounts_desired_less_length() { fn amounts_desired_more_length() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); - // let strategy_params_token1 = create_strategy_params_token1(&test); + 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.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; @@ -79,8 +86,12 @@ fn amounts_desired_more_length() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount = 1000i128; @@ -101,21 +112,21 @@ fn amounts_desired_more_length() { fn amounts_min_less_length() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + 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.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } - ]; + ]; let defindex_contract = create_defindex_vault( &test.env, @@ -127,8 +138,12 @@ fn amounts_min_less_length() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount = 1000i128; @@ -144,25 +159,24 @@ fn amounts_min_less_length() { assert_eq!(response, Err(Ok(ContractError::WrongAmountsLength))); } - // test deposit amount min more length #[test] fn amounts_min_more_length() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + 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.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -176,8 +190,12 @@ fn amounts_min_more_length() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount = 1000i128; @@ -198,19 +216,19 @@ fn amounts_min_more_length() { fn amounts_desired_negative() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + 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.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -224,8 +242,12 @@ fn amounts_desired_negative() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount = 1000i128; @@ -241,19 +263,19 @@ fn amounts_desired_negative() { assert_eq!(response, Err(Ok(ContractError::NegativeNotAllowed))); } -// test deposit one asset success +// test deposit one asset success #[test] fn one_asset_success() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); // initialize with 1 assets let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; @@ -267,16 +289,20 @@ fn one_asset_success() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount = 123456789i128; let users = DeFindexVaultTest::generate_random_users(&test.env, 1); // Balances before deposit - test.token0_admin_client.mint(&users[0], &amount); - let user_balance = test.token0.balance(&users[0]); + test.token_0_admin_client.mint(&users[0], &amount); + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, amount); let df_balance = defindex_contract.balance(&users[0]); @@ -287,52 +313,54 @@ fn one_asset_success() { &sorobanvec![&test.env, amount], &sorobanvec![&test.env, amount], &users[0], - &false, + &false, ); // check balances after deposit let df_balance = defindex_contract.balance(&users[0]); assert_eq!(df_balance, amount - 1000); - let user_balance = test.token0.balance(&users[0]); + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, 0i128); // check that all the assets are in the vault - let vault_balance = test.token0.balance(&defindex_contract.address); + let vault_balance = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance, amount); - + // check total manage funds let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 0, //funds has not been invested yet! - }]; - total_managed_funds_expected.set(test.token0.address.clone(), + let strategy_investments_expected = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, //funds has not been invested yet! + } + ]; + total_managed_funds_expected.set( + test.token_0.address.clone(), CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), + asset: test.token_0.address.clone(), total_amount: amount, idle_amount: amount, invested_amount: 0i128, strategy_allocations: strategy_investments_expected, - } + }, ); - - // check that fetch_total_managed_funds returns correct amount let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); - // check current idle funds, + // check current idle funds, let mut expected_idle_funds_map = Map::new(&test.env); - expected_idle_funds_map.set(test.token0.address.clone(), amount); + expected_idle_funds_map.set(test.token_0.address.clone(), amount); let current_idle_funds = defindex_contract.fetch_current_idle_funds(); assert_eq!(current_idle_funds, expected_idle_funds_map); //map shuould be map let mut expected_map = Map::new(&test.env); - expected_map.set(test.token0.address.clone(), 0i128); + expected_map.set(test.token_0.address.clone(), 0i128); // check that current invested funds is now 0, funds still in idle funds let current_invested_funds = defindex_contract.fetch_current_invested_funds(); @@ -340,8 +368,8 @@ fn one_asset_success() { // Now user deposits for the second time let amount2 = 987654321i128; - test.token0_admin_client.mint(&users[0], &amount2); - let user_balance = test.token0.balance(&users[0]); + test.token_0_admin_client.mint(&users[0], &amount2); + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, amount2); // deposit @@ -354,52 +382,52 @@ fn one_asset_success() { //map shuould be map let mut expected_map = Map::new(&test.env); - expected_map.set(test.token0.address.clone(), amount + amount2); + expected_map.set(test.token_0.address.clone(), amount + amount2); // check balances after deposit let df_balance = defindex_contract.balance(&users[0]); assert_eq!(df_balance, amount + amount2 - 1000); - let user_balance = test.token0.balance(&users[0]); + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, 0i128); - + // check that all the assets are in the vault - let vault_balance = test.token0.balance(&defindex_contract.address); + let vault_balance = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance, amount + amount2); - + // check that fetch_total_managed_funds returns correct amount let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 0, // funds have not been invested yet! - }]; - total_managed_funds_expected.set(test.token0.address.clone(), + let strategy_investments_expected = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, // funds have not been invested yet! + } + ]; + total_managed_funds_expected.set( + test.token_0.address.clone(), CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), + asset: test.token_0.address.clone(), total_amount: amount + amount2, idle_amount: amount + amount2, invested_amount: 0i128, strategy_allocations: strategy_investments_expected, - } + }, ); let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); - + // check current idle funds let current_idle_funds = defindex_contract.fetch_current_idle_funds(); assert_eq!(current_idle_funds, expected_map); - //map shuould be map let mut expected_map = Map::new(&test.env); - expected_map.set(test.token0.address.clone(), 0i128); - + expected_map.set(test.token_0.address.clone(), 0i128); + // check that current invested funds is now 0, funds still in idle funds let current_invested_funds = defindex_contract.fetch_current_invested_funds(); assert_eq!(current_invested_funds, expected_map); - - - } // test deposit one asset with minimum more than desired @@ -407,14 +435,14 @@ fn one_asset_success() { fn one_asset_min_more_than_desired() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); // initialize with 1 assets let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; @@ -428,23 +456,27 @@ fn one_asset_min_more_than_desired() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount = 123456789i128; let users = DeFindexVaultTest::generate_random_users(&test.env, 1); // Balances before deposit - test.token0_admin_client.mint(&users[0], &amount); - let user_balance = test.token0.balance(&users[0]); + test.token_0_admin_client.mint(&users[0], &amount); + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, amount); let df_balance = defindex_contract.balance(&users[0]); assert_eq!(df_balance, 0i128); // deposit - let result=defindex_contract.try_deposit( + let result = defindex_contract.try_deposit( &sorobanvec![&test.env, amount], &sorobanvec![&test.env, amount + 1], &users[0], @@ -452,7 +484,6 @@ fn one_asset_min_more_than_desired() { ); // this should fail assert_eq!(result, Err(Ok(ContractError::InsufficientAmount))); - } // test deposit of several asset, considering different proportion of assets @@ -460,19 +491,19 @@ fn one_asset_min_more_than_desired() { fn several_assets_success() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + 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.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -486,8 +517,12 @@ fn several_assets_success() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount0 = 123456789i128; let amount1 = 987654321i128; @@ -495,18 +530,18 @@ fn several_assets_success() { let users = DeFindexVaultTest::generate_random_users(&test.env, 2); // Balances before deposit - test.token0_admin_client.mint(&users[0], &amount0); - test.token1_admin_client.mint(&users[0], &amount1); - let user_balance0 = test.token0.balance(&users[0]); + test.token_0_admin_client.mint(&users[0], &amount0); + test.token_1_admin_client.mint(&users[0], &amount1); + let user_balance0 = test.token_0.balance(&users[0]); assert_eq!(user_balance0, amount0); - let user_balance1 = test.token1.balance(&users[0]); + 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 - let deposit_result=defindex_contract.deposit( + let deposit_result = defindex_contract.deposit( &sorobanvec![&test.env, amount0, amount1], &sorobanvec![&test.env, amount0, amount1], &users[0], @@ -514,7 +549,10 @@ fn several_assets_success() { ); // check deposit result - assert_eq!(deposit_result, (sorobanvec![&test.env, amount0, amount1], amount0 + amount1)); + assert_eq!( + deposit_result, + (sorobanvec![&test.env, amount0, amount1], amount0 + amount1) + ); // check balances after deposit let df_balance = defindex_contract.balance(&users[0]); @@ -524,88 +562,93 @@ fn several_assets_success() { // check that the vault holds 1000 shares let vault_df_shares = defindex_contract.balance(&defindex_contract.address); assert_eq!(vault_df_shares, 1000i128); - - let user_balance0 = test.token0.balance(&users[0]); - assert_eq!(user_balance0,0i128); - let user_balance1 = test.token1.balance(&users[0]); - assert_eq!(user_balance1,0i128); + + let user_balance0 = test.token_0.balance(&users[0]); + assert_eq!(user_balance0, 0i128); + let user_balance1 = test.token_1.balance(&users[0]); + assert_eq!(user_balance1, 0i128); // check vault balance of asset 0 - let vault_balance0 = test.token0.balance(&defindex_contract.address); + let vault_balance0 = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance0, amount0); // check vault balance of asset 1 - let vault_balance1 = test.token1.balance(&defindex_contract.address); + let vault_balance1 = test.token_1.balance(&defindex_contract.address); assert_eq!(vault_balance1, amount1); // check total managed funds let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected_token_0 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 0, // funds have not been invested yet! - }]; - let strategy_investments_expected_token_1 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), - amount: 0, // funds have not been invested yet! - }]; - total_managed_funds_expected.set(test.token0.address.clone(), + let strategy_investments_expected_token_0 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, // funds have not been invested yet! + } + ]; + let strategy_investments_expected_token_1 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: 0, // funds have not been invested yet! + } + ]; + total_managed_funds_expected.set( + test.token_0.address.clone(), CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), + asset: test.token_0.address.clone(), total_amount: amount0, idle_amount: amount0, invested_amount: 0i128, strategy_allocations: strategy_investments_expected_token_0, - } + }, ); - total_managed_funds_expected.set(test.token1.address.clone(), + total_managed_funds_expected.set( + test.token_1.address.clone(), CurrentAssetInvestmentAllocation { - asset: test.token1.address.clone(), + asset: test.token_1.address.clone(), total_amount: amount1, idle_amount: amount1, invested_amount: 0i128, strategy_allocations: strategy_investments_expected_token_1, - } + }, ); let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); - //map shuould be map - let mut expected_map = Map::new(&test.env); - expected_map.set(test.token0.address.clone(), amount0); - expected_map.set(test.token1.address.clone(), amount1); - + //map shuould be map + let mut expected_map = Map::new(&test.env); + expected_map.set(test.token_0.address.clone(), amount0); + expected_map.set(test.token_1.address.clone(), amount1); // check current idle funds let current_idle_funds = defindex_contract.fetch_current_idle_funds(); assert_eq!(current_idle_funds, expected_map); - + //map shuould be map let mut expected_map = Map::new(&test.env); - expected_map.set(test.token0.address.clone(), 0i128); - expected_map.set(test.token1.address.clone(), 0i128); + expected_map.set(test.token_0.address.clone(), 0i128); + expected_map.set(test.token_1.address.clone(), 0i128); // check that current invested funds is now 0, funds still in idle funds let current_invested_funds = defindex_contract.fetch_current_invested_funds(); assert_eq!(current_invested_funds, expected_map); - // new user wants to do a deposit with more assets 0 than the proportion, but with minium amount 0 // multiply amount0 by 2 - let amount0_new = amount0*2 +100 ; - let amount1_new = amount1*2; + let amount0_new = amount0 * 2 + 100; + let amount1_new = amount1 * 2; // mint this to user 1 - test.token0_admin_client.mint(&users[1], &amount0_new); - test.token1_admin_client.mint(&users[1], &amount1_new); + test.token_0_admin_client.mint(&users[1], &amount0_new); + test.token_1_admin_client.mint(&users[1], &amount1_new); // check user balances - let user_balance0 = test.token0.balance(&users[1]); + let user_balance0 = test.token_0.balance(&users[1]); assert_eq!(user_balance0, amount0_new); - let user_balance1 = test.token1.balance(&users[1]); + let user_balance1 = test.token_1.balance(&users[1]); assert_eq!(user_balance1, amount1_new); - // user 1 deposits - let deposit_result=defindex_contract.deposit( + let deposit_result = defindex_contract.deposit( &sorobanvec![&test.env, amount0_new, amount1_new], &sorobanvec![&test.env, 0i128, 0i128], &users[1], @@ -615,91 +658,103 @@ fn several_assets_success() { // check deposit result. Ok((amounts, shares_to_mint)) // Vec, i128 - assert_eq!(deposit_result, (sorobanvec![&test.env, amount0*2, amount1*2], amount0*2 + amount1*2)); - + assert_eq!( + deposit_result, + ( + sorobanvec![&test.env, amount0 * 2, amount1 * 2], + amount0 * 2 + amount1 * 2 + ) + ); // check balances after deposit let df_balance = defindex_contract.balance(&users[1]); - assert_eq!(df_balance, 2*(amount0 + amount1)); + assert_eq!(df_balance, 2 * (amount0 + amount1)); - let user_balance0 = test.token0.balance(&users[1]); - assert_eq!(user_balance0, amount0_new - 2*amount0); + let user_balance0 = test.token_0.balance(&users[1]); + assert_eq!(user_balance0, amount0_new - 2 * amount0); - let user_balance1 = test.token1.balance(&users[1]); - assert_eq!(user_balance1, amount1_new - 2*amount1); + let user_balance1 = test.token_1.balance(&users[1]); + assert_eq!(user_balance1, amount1_new - 2 * amount1); // check vault balance of asset 0 - let vault_balance0 = test.token0.balance(&defindex_contract.address); - assert_eq!(vault_balance0, 3*amount0); + let vault_balance0 = test.token_0.balance(&defindex_contract.address); + assert_eq!(vault_balance0, 3 * amount0); // check vault balance of asset 1 - let vault_balance1 = test.token1.balance(&defindex_contract.address); - assert_eq!(vault_balance1, 3*amount1); + let vault_balance1 = test.token_1.balance(&defindex_contract.address); + assert_eq!(vault_balance1, 3 * amount1); - // check total managed funds let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected_token_0 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 0, // funds have not been invested yet! - }]; - let strategy_investments_expected_token_1 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), - amount: 0, // funds have not been invested yet! - }]; - total_managed_funds_expected.set(test.token0.address.clone(), + let strategy_investments_expected_token_0 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, // funds have not been invested yet! + } + ]; + let strategy_investments_expected_token_1 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: 0, // funds have not been invested yet! + } + ]; + total_managed_funds_expected.set( + test.token_0.address.clone(), CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), - total_amount: 3*amount0, - idle_amount: 3*amount0, + asset: test.token_0.address.clone(), + total_amount: 3 * amount0, + idle_amount: 3 * amount0, invested_amount: 0i128, strategy_allocations: strategy_investments_expected_token_0, - } + }, ); - total_managed_funds_expected.set(test.token1.address.clone(), + total_managed_funds_expected.set( + test.token_1.address.clone(), CurrentAssetInvestmentAllocation { - asset: test.token1.address.clone(), - total_amount: 3*amount1, - idle_amount: 3*amount1, + asset: test.token_1.address.clone(), + total_amount: 3 * amount1, + idle_amount: 3 * amount1, invested_amount: 0i128, strategy_allocations: strategy_investments_expected_token_1, - } + }, ); let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); //map shuould be map let mut expected_map = Map::new(&test.env); - expected_map.set(test.token0.address.clone(), 3*amount0); - expected_map.set(test.token1.address.clone(), 3*amount1); + expected_map.set(test.token_0.address.clone(), 3 * amount0); + expected_map.set(test.token_1.address.clone(), 3 * amount1); // check current idle funds let current_idle_funds = defindex_contract.fetch_current_idle_funds(); assert_eq!(current_idle_funds, expected_map); //map shuould be map let mut expected_map = Map::new(&test.env); - expected_map.set(test.token0.address.clone(), 0i128); - expected_map.set(test.token1.address.clone(), 0i128); + expected_map.set(test.token_0.address.clone(), 0i128); + expected_map.set(test.token_1.address.clone(), 0i128); // check that current invested funds is now 0, funds still in idle funds let current_invested_funds = defindex_contract.fetch_current_invested_funds(); assert_eq!(current_invested_funds, expected_map); // we will repeat one more time, now enforcing the first asset - let amount0_new = amount0*2; - let amount1_new = amount1*2+100; + let amount0_new = amount0 * 2; + let amount1_new = amount1 * 2 + 100; // mint this to user 1 - test.token0_admin_client.mint(&users[1], &amount0_new); - test.token1_admin_client.mint(&users[1], &amount1_new); - + test.token_0_admin_client.mint(&users[1], &amount0_new); + test.token_1_admin_client.mint(&users[1], &amount1_new); + // check user balances - let user_balance0 = test.token0.balance(&users[1]); + let user_balance0 = test.token_0.balance(&users[1]); assert_eq!(user_balance0, 100 + amount0_new); // we still have 100 from before - let user_balance1 = test.token1.balance(&users[1]); + let user_balance1 = test.token_1.balance(&users[1]); assert_eq!(user_balance1, amount1_new); // user 1 deposits - let deposit_result=defindex_contract.deposit( + let deposit_result = defindex_contract.deposit( &sorobanvec![&test.env, amount0_new, amount1_new], &sorobanvec![&test.env, 0i128, 0i128], &users[1], @@ -708,8 +763,13 @@ fn several_assets_success() { // check deposit result. Ok((amounts, shares_to_mint)) // Vec, i128 - assert_eq!(deposit_result, (sorobanvec![&test.env, amount0*2, amount1*2], amount0*2 + amount1*2)); - + assert_eq!( + deposit_result, + ( + sorobanvec![&test.env, amount0 * 2, amount1 * 2], + amount0 * 2 + amount1 * 2 + ) + ); } // test deposit of several asset, imposing a minimum amount greater than optimal for asset 0 @@ -717,19 +777,19 @@ fn several_assets_success() { fn several_assets_min_greater_than_optimal() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + 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.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -743,8 +803,12 @@ fn several_assets_min_greater_than_optimal() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount0 = 123456789i128; let amount1 = 987654321i128; @@ -752,18 +816,18 @@ fn several_assets_min_greater_than_optimal() { let users = DeFindexVaultTest::generate_random_users(&test.env, 2); // Balances before deposit - test.token0_admin_client.mint(&users[0], &amount0); - test.token1_admin_client.mint(&users[0], &amount1); - let user_balance0 = test.token0.balance(&users[0]); + test.token_0_admin_client.mint(&users[0], &amount0); + test.token_1_admin_client.mint(&users[0], &amount1); + let user_balance0 = test.token_0.balance(&users[0]); assert_eq!(user_balance0, amount0); - let user_balance1 = test.token1.balance(&users[0]); + 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 - let deposit_result=defindex_contract.try_deposit( + let deposit_result = defindex_contract.try_deposit( &sorobanvec![&test.env, amount0, amount1], &sorobanvec![&test.env, amount0 + 1, amount1], &users[0], @@ -772,7 +836,7 @@ fn several_assets_min_greater_than_optimal() { // this should fail assert_eq!(deposit_result, Err(Ok(ContractError::InsufficientAmount))); - + // now we manage to deposit defindex_contract.deposit( &sorobanvec![&test.env, amount0, amount1], @@ -782,21 +846,21 @@ fn several_assets_min_greater_than_optimal() { ); // check deposit result - + // and now will try again with minimum more than optimal // new user wants to do a deposit with more assets 0 than the proportion, but with minium amount 0 // multiply amount0 by 2 - let amount0_new = amount0*2 +100 ; - let amount1_new = amount1*2; + let amount0_new = amount0 * 2 + 100; + let amount1_new = amount1 * 2; - // mint this to user - test.token0_admin_client.mint(&users[0], &amount0_new); - test.token1_admin_client.mint(&users[0], &amount1_new); + // mint this to user + test.token_0_admin_client.mint(&users[0], &amount0_new); + test.token_1_admin_client.mint(&users[0], &amount1_new); - let deposit_result=defindex_contract.try_deposit( + let deposit_result = defindex_contract.try_deposit( &sorobanvec![&test.env, amount0_new, amount1_new], - &sorobanvec![&test.env, amount0*2+1, amount1*2], + &sorobanvec![&test.env, amount0 * 2 + 1, amount1 * 2], &users[0], &false, ); @@ -804,27 +868,26 @@ fn several_assets_min_greater_than_optimal() { // this should fail assert_eq!(deposit_result, Err(Ok(ContractError::InsufficientAmount))); - } //test deposit amounts_min greater than amounts_desired #[test] -fn amounts_min_greater_than_amounts_desired(){ +fn amounts_min_greater_than_amounts_desired() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + 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.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -838,8 +901,12 @@ fn amounts_min_greater_than_amounts_desired(){ test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount0 = 123456789i128; let amount1 = 987654321i128; @@ -847,22 +914,22 @@ fn amounts_min_greater_than_amounts_desired(){ let users = DeFindexVaultTest::generate_random_users(&test.env, 2); // Balances before deposit - test.token0_admin_client.mint(&users[0], &amount0); - test.token1_admin_client.mint(&users[0], &amount1); - let user_balance0 = test.token0.balance(&users[0]); + test.token_0_admin_client.mint(&users[0], &amount0); + test.token_1_admin_client.mint(&users[0], &amount1); + let user_balance0 = test.token_0.balance(&users[0]); assert_eq!(user_balance0, amount0); - let user_balance1 = test.token1.balance(&users[0]); + 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 - let deposit_result=defindex_contract.try_deposit( + let deposit_result = defindex_contract.try_deposit( &sorobanvec![&test.env, amount0, amount1], &sorobanvec![&test.env, amount0 + 1, amount1 + 1], &users[0], - &false + &false, ); // this should fail @@ -871,22 +938,22 @@ fn amounts_min_greater_than_amounts_desired(){ //Test token transfer from user to vault on deposit #[test] -fn transfers_tokens_from_user_to_vault(){ +fn transfers_tokens_from_user_to_vault() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + 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.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -900,8 +967,12 @@ fn transfers_tokens_from_user_to_vault(){ test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount0 = 123456789i128; let amount1 = 987654321i128; @@ -909,11 +980,11 @@ fn transfers_tokens_from_user_to_vault(){ let users = DeFindexVaultTest::generate_random_users(&test.env, 2); // Balances before deposit - test.token0_admin_client.mint(&users[0], &amount0); - test.token1_admin_client.mint(&users[0], &amount1); - let user_balance0 = test.token0.balance(&users[0]); + test.token_0_admin_client.mint(&users[0], &amount0); + test.token_1_admin_client.mint(&users[0], &amount1); + let user_balance0 = test.token_0.balance(&users[0]); assert_eq!(user_balance0, amount0); - let user_balance1 = test.token1.balance(&users[0]); + let user_balance1 = test.token_1.balance(&users[0]); assert_eq!(user_balance1, amount1); let df_balance = defindex_contract.balance(&users[0]); @@ -924,14 +995,14 @@ fn transfers_tokens_from_user_to_vault(){ &sorobanvec![&test.env, amount0, amount1], &sorobanvec![&test.env, amount0, amount1], &users[0], - &false + &false, ); // check balances after deposit let df_balance = defindex_contract.balance(&users[0]); assert_eq!(df_balance, amount0 + amount1 - 1000); - let user_balance0 = test.token0.balance(&users[0]); + let user_balance0 = test.token_0.balance(&users[0]); assert_eq!(user_balance0, 0i128); } @@ -939,14 +1010,14 @@ fn transfers_tokens_from_user_to_vault(){ fn arithmetic_error() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); // Initialize with 1 asset let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; @@ -960,38 +1031,42 @@ fn arithmetic_error() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); // Mock the environment to provoke a division by zero let mut mock_map = Map::new(&test.env); - mock_map.set(test.token0.address.clone(), 0i128); // Total funds for token0 is 0 + mock_map.set(test.token_0.address.clone(), 0i128); // Total funds for token_0 is 0 let amount = 123456789i128; let users = DeFindexVaultTest::generate_random_users(&test.env, 1); // Mint tokens to user - test.token0_admin_client.mint(&users[0], &amount); + test.token_0_admin_client.mint(&users[0], &amount); let large_amount = i128::MAX / 2; - test.token0_admin_client.mint(&users[0], &large_amount); + test.token_0_admin_client.mint(&users[0], &large_amount); //first deposit to overflow the balance defindex_contract.deposit( &sorobanvec![&test.env, large_amount], &sorobanvec![&test.env, large_amount], &users[0], - &false + &false, ); - + // Try to deposit a large amount let result = defindex_contract.try_deposit( &sorobanvec![&test.env, large_amount], &sorobanvec![&test.env, large_amount], &users[0], - &false + &false, ); // Verify that the returned error is ContractError::ArithmeticError @@ -1003,14 +1078,14 @@ fn arithmetic_error() { fn amounts_desired_zero() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); // Initialize with 1 asset let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; @@ -1024,8 +1099,12 @@ fn amounts_desired_zero() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount = 123456789i128; @@ -1033,13 +1112,13 @@ fn amounts_desired_zero() { let users = DeFindexVaultTest::generate_random_users(&test.env, 1); // Mint tokens to user - test.token0_admin_client.mint(&users[0], &amount); + test.token_0_admin_client.mint(&users[0], &amount); // Balances before deposit - let user_balance_before = test.token0.balance(&users[0]); + let user_balance_before = test.token_0.balance(&users[0]); assert_eq!(user_balance_before, amount); - let vault_balance_before = test.token0.balance(&defindex_contract.address); + let vault_balance_before = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance_before, 0i128); let df_balance_before = defindex_contract.balance(&users[0]); @@ -1050,32 +1129,31 @@ fn amounts_desired_zero() { &sorobanvec![&test.env, 0i128], &sorobanvec![&test.env, 0i128], &users[0], - &false + &false, ); // Verify that the returned error is ContractError::InsufficientAmount assert_eq!(deposit_result, Err(Ok(ContractError::InsufficientAmount))); } - - // Deposit with insufficient funds and check for specific error message +// Deposit with insufficient funds and check for specific error message #[test] fn insufficient_funds_with_error_message() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + 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.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -1089,8 +1167,12 @@ fn insufficient_funds_with_error_message() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount0 = 123456789i128; @@ -1099,13 +1181,13 @@ fn insufficient_funds_with_error_message() { let users = DeFindexVaultTest::generate_random_users(&test.env, 1); // Mint tokens to user - test.token0_admin_client.mint(&users[0], &amount0); - test.token1_admin_client.mint(&users[0], &amount1); + test.token_0_admin_client.mint(&users[0], &amount0); + test.token_1_admin_client.mint(&users[0], &amount1); // Balances before deposit - let user_balance0 = test.token0.balance(&users[0]); + let user_balance0 = test.token_0.balance(&users[0]); assert_eq!(user_balance0, amount0); - let user_balance1 = test.token1.balance(&users[0]); + let user_balance1 = test.token_1.balance(&users[0]); assert_eq!(user_balance1, amount1); let df_balance = defindex_contract.balance(&users[0]); @@ -1116,7 +1198,7 @@ fn insufficient_funds_with_error_message() { &sorobanvec![&test.env, amount0 + 1, amount1 + 1], &sorobanvec![&test.env, amount0 + 1, amount1 + 1], &users[0], - &false + &false, ); if deposit_result == Err(Err(InvokeError::Contract(10))) { @@ -1124,5 +1206,4 @@ fn insufficient_funds_with_error_message() { } else { panic!("Expected error not returned"); } - -} \ No newline at end of file +} 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 5a075b79..a800f1ea 100644 --- a/apps/contracts/vault/src/test/vault/deposit_and_invest.rs +++ b/apps/contracts/vault/src/test/vault/deposit_and_invest.rs @@ -1,13 +1,12 @@ -use soroban_sdk::{vec as sorobanvec, String, Vec, Map, vec}; +use soroban_sdk::{vec as sorobanvec, vec, Map, String, Vec}; use crate::test::defindex_vault::{ - AssetStrategySet, - StrategyAllocation, - CurrentAssetInvestmentAllocation, - AssetInvestmentAllocation, + AssetInvestmentAllocation, AssetStrategySet, CurrentAssetInvestmentAllocation, + StrategyAllocation, }; use crate::test::{ - create_defindex_vault, create_strategy_params_token0, create_strategy_params_token1, DeFindexVaultTest + create_defindex_vault, create_strategy_params_token_0, create_strategy_params_token_1, + DeFindexVaultTest, }; // with no previous investment, there should not be any investment @@ -15,14 +14,14 @@ use crate::test::{ fn one_asset_no_previous_investment() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); // initialize with 1 assets let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; @@ -36,16 +35,20 @@ fn one_asset_no_previous_investment() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount = 123456789i128; let users = DeFindexVaultTest::generate_random_users(&test.env, 1); // Balances before deposit - test.token0_admin_client.mint(&users[0], &amount); - let user_balance = test.token0.balance(&users[0]); + test.token_0_admin_client.mint(&users[0], &amount); + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, amount); let df_balance = defindex_contract.balance(&users[0]); @@ -64,49 +67,53 @@ fn one_asset_no_previous_investment() { // check balances after deposit let df_balance = defindex_contract.balance(&users[0]); assert_eq!(df_balance, amount - 1000); - - let user_balance = test.token0.balance(&users[0]); + + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, 0i128); // all in idle funds - let vault_balance = test.token0.balance(&defindex_contract.address); + let vault_balance = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance, amount); // check total managed funds let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected_token_0 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 0, // all in idle funds - }]; - - total_managed_funds_expected.set(test.token0.address.clone(), - CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), - total_amount: amount, - idle_amount: amount, - invested_amount: 0, - strategy_allocations: strategy_investments_expected_token_0, - }); + let strategy_investments_expected_token_0 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, // all in idle funds + } + ]; + + total_managed_funds_expected.set( + test.token_0.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_0.address.clone(), + total_amount: amount, + idle_amount: amount, + invested_amount: 0, + strategy_allocations: strategy_investments_expected_token_0, + }, + ); let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); - - - // check current idle funds, + + // check current idle funds, let mut expected_idle_map = Map::new(&test.env); - expected_idle_map.set(test.token0.address.clone(), amount); + expected_idle_map.set(test.token_0.address.clone(), amount); let current_idle_funds = defindex_contract.fetch_current_idle_funds(); assert_eq!(current_idle_funds, expected_idle_map); - + let mut expected_invested_map = Map::new(&test.env); - expected_invested_map.set(test.token0.address.clone(), 0); + expected_invested_map.set(test.token_0.address.clone(), 0); let current_invested_funds = defindex_contract.fetch_current_invested_funds(); assert_eq!(current_invested_funds, expected_invested_map); // Now user deposits for the second time let amount2 = 987654321i128; - test.token0_admin_client.mint(&users[0], &amount2); - let user_balance = test.token0.balance(&users[0]); + test.token_0_admin_client.mint(&users[0], &amount2); + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, amount2); // deposit AND INVEST @@ -117,45 +124,49 @@ fn one_asset_no_previous_investment() { &true, ); - // check balances after deposit let df_balance = defindex_contract.balance(&users[0]); assert_eq!(df_balance, amount + amount2 - 1000); - - let user_balance = test.token0.balance(&users[0]); + + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, 0i128); - - let vault_balance = test.token0.balance(&defindex_contract.address); + + let vault_balance = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance, amount + amount2); - + // check that fetch_total_managed_funds returns correct amount let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected_token_0 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 0, - }]; - - total_managed_funds_expected.set(test.token0.address.clone(), - CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), - total_amount: amount + amount2, - idle_amount: amount + amount2, - invested_amount: 0, - strategy_allocations: strategy_investments_expected_token_0, - }); + let strategy_investments_expected_token_0 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, + } + ]; + + total_managed_funds_expected.set( + test.token_0.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_0.address.clone(), + total_amount: amount + amount2, + idle_amount: amount + amount2, + invested_amount: 0, + strategy_allocations: strategy_investments_expected_token_0, + }, + ); let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); - + // check current idle funds let mut expected_idle_map = Map::new(&test.env); - expected_idle_map.set(test.token0.address.clone(), amount + amount2); + expected_idle_map.set(test.token_0.address.clone(), amount + amount2); let current_idle_funds = defindex_contract.fetch_current_idle_funds(); assert_eq!(current_idle_funds, expected_idle_map); - + // check that current invested funds is now 0, funds still in idle funds let mut expected_invested_map = Map::new(&test.env); - expected_invested_map.set(test.token0.address.clone(), 0); + expected_invested_map.set(test.token_0.address.clone(), 0); let current_invested_funds = defindex_contract.fetch_current_invested_funds(); assert_eq!(current_invested_funds, expected_invested_map); } @@ -164,14 +175,14 @@ fn one_asset_no_previous_investment() { fn one_asset_previous_investment_success() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); // initialize with 1 assets let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; @@ -185,8 +196,12 @@ fn one_asset_previous_investment_success() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount = 123456789i128; @@ -194,8 +209,8 @@ fn one_asset_previous_investment_success() { let users = DeFindexVaultTest::generate_random_users(&test.env, 1); // Balances before deposit - test.token0_admin_client.mint(&users[0], &amount); - let user_balance = test.token0.balance(&users[0]); + test.token_0_admin_client.mint(&users[0], &amount); + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, amount); let df_balance = defindex_contract.balance(&users[0]); @@ -210,84 +225,92 @@ fn one_asset_previous_investment_success() { ); // all in idle funds - let vault_balance = test.token0.balance(&defindex_contract.address); + let vault_balance = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance, amount); let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected_token_0 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 0, // everything has been invested - }]; - - total_managed_funds_expected.set(test.token0.address.clone(), - CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), - total_amount: amount, - idle_amount: amount, - invested_amount: 0, - strategy_allocations: strategy_investments_expected_token_0, - }); - + let strategy_investments_expected_token_0 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, // everything has been invested + } + ]; + + total_managed_funds_expected.set( + test.token_0.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_0.address.clone(), + total_amount: amount, + idle_amount: amount, + invested_amount: 0, + strategy_allocations: strategy_investments_expected_token_0, + }, + ); + let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); - - let amount_to_invest =100000000i128; + + let amount_to_invest = 100000000i128; // GENERATE INVESTMENT let asset_investments = vec![ &test.env, Some(AssetInvestmentAllocation { - asset: test.token0.address.clone(), - strategy_allocations: vec![ - &test.env, - Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: amount_to_invest, - }), - ], - })]; + 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, + }), + ], + }), + ]; - defindex_contract.invest( - &asset_investments, - ); + defindex_contract.invest(&asset_investments); // Now we should have: let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected_token_0 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: amount_to_invest, // everything has been invested - }]; - - total_managed_funds_expected.set(test.token0.address.clone(), - CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), - total_amount: amount, - idle_amount: amount -amount_to_invest, - invested_amount: amount_to_invest, - strategy_allocations: strategy_investments_expected_token_0, - }); - + let strategy_investments_expected_token_0 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: amount_to_invest, // everything has been invested + } + ]; + + total_managed_funds_expected.set( + test.token_0.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_0.address.clone(), + total_amount: amount, + idle_amount: amount - amount_to_invest, + invested_amount: amount_to_invest, + strategy_allocations: strategy_investments_expected_token_0, + }, + ); + let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); - - // check current idle funds, + // check current idle funds, let mut expected_idle_map = Map::new(&test.env); - expected_idle_map.set(test.token0.address.clone(), amount -amount_to_invest); + expected_idle_map.set(test.token_0.address.clone(), amount - amount_to_invest); let current_idle_funds = defindex_contract.fetch_current_idle_funds(); assert_eq!(current_idle_funds, expected_idle_map); - + // check that current invested funds is now 0, funds still in idle funds //map shuould be map let mut expected_invested_map = Map::new(&test.env); - expected_invested_map.set(test.token0.address.clone(), amount_to_invest); + expected_invested_map.set(test.token_0.address.clone(), amount_to_invest); let current_invested_funds = defindex_contract.fetch_current_invested_funds(); assert_eq!(current_invested_funds, expected_invested_map); // DEPOSIT AND INVEST let amount2 = 987654321i128; - test.token0_admin_client.mint(&users[0], &amount2); - let user_balance = test.token0.balance(&users[0]); + test.token_0_admin_client.mint(&users[0], &amount2); + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, amount2); // deposit AND INVEST @@ -299,46 +322,51 @@ fn one_asset_previous_investment_success() { ); // because there was already some strategy allocation, all of the amount2 should be invested - + // check balances after deposit let df_balance = defindex_contract.balance(&users[0]); assert_eq!(df_balance, amount + amount2 - 1000); - - let user_balance = test.token0.balance(&users[0]); + + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, 0i128); - + // check that the assets are not in the vault - let vault_balance = test.token0.balance(&defindex_contract.address); + let vault_balance = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance, amount - amount_to_invest); - + // check that fetch_total_managed_funds returns correct amount let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected_token_0 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: amount_to_invest + amount2, // everything has been invested - }]; - - total_managed_funds_expected.set(test.token0.address.clone(), - CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), - total_amount: amount + amount2, - idle_amount: amount - amount_to_invest, - invested_amount: amount_to_invest + amount2, - strategy_allocations: strategy_investments_expected_token_0, - }); + let strategy_investments_expected_token_0 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: amount_to_invest + amount2, // everything has been invested + } + ]; + + total_managed_funds_expected.set( + test.token_0.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_0.address.clone(), + total_amount: amount + amount2, + idle_amount: amount - amount_to_invest, + invested_amount: amount_to_invest + amount2, + strategy_allocations: strategy_investments_expected_token_0, + }, + ); let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); - + // check current idle funds let mut expected_idle_map = Map::new(&test.env); - expected_idle_map.set(test.token0.address.clone(), amount - amount_to_invest); + expected_idle_map.set(test.token_0.address.clone(), amount - amount_to_invest); let current_idle_funds = defindex_contract.fetch_current_idle_funds(); assert_eq!(current_idle_funds, expected_idle_map); - + // check that current invested funds let mut expected_invested_map = Map::new(&test.env); - expected_invested_map.set(test.token0.address.clone(), amount_to_invest + amount2); + expected_invested_map.set(test.token_0.address.clone(), amount_to_invest + amount2); let current_invested_funds = defindex_contract.fetch_current_invested_funds(); assert_eq!(current_invested_funds, expected_invested_map); } @@ -347,19 +375,19 @@ fn one_asset_previous_investment_success() { fn several_assets_no_previous_investment() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + 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.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -373,8 +401,12 @@ fn several_assets_no_previous_investment() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount0 = 123456789i128; let amount1 = 987654321i128; @@ -382,18 +414,18 @@ fn several_assets_no_previous_investment() { let users = DeFindexVaultTest::generate_random_users(&test.env, 2); // Balances before deposit - test.token0_admin_client.mint(&users[0], &amount0); - test.token1_admin_client.mint(&users[0], &amount1); - let user_balance0 = test.token0.balance(&users[0]); + test.token_0_admin_client.mint(&users[0], &amount0); + test.token_1_admin_client.mint(&users[0], &amount1); + let user_balance0 = test.token_0.balance(&users[0]); assert_eq!(user_balance0, amount0); - let user_balance1 = test.token1.balance(&users[0]); + 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 // however wih no previous investment yet - let deposit_result=defindex_contract.deposit( + let deposit_result = defindex_contract.deposit( &sorobanvec![&test.env, amount0, amount1], &sorobanvec![&test.env, amount0, amount1], &users[0], @@ -401,7 +433,10 @@ fn several_assets_no_previous_investment() { ); // check deposit result - assert_eq!(deposit_result, (sorobanvec![&test.env, amount0, amount1], amount0 + amount1)); + assert_eq!( + deposit_result, + (sorobanvec![&test.env, amount0, amount1], amount0 + amount1) + ); // check balances after deposit let df_balance = defindex_contract.balance(&users[0]); @@ -411,136 +446,157 @@ fn several_assets_no_previous_investment() { // check that the vault holds 1000 shares let vault_df_shares = defindex_contract.balance(&defindex_contract.address); assert_eq!(vault_df_shares, 1000i128); - - let user_balance0 = test.token0.balance(&users[0]); - assert_eq!(user_balance0,0i128); - let user_balance1 = test.token1.balance(&users[0]); - assert_eq!(user_balance1,0i128); + + let user_balance0 = test.token_0.balance(&users[0]); + assert_eq!(user_balance0, 0i128); + let user_balance1 = test.token_1.balance(&users[0]); + assert_eq!(user_balance1, 0i128); // all in idle funds - let vault_balance0 = test.token0.balance(&defindex_contract.address); + let vault_balance0 = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance0, amount0); // check vault balance of asset 1 - let vault_balance1 = test.token1.balance(&defindex_contract.address); - assert_eq!(vault_balance1, amount1); + let vault_balance1 = test.token_1.balance(&defindex_contract.address); + assert_eq!(vault_balance1, amount1); // check that fetch_total_managed_funds returns correct amount let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected_token_0 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 0, - }]; - let strategy_investments_expected_token_1 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), - amount: 0, - }]; - total_managed_funds_expected.set(test.token0.address.clone(), - CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), - total_amount: amount0, - idle_amount: amount0, - invested_amount: 0, - strategy_allocations: strategy_investments_expected_token_0, - }); - total_managed_funds_expected.set(test.token1.address.clone(), - CurrentAssetInvestmentAllocation { - asset: test.token1.address.clone(), - total_amount: amount1, - idle_amount: amount1, - invested_amount: 0, - strategy_allocations: strategy_investments_expected_token_1, - }); + let strategy_investments_expected_token_0 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, + } + ]; + let strategy_investments_expected_token_1 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: 0, + } + ]; + total_managed_funds_expected.set( + test.token_0.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_0.address.clone(), + total_amount: amount0, + idle_amount: amount0, + invested_amount: 0, + strategy_allocations: strategy_investments_expected_token_0, + }, + ); + total_managed_funds_expected.set( + test.token_1.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_1.address.clone(), + total_amount: amount1, + idle_amount: amount1, + invested_amount: 0, + strategy_allocations: strategy_investments_expected_token_1, + }, + ); let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); - + // check current idle funds let mut expected_idle_map = Map::new(&test.env); - expected_idle_map.set(test.token0.address.clone(), amount0); - expected_idle_map.set(test.token1.address.clone(), amount1); + expected_idle_map.set(test.token_0.address.clone(), amount0); + expected_idle_map.set(test.token_1.address.clone(), amount1); let current_idle_funds = defindex_contract.fetch_current_idle_funds(); assert_eq!(current_idle_funds, expected_idle_map); - + // check that current invested funds is now correct, let mut expected_invested_map = Map::new(&test.env); - expected_invested_map.set(test.token0.address.clone(), 0); - expected_invested_map.set(test.token1.address.clone(), 0); + expected_invested_map.set(test.token_0.address.clone(), 0); + expected_invested_map.set(test.token_1.address.clone(), 0); let current_invested_funds = defindex_contract.fetch_current_invested_funds(); assert_eq!(current_invested_funds, expected_invested_map); // new user wants to do a deposit with more assets 0 than the proportion, but with minium amount 0 // multiply amount0 by 2 - let amount0_new = amount0*2 +100 ; - let amount1_new = amount1*2; + let amount0_new = amount0 * 2 + 100; + let amount1_new = amount1 * 2; // mint this to user 1 - test.token0_admin_client.mint(&users[1], &amount0_new); - test.token1_admin_client.mint(&users[1], &amount1_new); + test.token_0_admin_client.mint(&users[1], &amount0_new); + test.token_1_admin_client.mint(&users[1], &amount1_new); // check user balances - let user_balance0 = test.token0.balance(&users[1]); + let user_balance0 = test.token_0.balance(&users[1]); assert_eq!(user_balance0, amount0_new); - let user_balance1 = test.token1.balance(&users[1]); + let user_balance1 = test.token_1.balance(&users[1]); assert_eq!(user_balance1, amount1_new); - // user 1 deposits - let deposit_result=defindex_contract.deposit( + let deposit_result = defindex_contract.deposit( &sorobanvec![&test.env, amount0_new, amount1_new], &sorobanvec![&test.env, 0i128, 0i128], &users[1], &true, ); - - - assert_eq!(deposit_result, (sorobanvec![&test.env, amount0*2, amount1*2], amount0*2 + amount1*2)); - + assert_eq!( + deposit_result, + ( + sorobanvec![&test.env, amount0 * 2, amount1 * 2], + amount0 * 2 + amount1 * 2 + ) + ); // check balances after deposit let df_balance = defindex_contract.balance(&users[1]); - assert_eq!(df_balance, 2*(amount0 + amount1)); + assert_eq!(df_balance, 2 * (amount0 + amount1)); - let user_balance0 = test.token0.balance(&users[1]); - assert_eq!(user_balance0, amount0_new - 2*amount0); + let user_balance0 = test.token_0.balance(&users[1]); + assert_eq!(user_balance0, amount0_new - 2 * amount0); - let user_balance1 = test.token1.balance(&users[1]); - assert_eq!(user_balance1, amount1_new - 2*amount1); + let user_balance1 = test.token_1.balance(&users[1]); + assert_eq!(user_balance1, amount1_new - 2 * amount1); // check vault balance of asset 0, all in idle funds - let vault_balance0 = test.token0.balance(&defindex_contract.address); - assert_eq!(vault_balance0, amount0*3); + let vault_balance0 = test.token_0.balance(&defindex_contract.address); + assert_eq!(vault_balance0, amount0 * 3); // check vault balance of asset 1 - let vault_balance1 = test.token1.balance(&defindex_contract.address); - assert_eq!(vault_balance1, amount1*3); + let vault_balance1 = test.token_1.balance(&defindex_contract.address); + assert_eq!(vault_balance1, amount1 * 3); - // check that fetch_total_managed_funds returns correct amount let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected_token_0 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 0, // everything has been invested - }]; - let strategy_investments_expected_token_1 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), - amount: 0, // everything has been invested - }]; - total_managed_funds_expected.set(test.token0.address.clone(), - CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), - total_amount: amount0*3, - idle_amount: amount0*3, - invested_amount: 0, - strategy_allocations: strategy_investments_expected_token_0, - }); - total_managed_funds_expected.set(test.token1.address.clone(), - CurrentAssetInvestmentAllocation { - asset: test.token1.address.clone(), - total_amount: amount1*3, - idle_amount: amount1*3, - invested_amount: 0, - strategy_allocations: strategy_investments_expected_token_1, - }); + let strategy_investments_expected_token_0 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, // everything has been invested + } + ]; + let strategy_investments_expected_token_1 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: 0, // everything has been invested + } + ]; + total_managed_funds_expected.set( + test.token_0.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_0.address.clone(), + total_amount: amount0 * 3, + idle_amount: amount0 * 3, + invested_amount: 0, + strategy_allocations: strategy_investments_expected_token_0, + }, + ); + total_managed_funds_expected.set( + test.token_1.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_1.address.clone(), + total_amount: amount1 * 3, + idle_amount: amount1 * 3, + invested_amount: 0, + strategy_allocations: strategy_investments_expected_token_1, + }, + ); let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); } @@ -549,19 +605,19 @@ fn several_assets_no_previous_investment() { fn several_assets_wih_previous_investment_success() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + 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.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; let defindex_contract = create_defindex_vault( @@ -574,8 +630,12 @@ fn several_assets_wih_previous_investment_success() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount0 = 123456789i128; @@ -584,9 +644,9 @@ fn several_assets_wih_previous_investment_success() { let users = DeFindexVaultTest::generate_random_users(&test.env, 2); // Balances before deposit - test.token0_admin_client.mint(&users[0], &amount0); - test.token1_admin_client.mint(&users[0], &amount1); - + test.token_0_admin_client.mint(&users[0], &amount0); + test.token_1_admin_client.mint(&users[0], &amount1); + // deposit with no previous investment defindex_contract.deposit( &sorobanvec![&test.env, amount0, amount1], @@ -595,88 +655,95 @@ fn several_assets_wih_previous_investment_success() { &true, ); - // GENERATE INVESTMENT - let amount_to_invest_0 =100000000i128; - let amount_to_invest_1 =200000000i128; + // GENERATE INVESTMENT + let amount_to_invest_0 = 100000000i128; + let amount_to_invest_1 = 200000000i128; let asset_investments = sorobanvec![ &test.env, Some(AssetInvestmentAllocation { - asset: test.token0.address.clone(), + asset: test.token_0.address.clone(), strategy_allocations: vec![ &test.env, Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: amount_to_invest_0, + strategy_address: test.strategy_client_token_0.address.clone(), + amount: amount_to_invest_0, }), ], }), Some(AssetInvestmentAllocation { - asset: test.token1.address.clone(), + asset: test.token_1.address.clone(), strategy_allocations: vec![ &test.env, Some(StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), - amount: amount_to_invest_1, + strategy_address: test.strategy_client_token_1.address.clone(), + amount: amount_to_invest_1, }), ], - })]; + }) + ]; - defindex_contract.invest( - &asset_investments, - ); + defindex_contract.invest(&asset_investments); // total managed funds let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected_token_0 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: amount_to_invest_0, // everything has been invested - }]; - let strategy_investments_expected_token_1 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), - amount: amount_to_invest_1, // everything has been invested - }]; - total_managed_funds_expected.set(test.token0.address.clone(), - CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), - total_amount: amount0, - idle_amount: amount0 - amount_to_invest_0, - invested_amount: amount_to_invest_0, - strategy_allocations: strategy_investments_expected_token_0, - }); - total_managed_funds_expected.set(test.token1.address.clone(), - CurrentAssetInvestmentAllocation { - asset: test.token1.address.clone(), - total_amount: amount1, - idle_amount: amount1 - amount_to_invest_1, - invested_amount: amount_to_invest_1, - strategy_allocations: strategy_investments_expected_token_1, - }); + let strategy_investments_expected_token_0 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: amount_to_invest_0, // everything has been invested + } + ]; + let strategy_investments_expected_token_1 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: amount_to_invest_1, // everything has been invested + } + ]; + total_managed_funds_expected.set( + test.token_0.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_0.address.clone(), + total_amount: amount0, + idle_amount: amount0 - amount_to_invest_0, + invested_amount: amount_to_invest_0, + strategy_allocations: strategy_investments_expected_token_0, + }, + ); + total_managed_funds_expected.set( + test.token_1.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_1.address.clone(), + total_amount: amount1, + idle_amount: amount1 - amount_to_invest_1, + invested_amount: amount_to_invest_1, + strategy_allocations: strategy_investments_expected_token_1, + }, + ); let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); - // Now that we have previous invesment, we will do deposit and invest and this deposit should be invested directly // new user wants to do a deposit with more assets 0 than the proportion, but with minium amount 0 // multiply amount0 by 2 - let amount0_new = amount0*2 +100 ; - let amount1_new = amount1*2; + let amount0_new = amount0 * 2 + 100; + let amount1_new = amount1 * 2; // mint this to user 1 - test.token0_admin_client.mint(&users[1], &amount0_new); - test.token1_admin_client.mint(&users[1], &amount1_new); + test.token_0_admin_client.mint(&users[1], &amount0_new); + test.token_1_admin_client.mint(&users[1], &amount1_new); // check user balances - let user_balance0 = test.token0.balance(&users[1]); + let user_balance0 = test.token_0.balance(&users[1]); assert_eq!(user_balance0, amount0_new); - let user_balance1 = test.token1.balance(&users[1]); + let user_balance1 = test.token_1.balance(&users[1]); assert_eq!(user_balance1, amount1_new); - // user 1 deposits - let deposit_result=defindex_contract.deposit( + let deposit_result = defindex_contract.deposit( &sorobanvec![&test.env, amount0_new, amount1_new], &sorobanvec![&test.env, 0i128, 0i128], &users[1], @@ -686,69 +753,83 @@ fn several_assets_wih_previous_investment_success() { // check deposit result. Ok((amounts, shares_to_mint)) // Vec, i128 - assert_eq!(deposit_result, (sorobanvec![&test.env, amount0*2, amount1*2], amount0*2 + amount1*2)); - + assert_eq!( + deposit_result, + ( + sorobanvec![&test.env, amount0 * 2, amount1 * 2], + amount0 * 2 + amount1 * 2 + ) + ); // check balances after deposit let df_balance = defindex_contract.balance(&users[1]); - assert_eq!(df_balance, 2*(amount0 + amount1)); + assert_eq!(df_balance, 2 * (amount0 + amount1)); - let user_balance0 = test.token0.balance(&users[1]); - assert_eq!(user_balance0, amount0_new - 2*amount0); + let user_balance0 = test.token_0.balance(&users[1]); + assert_eq!(user_balance0, amount0_new - 2 * amount0); - let user_balance1 = test.token1.balance(&users[1]); - assert_eq!(user_balance1, amount1_new - 2*amount1); + let user_balance1 = test.token_1.balance(&users[1]); + assert_eq!(user_balance1, amount1_new - 2 * amount1); // check vault balance of asset 0 - let vault_balance0 = test.token0.balance(&defindex_contract.address); + let vault_balance0 = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance0, amount0 - amount_to_invest_0); // check vault balance of asset 1 - let vault_balance1 = test.token1.balance(&defindex_contract.address); + let vault_balance1 = test.token_1.balance(&defindex_contract.address); assert_eq!(vault_balance1, amount1 - amount_to_invest_1); - // check that fetch_total_managed_funds returns correct amount let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected_token_0 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: amount0*2 + amount_to_invest_0, // only new deposit and invest - }]; - let strategy_investments_expected_token_1 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), - amount: amount1*2 + amount_to_invest_1, // only new deposit and invest - }]; - total_managed_funds_expected.set(test.token0.address.clone(), - CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), - total_amount: amount0*3, - idle_amount: amount0 - amount_to_invest_0, - invested_amount: amount0*2 + amount_to_invest_0, - strategy_allocations: strategy_investments_expected_token_0, - }); - total_managed_funds_expected.set(test.token1.address.clone(), - CurrentAssetInvestmentAllocation { - asset: test.token1.address.clone(), - total_amount: amount1*3, - idle_amount: amount1 - amount_to_invest_1, - invested_amount: amount1*2 + amount_to_invest_1, - strategy_allocations: strategy_investments_expected_token_1, - }); + let strategy_investments_expected_token_0 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: amount0 * 2 + amount_to_invest_0, // only new deposit and invest + } + ]; + let strategy_investments_expected_token_1 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: amount1 * 2 + amount_to_invest_1, // only new deposit and invest + } + ]; + total_managed_funds_expected.set( + test.token_0.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_0.address.clone(), + total_amount: amount0 * 3, + idle_amount: amount0 - amount_to_invest_0, + invested_amount: amount0 * 2 + amount_to_invest_0, + strategy_allocations: strategy_investments_expected_token_0, + }, + ); + total_managed_funds_expected.set( + test.token_1.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_1.address.clone(), + total_amount: amount1 * 3, + idle_amount: amount1 - amount_to_invest_1, + invested_amount: amount1 * 2 + amount_to_invest_1, + strategy_allocations: strategy_investments_expected_token_1, + }, + ); let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); - + // invested_amount: 1780246914, strategy_allocations: Vec(Ok(StrategyAllocation { amount: 1780246914, strategy_address: Contract(CDDD62URLXHZ2SEMZ3ZWWKRA2DCK75PELPRVLAW4PPO5PRL2HJW25HLF) })), total_amount: 2567901235 })), Ok((Contract(CDS3FDGQ4JA2V3F26Y4BMWWJEC5TT26RJBN7KIQKUMVO2MAOCMDTSZ7A), CurrentAssetInvestmentAllocation { asset: Contract(CDS3FDGQ4JA2V3F26Y4BMWWJEC5TT26RJBN7KIQKUMVO2MAOCMDTSZ7A), idle_amount: 23456789, invested_amount: 297530863, strategy_allocations: Vec(Ok(StrategyAllocation { amount: 297530863, strategy_address: Contract(CB457TMKS3NBPJJRHNCRJMSAWP2YMCNIORWHHF6MNZJQQGZQRPSANQSE) })), total_amount: 320987652 }))) // invested_amount: 2175308642, strategy_allocations: Vec(Ok(StrategyAllocation { amount: 2175308642, strategy_address: Contract(CDDD62URLXHZ2SEMZ3ZWWKRA2DCK75PELPRVLAW4PPO5PRL2HJW25HLF) })), total_amount: 2962962963 })), Ok((Contract(CDS3FDGQ4JA2V3F26Y4BMWWJEC5TT26RJBN7KIQKUMVO2MAOCMDTSZ7A), CurrentAssetInvestmentAllocation { asset: Contract(CDS3FDGQ4JA2V3F26Y4BMWWJEC5TT26RJBN7KIQKUMVO2MAOCMDTSZ7A), idle_amount: 23456789, invested_amount: 346913578, strategy_allocations: Vec(Ok(StrategyAllocation { amount: 346913578, strategy_address: Contract(CB457TMKS3NBPJJRHNCRJMSAWP2YMCNIORWHHF6MNZJQQGZQRPSANQSE) })), total_amount: 370370367 }))) // // check current idle funds // let mut expected_idle_map = Map::new(&test.env); - // expected_idle_map.set(test.token0.address.clone(), 0); - // expected_idle_map.set(test.token1.address.clone(), 0); + // expected_idle_map.set(test.token_0.address.clone(), 0); + // expected_idle_map.set(test.token_1.address.clone(), 0); // let current_idle_funds = test.defindex_contract.fetch_current_idle_funds(); // assert_eq!(current_idle_funds, expected_idle_map); - + // // check that current invested funds is now 0, funds still in idle funds // let mut expected_invested_map = Map::new(&test.env); - // expected_invested_map.set(test.token0.address.clone(), 3*amount0); - // expected_invested_map.set(test.token1.address.clone(), 3*amount1); + // expected_invested_map.set(test.token_0.address.clone(), 3*amount0); + // expected_invested_map.set(test.token_1.address.clone(), 3*amount1); // let current_invested_funds = test.defindex_contract.fetch_current_invested_funds(); // assert_eq!(current_invested_funds, expected_invested_map); @@ -757,13 +838,13 @@ fn several_assets_wih_previous_investment_success() { // let amount1_new = amount1*2+100; // // mint this to user 1 - // test.token0_admin_client.mint(&users[1], &amount0_new); - // test.token1_admin_client.mint(&users[1], &amount1_new); - + // test.token_0_admin_client.mint(&users[1], &amount0_new); + // test.token_1_admin_client.mint(&users[1], &amount1_new); + // // check user balances - // let user_balance0 = test.token0.balance(&users[1]); + // let user_balance0 = test.token_0.balance(&users[1]); // assert_eq!(user_balance0, 100 + amount0_new); // we still have 100 from before - // let user_balance1 = test.token1.balance(&users[1]); + // let user_balance1 = test.token_1.balance(&users[1]); // assert_eq!(user_balance1, amount1_new); // // user 1 deposits @@ -777,26 +858,23 @@ fn several_assets_wih_previous_investment_success() { // // check deposit result. Ok((amounts, shares_to_mint)) // // Vec, i128 // assert_eq!(deposit_result, (sorobanvec![&test.env, amount0*2, amount1*2], amount0*2 + amount1*2)); - } -#[test] +#[test] fn one_asset_several_strategies() { /* What happens when no previous investment has been done? - + */ todo!(); } - - -#[test] +#[test] 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!(); } diff --git a/apps/contracts/vault/src/test/vault/emergency_withdraw.rs b/apps/contracts/vault/src/test/vault/emergency_withdraw.rs index df40cbe4..07cd11b3 100644 --- a/apps/contracts/vault/src/test/vault/emergency_withdraw.rs +++ b/apps/contracts/vault/src/test/vault/emergency_withdraw.rs @@ -1,20 +1,21 @@ use soroban_sdk::{vec as sorobanvec, String, Vec}; use crate::test::{ - create_defindex_vault, create_strategy_params_token0, defindex_vault::{AssetInvestmentAllocation, AssetStrategySet, StrategyAllocation - }, DeFindexVaultTest + create_defindex_vault, create_strategy_params_token_0, + defindex_vault::{AssetInvestmentAllocation, AssetStrategySet, StrategyAllocation}, + DeFindexVaultTest, }; #[test] fn withdraw_success() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; @@ -28,16 +29,20 @@ fn withdraw_success() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount = 987654321i128; let users = DeFindexVaultTest::generate_random_users(&test.env, 1); - test.token0_admin_client.mint(&users[0], &amount); - let user_balance = test.token0.balance(&users[0]); + test.token_0_admin_client.mint(&users[0], &amount); + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, amount); let df_balance = defindex_contract.balance(&users[0]); @@ -48,56 +53,55 @@ fn withdraw_success() { &sorobanvec![&test.env, amount], &sorobanvec![&test.env, amount], &users[0], - &false + &false, ); let df_balance = defindex_contract.balance(&users[0]); - assert_eq!(df_balance, amount - 1000); + assert_eq!(df_balance, amount - 1000); - // Balance of the token0 on the vault should be `amount` since it is deposited into the vault first - let vault_balance_of_token = test.token0.balance(&defindex_contract.address); + // Balance of the token_0 on the vault should be `amount` since it is deposited into the vault first + let vault_balance_of_token = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance_of_token, amount); - + let investments = sorobanvec![ &test.env, Some(AssetInvestmentAllocation { - asset: test.token0.address.clone(), + asset: test.token_0.address.clone(), strategy_allocations: sorobanvec![ &test.env, Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), + strategy_address: test.strategy_client_token_0.address.clone(), amount: amount, }), ], }), ]; - defindex_contract.invest(&investments); - // Balance of the token0 on the vault should be 0 - let vault_balance_of_token = test.token0.balance(&defindex_contract.address); + // Balance of the token_0 on the vault should be 0 + let vault_balance_of_token = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance_of_token, 0); // Balance of the vault on the strategy contract should be `amount` let strategy_balance = test - .strategy_client_token0 + .strategy_client_token_0 .balance(&defindex_contract.address); assert_eq!(strategy_balance, amount); defindex_contract.emergency_withdraw( - &strategy_params_token0.first().unwrap().address, + &strategy_params_token_0.first().unwrap().address, &test.emergency_manager, ); // Balance of the vault on the strategy should be 0 let strategy_balance = test - .strategy_client_token0 + .strategy_client_token_0 .balance(&defindex_contract.address); assert_eq!(strategy_balance, 0); - // Balance of the token0 on the vault should be `amount` - let vault_balance_of_token = test.token0.balance(&defindex_contract.address); + // Balance of the token_0 on the vault should be `amount` + let vault_balance_of_token = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance_of_token, amount); // check if strategy is paused diff --git a/apps/contracts/vault/src/test/vault/fees.rs b/apps/contracts/vault/src/test/vault/fees.rs index 5747834b..2ddca4a0 100644 --- a/apps/contracts/vault/src/test/vault/fees.rs +++ b/apps/contracts/vault/src/test/vault/fees.rs @@ -1,6 +1,5 @@ - // test fees are correctly calculated and harvested (todo) -#[test] +#[test] fn test_fees() { todo!(); } 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 8efa8816..2a4bcfcd 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,31 +1,30 @@ -use soroban_sdk::{vec as sorobanvec, String, Vec, Map}; +use soroban_sdk::{vec as sorobanvec, Map, String, Vec}; use crate::test::defindex_vault::{AssetStrategySet, ContractError}; use crate::test::{ - create_defindex_vault, create_strategy_params_token0, create_strategy_params_token1, DeFindexVaultTest + create_defindex_vault, create_strategy_params_token_0, create_strategy_params_token_1, + DeFindexVaultTest, }; - - // test get_asset_amounts_per_shares function after every deposit // do a bunch of deposits with different ratios and check that shares are calculated correctly #[test] fn deposit_several_assets_get_asset_amounts_per_shares() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + 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.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -39,8 +38,12 @@ fn deposit_several_assets_get_asset_amounts_per_shares() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount0 = 123456789i128; @@ -49,11 +52,11 @@ fn deposit_several_assets_get_asset_amounts_per_shares() { let users = DeFindexVaultTest::generate_random_users(&test.env, 2); // Balances before deposit - test.token0_admin_client.mint(&users[0], &amount0); - test.token1_admin_client.mint(&users[0], &amount1); - let user_balance0 = test.token0.balance(&users[0]); + test.token_0_admin_client.mint(&users[0], &amount0); + test.token_1_admin_client.mint(&users[0], &amount1); + let user_balance0 = test.token_0.balance(&users[0]); assert_eq!(user_balance0, amount0); - let user_balance1 = test.token1.balance(&users[0]); + let user_balance1 = test.token_1.balance(&users[0]); assert_eq!(user_balance1, amount1); let df_balance = defindex_contract.balance(&users[0]); @@ -77,98 +80,96 @@ fn deposit_several_assets_get_asset_amounts_per_shares() { 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 = {token0: 0, token1: 0} + // result1_should = {token_0: 0, token_1: 0} let mut result1_should = Map::new(&test.env); - result1_should.set(test.token0.address.clone(), 0i128); - result1_should.set(test.token1.address.clone(), 0i128); + 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 token0: + // 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 token1: + + // 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 = {token0: 111, token1: 888} + // result2_should = {token_0: 111, token_1: 888} let mut result2_should = Map::new(&test.env); - result2_should.set(test.token0.address.clone(), 111i128); - result2_should.set(test.token1.address.clone(), 888i128); + 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 token0: + // 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 token1: + + // 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 = {token0: 222, token1: 1777} + // result3_should = {token_0: 222, token_1: 1777} let mut result3_should = Map::new(&test.env); - result3_should.set(test.token0.address.clone(), 222i128); - result3_should.set(test.token1.address.clone(), 1777i128); + 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 token0: + // 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 token1: + + // 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 = {token0: 333, token1: 2666} + // result4_should = {token_0: 333, token_1: 2666} let mut result4_should = Map::new(&test.env); - result4_should.set(test.token0.address.clone(), 333i128); - result4_should.set(test.token1.address.clone(), 2666i128); + 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 token0: + // 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 token1: + + // 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 = {token0: 444, token1: 3555} + // result5_should = {token_0: 444, token_1: 3555} let mut result5_should = Map::new(&test.env); - result5_should.set(test.token0.address.clone(), 444i128); - result5_should.set(test.token1.address.clone(), 3555i128); + 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 token0: + // 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 token1: + + // 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 = {token0: 555, token1: 4444} + // result6_should = {token_0: 555, token_1: 4444} let mut result6_should = Map::new(&test.env); - result6_should.set(test.token0.address.clone(), 555i128); - result6_should.set(test.token1.address.clone(), 4444i128); + 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))); - } #[test] fn deposit_and_invest_several_assets_get_asset_amounts_per_shares() { todo!(); - } diff --git a/apps/contracts/vault/src/test/vault/initialize.rs b/apps/contracts/vault/src/test/vault/initialize.rs index 18da0978..8f60133d 100644 --- a/apps/contracts/vault/src/test/vault/initialize.rs +++ b/apps/contracts/vault/src/test/vault/initialize.rs @@ -1,24 +1,24 @@ use soroban_sdk::{vec as sorobanvec, String, Vec}; use crate::test::{ - create_defindex_vault, create_strategy_params_token0, create_strategy_params_token1, defindex_vault::AssetStrategySet, DeFindexVaultTest + create_defindex_vault, create_strategy_params_token_0, create_strategy_params_token_1, + defindex_vault::AssetStrategySet, DeFindexVaultTest, }; - #[test] fn get_roles() { let test = DeFindexVaultTest::setup(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); + let strategy_params_token_1 = create_strategy_params_token_1(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -32,8 +32,12 @@ fn get_roles() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let manager_role = defindex_contract.get_manager(); @@ -45,23 +49,22 @@ fn get_roles() { assert_eq!(emergency_manager_role, test.emergency_manager); } - // Test that if strategy does support other asset we get an error when initializing #[test] #[should_panic(expected = "HostError: Error(Context, InvalidAction)")] fn deploy_unsupported_strategy() { let test = DeFindexVaultTest::setup(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token0.clone() // Here Strategy 0 supports token0 + address: test.token_1.address.clone(), + strategies: strategy_params_token_0.clone() // Here Strategy 0 supports token_0 } ]; @@ -75,8 +78,12 @@ fn deploy_unsupported_strategy() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); } @@ -85,7 +92,7 @@ fn deploy_unsupported_strategy() { #[should_panic(expected = "HostError: Error(Context, InvalidAction)")] fn initialize_with_empty_asset_allocation() { let test = DeFindexVaultTest::setup(); - // let strategy_params_token0 = create_strategy_params_token0(&test); + // let strategy_params_token_0 = create_strategy_params_token_0(&test); let assets: Vec = sorobanvec![&test.env]; @@ -99,8 +106,12 @@ fn initialize_with_empty_asset_allocation() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); } @@ -108,4 +119,4 @@ fn initialize_with_empty_asset_allocation() { #[test] fn with_one_asset_and_several_strategies() { todo!(); -} \ No newline at end of file +} diff --git a/apps/contracts/vault/src/test/vault/invest.rs b/apps/contracts/vault/src/test/vault/invest.rs index d1e42039..4b7dff51 100644 --- a/apps/contracts/vault/src/test/vault/invest.rs +++ b/apps/contracts/vault/src/test/vault/invest.rs @@ -1,38 +1,35 @@ -use soroban_sdk::{vec as sorobanvec, String, Vec, Map, vec}; use soroban_sdk::{ testutils::{MockAuth, MockAuthInvoke}, IntoVal, }; +use soroban_sdk::{vec as sorobanvec, vec, Map, String, Vec}; use crate::test::defindex_vault::{ - CurrentAssetInvestmentAllocation, - AssetStrategySet, - AssetInvestmentAllocation, - StrategyAllocation, - Strategy, - ContractError}; + AssetInvestmentAllocation, AssetStrategySet, ContractError, CurrentAssetInvestmentAllocation, + Strategy, StrategyAllocation, +}; use crate::test::{ - create_defindex_vault, create_strategy_params_token0, create_strategy_params_token1, DeFindexVaultTest + create_defindex_vault, 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() { let test = DeFindexVaultTest::setup(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); + let strategy_params_token_1 = create_strategy_params_token_1(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -46,29 +43,32 @@ fn wrong_asset_investment_length() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); // now will try to invest with less lengh (only one instead of 2) let asset_investments = vec![ &test.env, Some(AssetInvestmentAllocation { - asset: test.token0.address.clone(), - strategy_allocations: vec![ - &test.env, - Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 100, - })], - }) // First Asset + asset: test.token_0.address.clone(), + strategy_allocations: vec![ + &test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 100, + }), + ], + }), // First Asset ]; test.env.mock_all_auths(); // TODO, Mock only Manager - let result = defindex_contract.try_invest( - &asset_investments, - ); + let result = defindex_contract.try_invest(&asset_investments); assert_eq!(result, Err(Ok(ContractError::WrongInvestmentLength))); @@ -76,23 +76,22 @@ fn wrong_asset_investment_length() { let asset_investments = vec![ &test.env, Some(AssetInvestmentAllocation { - asset: test.token0.address.clone(), - strategy_allocations: vec![ - &test.env, - Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 100, - }) - ], - }), - None, - None]; + asset: test.token_0.address.clone(), + strategy_allocations: vec![ + &test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 100, + }), + ], + }), + None, + None, + ]; test.env.mock_all_auths(); // TODO, Mock only Manager - let result = defindex_contract.try_invest( - &asset_investments, - ); + let result = defindex_contract.try_invest(&asset_investments); assert_eq!(result, Err(Ok(ContractError::WrongInvestmentLength))); } @@ -102,27 +101,27 @@ fn wrong_asset_investment_length() { fn wrong_strategy_length() { let test = DeFindexVaultTest::setup(); - let strategy_params_token0 = create_strategy_params_token0(&test); - // let strategy_params_token1 = create_strategy_params_token1(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); + // let strategy_params_token_1 = create_strategy_params_token_1(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), + address: test.token_1.address.clone(), strategies: sorobanvec![ &test.env, Strategy { name: String::from_str(&test.env, "Strategy 1"), - address: test.strategy_client_token1.address.clone(), + address: test.strategy_client_token_1.address.clone(), paused: false, }, Strategy { name: String::from_str(&test.env, "Strategy 2"), - address: test.strategy_client_token1.address.clone(), + address: test.strategy_client_token_1.address.clone(), paused: false, } ] @@ -139,34 +138,37 @@ fn wrong_strategy_length() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); // now will try to invest with more strategy length for asset 0 let asset_investments = vec![ &test.env, Some(AssetInvestmentAllocation { - asset: test.token0.address.clone(), - strategy_allocations: vec![ - &test.env, - Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 100, - }), - Some(StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), - amount: 100, - }), - ], - }), - None]; + asset: test.token_0.address.clone(), + strategy_allocations: vec![ + &test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 100, + }), + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: 100, + }), + ], + }), + None, + ]; test.env.mock_all_auths(); // TODO, Mock only Manager - let result = defindex_contract.try_invest( - &asset_investments, - ); + let result = defindex_contract.try_invest(&asset_investments); assert_eq!(result, Err(Ok(ContractError::WrongStrategiesLength))); @@ -174,33 +176,29 @@ fn wrong_strategy_length() { let asset_investments = vec![ &test.env, Some(AssetInvestmentAllocation { - asset: test.token0.address.clone(), - strategy_allocations: vec![ - &test.env, // 0 instead of 1 + asset: test.token_0.address.clone(), + strategy_allocations: vec![ + &test.env, // 0 instead of 1 ], }), Some(AssetInvestmentAllocation { - asset: test.token1.address.clone(), + asset: test.token_1.address.clone(), strategy_allocations: vec![ &test.env, Some(StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), - amount: 100, + strategy_address: test.strategy_client_token_1.address.clone(), + amount: 100, }), - None - ] - }) + None, + ], + }), ]; test.env.mock_all_auths(); // TODO, Mock only Manager - let result = defindex_contract.try_invest( - &asset_investments, - ); + let result = defindex_contract.try_invest(&asset_investments); assert_eq!(result, Err(Ok(ContractError::WrongStrategiesLength))); - - } // check that fails if asset address is wrong @@ -208,18 +206,18 @@ fn wrong_strategy_length() { fn wrong_asset_address() { let test = DeFindexVaultTest::setup(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); + let strategy_params_token_1 = create_strategy_params_token_1(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -233,31 +231,33 @@ fn wrong_asset_address() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); // now will try to invest with wrong asset address let asset_investments = vec![ &test.env, Some(AssetInvestmentAllocation { - asset: test.token1.address.clone(), // wrong address, should be asset 0 - strategy_allocations: vec![ - &test.env, - Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 100, - }), - ], - }), - None // for asset + asset: test.token_1.address.clone(), // wrong address, should be asset 0 + strategy_allocations: vec![ + &test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 100, + }), + ], + }), + None, // for asset ]; test.env.mock_all_auths(); // TODO, Mock only Manager - let result = defindex_contract.try_invest( - &asset_investments, - ); + let result = defindex_contract.try_invest(&asset_investments); assert_eq!(result, Err(Ok(ContractError::WrongAssetAddress))); } @@ -267,18 +267,18 @@ fn wrong_asset_address() { fn negative_amount() { let test = DeFindexVaultTest::setup(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); + let strategy_params_token_1 = create_strategy_params_token_1(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -292,31 +292,33 @@ fn negative_amount() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); // now will try to invest with negative amount let asset_investments = vec![ &test.env, Some(AssetInvestmentAllocation { - asset: test.token0.address.clone(), - strategy_allocations: vec![ - &test.env, - Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: -100, // negative amount - }), - ], - }), - None // for asset 1 + asset: test.token_0.address.clone(), + strategy_allocations: vec![ + &test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: -100, // negative amount + }), + ], + }), + None, // for asset 1 ]; test.env.mock_all_auths(); // TODO, Mock only Manager - let result = defindex_contract.try_invest( - &asset_investments, - ); + let result = defindex_contract.try_invest(&asset_investments); assert_eq!(result, Err(Ok(ContractError::NegativeNotAllowed))); } @@ -326,18 +328,18 @@ fn negative_amount() { fn paused_strategy() { let test = DeFindexVaultTest::setup(); - let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), + address: test.token_0.address.clone(), strategies: sorobanvec![ &test.env, Strategy { name: String::from_str(&test.env, "Strategy 0"), - address: test.strategy_client_token0.address.clone(), + address: test.strategy_client_token_0.address.clone(), paused: true, - } ] + } + ] } ]; @@ -351,51 +353,53 @@ fn paused_strategy() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); - // now will try to invest with some amount + // now will try to invest with some amount let asset_investments = vec![ &test.env, Some(AssetInvestmentAllocation { - asset: test.token0.address.clone(), - strategy_allocations: vec![ - &test.env, - Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 100, - }), - ], - })]; - + asset: test.token_0.address.clone(), + strategy_allocations: vec![ + &test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 100, + }), + ], + }), + ]; + test.env.mock_all_auths(); // TODO, Mock only Manager - let result = defindex_contract.try_invest( - &asset_investments, - ); + let result = defindex_contract.try_invest(&asset_investments); assert_eq!(result, Err(Ok(ContractError::StrategyPaused))); } - // invest in strategy should work #[test] fn in_strategy() { let test = DeFindexVaultTest::setup(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); + let strategy_params_token_1 = create_strategy_params_token_1(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -409,208 +413,230 @@ fn in_strategy() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let users = DeFindexVaultTest::generate_random_users(&test.env, 1); let amount_0 = 987654321i128; let amount_1 = 123456789i128; - - test.env.mock_all_auths(); + + test.env.mock_all_auths(); // mint - test.token0_admin_client.mint(&users[0], &amount_0); - test.token1_admin_client.mint(&users[0], &amount_1); + test.token_0_admin_client.mint(&users[0], &amount_0); + test.token_1_admin_client.mint(&users[0], &amount_1); // check user amount - let user_amount_0 = test.token0.balance(&users[0]); - let user_amount_1 = test.token1.balance(&users[0]); - + let user_amount_0 = test.token_0.balance(&users[0]); + let user_amount_1 = test.token_1.balance(&users[0]); + assert_eq!(user_amount_0, amount_0); assert_eq!(user_amount_1, amount_1); - defindex_contract.deposit( &sorobanvec![&test.env, amount_0, amount_1], // asset 0 - &sorobanvec![&test.env, amount_0, amount_1], // asset 1 + &sorobanvec![&test.env, amount_0, amount_1], // asset 1 &users[0], &false, ); - // check balances after deposit let df_balance = defindex_contract.balance(&users[0]); assert_eq!(df_balance, amount_0 + amount_1 - 1000); // check that all the assets are in the vault - let vault_balance_0 = test.token0.balance(&defindex_contract.address); - let vault_balance_1 = test.token1.balance(&defindex_contract.address); + let vault_balance_0 = test.token_0.balance(&defindex_contract.address); + let vault_balance_1 = test.token_1.balance(&defindex_contract.address); assert_eq!(vault_balance_0, amount_0); assert_eq!(vault_balance_1, amount_1); - - + let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected_token_0 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 0, // funds have not been invested yet! - }]; - let strategy_investments_expected_token_1 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), - amount: 0, // funds have not been invested yet! - }]; - total_managed_funds_expected.set(test.token0.address.clone(), - CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), - total_amount: amount_0, - idle_amount: amount_0, - invested_amount: 0i128, - strategy_allocations: strategy_investments_expected_token_0, - }); - total_managed_funds_expected.set(test.token1.address.clone(), - CurrentAssetInvestmentAllocation { - asset: test.token1.address.clone(), - total_amount: amount_1, - idle_amount: amount_1, - invested_amount: 0i128, - strategy_allocations: strategy_investments_expected_token_1, - }); - + let strategy_investments_expected_token_0 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, // funds have not been invested yet! + } + ]; + let strategy_investments_expected_token_1 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: 0, // funds have not been invested yet! + } + ]; + total_managed_funds_expected.set( + test.token_0.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_0.address.clone(), + total_amount: amount_0, + idle_amount: amount_0, + invested_amount: 0i128, + strategy_allocations: strategy_investments_expected_token_0, + }, + ); + total_managed_funds_expected.set( + test.token_1.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_1.address.clone(), + total_amount: amount_1, + idle_amount: amount_1, + invested_amount: 0i128, + strategy_allocations: strategy_investments_expected_token_1, + }, + ); + let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); - - // check current idle funds, let mut expected_map = Map::new(&test.env); - expected_map.set(test.token0.address.clone(), amount_0); - expected_map.set(test.token1.address.clone(), amount_1); + expected_map.set(test.token_0.address.clone(), amount_0); + expected_map.set(test.token_1.address.clone(), amount_1); let current_idle_funds = defindex_contract.fetch_current_idle_funds(); assert_eq!(current_idle_funds, expected_map); // check that current invested funds is now 0, funds still in idle funds let mut expected_map = Map::new(&test.env); - expected_map.set(test.token0.address.clone(), 0i128); - expected_map.set(test.token1.address.clone(), 0i128); + expected_map.set(test.token_0.address.clone(), 0i128); + expected_map.set(test.token_1.address.clone(), 0i128); let current_invested_funds = defindex_contract.fetch_current_invested_funds(); assert_eq!(current_invested_funds, expected_map); - // Prepare investments object let asset_investments = vec![ &test.env, Some(AssetInvestmentAllocation { - asset: test.token0.address.clone(), - strategy_allocations: vec![ - &test.env, - Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 100, - }), - ], - }), - Some(AssetInvestmentAllocation { - asset: test.token1.address.clone(), - strategy_allocations: vec![ - &test.env, - Some(StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), - amount: 200, - }), - ], - })]; + asset: test.token_0.address.clone(), + strategy_allocations: vec![ + &test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 100, + }), + ], + }), + Some(AssetInvestmentAllocation { + asset: test.token_1.address.clone(), + strategy_allocations: vec![ + &test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: 200, + }), + ], + }), + ]; - defindex_contract.invest( - &asset_investments, - ); + defindex_contract.invest(&asset_investments); // now only amunt_0 - 100 should be in the vault as idle funds - let vault_balance_0 = test.token0.balance(&defindex_contract.address); - let vault_balance_1 = test.token1.balance(&defindex_contract.address); + let vault_balance_0 = test.token_0.balance(&defindex_contract.address); + let vault_balance_1 = test.token_1.balance(&defindex_contract.address); assert_eq!(vault_balance_0, amount_0 - 100); assert_eq!(vault_balance_1, amount_1 - 200); // check total managed funds let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected_token_0 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 100, - }]; - let strategy_investments_expected_token_1 = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), - amount: 200, - }]; - total_managed_funds_expected.set(test.token0.address.clone(), - CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), - total_amount: amount_0, - idle_amount: amount_0 - 100, - invested_amount: 100i128, - strategy_allocations: strategy_investments_expected_token_0, - }); - total_managed_funds_expected.set(test.token1.address.clone(), - CurrentAssetInvestmentAllocation { - asset: test.token1.address.clone(), - total_amount: amount_1, - idle_amount: amount_1 - 200, - invested_amount: 200i128, - strategy_allocations: strategy_investments_expected_token_1, - }); + let strategy_investments_expected_token_0 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 100, + } + ]; + let strategy_investments_expected_token_1 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: 200, + } + ]; + total_managed_funds_expected.set( + test.token_0.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_0.address.clone(), + total_amount: amount_0, + idle_amount: amount_0 - 100, + invested_amount: 100i128, + strategy_allocations: strategy_investments_expected_token_0, + }, + ); + total_managed_funds_expected.set( + test.token_1.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_1.address.clone(), + total_amount: amount_1, + idle_amount: amount_1 - 200, + invested_amount: 200i128, + strategy_allocations: strategy_investments_expected_token_1, + }, + ); let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); - // check current idle funds, for token0 should be amount 0 - 100 + // check current idle funds, for token_0 should be amount 0 - 100 let mut expected_map = Map::new(&test.env); - expected_map.set(test.token0.address.clone(), amount_0 - 100); - expected_map.set(test.token1.address.clone(), amount_1 - 200); + expected_map.set(test.token_0.address.clone(), amount_0 - 100); + expected_map.set(test.token_1.address.clone(), amount_1 - 200); let current_idle_funds = defindex_contract.fetch_current_idle_funds(); assert_eq!(current_idle_funds, expected_map); // check that current invested funds is now 100 and 200 let mut expected_map = Map::new(&test.env); - expected_map.set(test.token0.address.clone(), 100i128); - expected_map.set(test.token1.address.clone(), 200i128); + expected_map.set(test.token_0.address.clone(), 100i128); + expected_map.set(test.token_1.address.clone(), 200i128); let current_invested_funds = defindex_contract.fetch_current_invested_funds(); assert_eq!(current_invested_funds, expected_map); // check that 100 and 200 are invested in the strategies - let strategy_0_balance = test.strategy_client_token0.balance(&defindex_contract.address); - let strategy_1_balance = test.strategy_client_token1.balance(&defindex_contract.address); + let strategy_0_balance = test + .strategy_client_token_0 + .balance(&defindex_contract.address); + let strategy_1_balance = test + .strategy_client_token_1 + .balance(&defindex_contract.address); assert_eq!(strategy_0_balance, 100); assert_eq!(strategy_1_balance, 200); // if we ask strategy.balance(vault) they should be 100 and 200 - let strategy_0_balance = test.strategy_client_token0.balance(&defindex_contract.address); - let strategy_1_balance = test.strategy_client_token1.balance(&defindex_contract.address); + let strategy_0_balance = test + .strategy_client_token_0 + .balance(&defindex_contract.address); + let strategy_1_balance = test + .strategy_client_token_1 + .balance(&defindex_contract.address); assert_eq!(strategy_0_balance, 100); assert_eq!(strategy_1_balance, 200); - - - } // check that try to invest more than idle funds return balance error #[test] #[should_panic(expected = "HostError: Error(Contract, #10)")] // balance is not sufficient to spend -// we get the error from the token contract + // we get the error from the token contract fn more_than_idle_funds() { let test = DeFindexVaultTest::setup(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); + let strategy_params_token_1 = create_strategy_params_token_1(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -624,69 +650,71 @@ fn more_than_idle_funds() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let users = DeFindexVaultTest::generate_random_users(&test.env, 1); let amount_0 = 987654321i128; let amount_1 = 123456789i128; - - test.env.mock_all_auths(); + + test.env.mock_all_auths(); // mint - test.token0_admin_client.mint(&users[0], &amount_0); - test.token1_admin_client.mint(&users[0], &amount_1); + test.token_0_admin_client.mint(&users[0], &amount_0); + test.token_1_admin_client.mint(&users[0], &amount_1); // check user amount - let user_amount_0 = test.token0.balance(&users[0]); - let user_amount_1 = test.token1.balance(&users[0]); - + let user_amount_0 = test.token_0.balance(&users[0]); + let user_amount_1 = test.token_1.balance(&users[0]); + assert_eq!(user_amount_0, amount_0); assert_eq!(user_amount_1, amount_1); - defindex_contract.deposit( &sorobanvec![&test.env, amount_0, amount_1], // asset 0 - &sorobanvec![&test.env, amount_0, amount_1], // asset 1 + &sorobanvec![&test.env, amount_0, amount_1], // asset 1 &users[0], &false, ); // check vault balances - let vault_balance_0 = test.token0.balance(&defindex_contract.address); - let vault_balance_1 = test.token1.balance(&defindex_contract.address); + let vault_balance_0 = test.token_0.balance(&defindex_contract.address); + let vault_balance_1 = test.token_1.balance(&defindex_contract.address); assert_eq!(vault_balance_0, amount_0); // try to invest vault_balance_0 + 1 for asset 0 let asset_investments = vec![ &test.env, Some(AssetInvestmentAllocation { - asset: test.token0.address.clone(), - strategy_allocations: vec![ - &test.env, - Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: vault_balance_0 + 1, - }), - ], - }), - Some(AssetInvestmentAllocation { - asset: test.token1.address.clone(), - strategy_allocations: vec![ - &test.env, - Some(StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), - amount: vault_balance_1 + 1, - }), - ], - })]; + asset: test.token_0.address.clone(), + strategy_allocations: vec![ + &test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: vault_balance_0 + 1, + }), + ], + }), + Some(AssetInvestmentAllocation { + asset: test.token_1.address.clone(), + strategy_allocations: vec![ + &test.env, + Some(StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: vault_balance_1 + 1, + }), + ], + }), + ]; test.env.mock_all_auths(); // TODO, Mock only Manager - defindex_contract.invest( - &asset_investments, - ); + defindex_contract.invest(&asset_investments); } // invest without mock aut, mocking only specific auths @@ -694,18 +722,18 @@ fn more_than_idle_funds() { fn without_mock_all_auths() { let test = DeFindexVaultTest::setup(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); + let strategy_params_token_1 = create_strategy_params_token_1(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -719,171 +747,180 @@ fn without_mock_all_auths() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let users = DeFindexVaultTest::generate_random_users(&test.env, 1); let amount_0 = 987654321i128; let amount_1 = 123456789i128; - // mock admin auth and mint - test.token0_admin_client.mock_auths(&[MockAuth { - address: &test.token0_admin.clone(), - invoke: &MockAuthInvoke { - contract: &test.token0.address.clone(), - fn_name: "mint", - args: (users[0].clone(), amount_0).into_val(&test.env), - sub_invokes: &[], - }, - }]).mint(&users[0], &amount_0); - - - test.token1_admin_client.mock_auths(&[MockAuth { - address: &test.token1_admin.clone(), - invoke: &MockAuthInvoke { - contract: &test.token1.address.clone(), - fn_name: "mint", - args: (users[0].clone(), amount_1).into_val(&test.env), - sub_invokes: &[], - }, - }]).mint(&users[0], &amount_1); + test.token_0_admin_client + .mock_auths(&[MockAuth { + address: &test.token_0_admin.clone(), + invoke: &MockAuthInvoke { + contract: &test.token_0.address.clone(), + fn_name: "mint", + args: (users[0].clone(), amount_0).into_val(&test.env), + sub_invokes: &[], + }, + }]) + .mint(&users[0], &amount_0); + + test.token_1_admin_client + .mock_auths(&[MockAuth { + address: &test.token_1_admin.clone(), + invoke: &MockAuthInvoke { + contract: &test.token_1.address.clone(), + fn_name: "mint", + args: (users[0].clone(), amount_1).into_val(&test.env), + sub_invokes: &[], + }, + }]) + .mint(&users[0], &amount_1); // check user amount - let user_amount_0 = test.token0.balance(&users[0]); - let user_amount_1 = test.token1.balance(&users[0]); - + let user_amount_0 = test.token_0.balance(&users[0]); + let user_amount_1 = test.token_1.balance(&users[0]); + assert_eq!(user_amount_0, amount_0); assert_eq!(user_amount_1, amount_1); - // mock deposit auth from user and deposit - defindex_contract.mock_auths(&[MockAuth { - address: &users[0].clone(), - invoke: &MockAuthInvoke { - contract: &defindex_contract.address.clone(), - fn_name: "deposit", - args: ( - Vec::from_array(&test.env,[amount_0, amount_1]), - Vec::from_array(&test.env,[amount_0, amount_1]), - users[0].clone(), - false - ).into_val(&test.env), - // mock toke 0 and token 1 subtransfer - sub_invokes: &[ - MockAuthInvoke { - contract: &test.token0.address.clone(), - fn_name: "transfer", - args: ( - users[0].clone(), - defindex_contract.address.clone(), - amount_0 - ).into_val(&test.env), - sub_invokes: &[] - }, - MockAuthInvoke { - contract: &test.token1.address.clone(), - fn_name: "transfer", - args: ( - users[0].clone(), - defindex_contract.address.clone(), - amount_1 - ).into_val(&test.env), - sub_invokes: &[] - }] - }, - }]).deposit( - &sorobanvec![&test.env, amount_0, amount_1], // asset 0 - &sorobanvec![&test.env, amount_0, amount_1], // asset 1 - &users[0], - &false, - ); + defindex_contract + .mock_auths(&[MockAuth { + address: &users[0].clone(), + invoke: &MockAuthInvoke { + contract: &defindex_contract.address.clone(), + fn_name: "deposit", + args: ( + Vec::from_array(&test.env, [amount_0, amount_1]), + Vec::from_array(&test.env, [amount_0, amount_1]), + users[0].clone(), + false, + ) + .into_val(&test.env), + // mock toke 0 and token 1 subtransfer + sub_invokes: &[ + MockAuthInvoke { + contract: &test.token_0.address.clone(), + fn_name: "transfer", + args: ( + users[0].clone(), + defindex_contract.address.clone(), + amount_0, + ) + .into_val(&test.env), + sub_invokes: &[], + }, + MockAuthInvoke { + contract: &test.token_1.address.clone(), + fn_name: "transfer", + args: ( + users[0].clone(), + defindex_contract.address.clone(), + amount_1, + ) + .into_val(&test.env), + sub_invokes: &[], + }, + ], + }, + }]) + .deposit( + &sorobanvec![&test.env, amount_0, amount_1], // asset 0 + &sorobanvec![&test.env, amount_0, amount_1], // asset 1 + &users[0], + &false, + ); // TODO check that the blockchain saw this authorizations // check vault balances - let vault_balance_0 = test.token0.balance(&defindex_contract.address); - let vault_balance_1 = test.token1.balance(&defindex_contract.address); + let vault_balance_0 = test.token_0.balance(&defindex_contract.address); + let vault_balance_1 = test.token_1.balance(&defindex_contract.address); assert_eq!(vault_balance_0, amount_0); assert_eq!(vault_balance_1, amount_1); // mock auth from manager to invest and invest - defindex_contract.mock_auths(&[MockAuth { - address: &test.manager.clone(), - invoke: &MockAuthInvoke { - contract: &defindex_contract.address.clone(), - fn_name: "invest", - args: ( - Vec::from_array(&test.env,[ - Some( - AssetInvestmentAllocation { - asset: test.token0.address.clone(), - strategy_allocations: - sorobanvec![&test.env, - Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 100, - })] - } - ), - Some( - AssetInvestmentAllocation { - asset: test.token1.address.clone(), - strategy_allocations: sorobanvec![&test.env, + defindex_contract + .mock_auths(&[MockAuth { + address: &test.manager.clone(), + invoke: &MockAuthInvoke { + contract: &defindex_contract.address.clone(), + fn_name: "invest", + args: (Vec::from_array( + &test.env, + [ + Some(AssetInvestmentAllocation { + asset: test.token_0.address.clone(), + strategy_allocations: sorobanvec![ + &test.env, Some(StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 100, + }) + ], + }), + 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: 200, - })] - } - )]), - ).into_val(&test.env), - sub_invokes: &[] - }, - }]).invest( - &sorobanvec![ - &test.env, - Some( - AssetInvestmentAllocation { - asset: test.token0.address.clone(), - strategy_allocations: sorobanvec![&test.env, - Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 100, - })] - } - ), - Some( - AssetInvestmentAllocation { - asset: test.token1.address.clone(), - strategy_allocations: sorobanvec![&test.env, - Some(StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), - amount: 200, - })] - } - )] - ); + }) + ], + }), + ], + ),) + .into_val(&test.env), + sub_invokes: &[], + }, + }]) + .invest(&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: 100, + }) + ] + }), + 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: 200, + }) + ] + }) + ]); // check that now vault has amount0 -100 in token 0, and amount1 -200 in token 1 - let vault_balance_0 = test.token0.balance(&defindex_contract.address); - let vault_balance_1 = test.token1.balance(&defindex_contract.address); + let vault_balance_0 = test.token_0.balance(&defindex_contract.address); + let vault_balance_1 = test.token_1.balance(&defindex_contract.address); assert_eq!(vault_balance_0, amount_0 - 100); assert_eq!(vault_balance_1, amount_1 - 200); // check invested funds let current_invested_funds = defindex_contract.fetch_current_invested_funds(); let mut expected_map = Map::new(&test.env); - expected_map.set(test.token0.address.clone(), 100i128); - expected_map.set(test.token1.address.clone(), 200i128); + expected_map.set(test.token_0.address.clone(), 100i128); + expected_map.set(test.token_1.address.clone(), 200i128); assert_eq!(current_invested_funds, expected_map); - - } #[test] -fn one_asset_several_strategies() { - -} - +fn one_asset_several_strategies() {} diff --git a/apps/contracts/vault/src/test/vault/mod.rs b/apps/contracts/vault/src/test/vault/mod.rs index 3eced9bf..74e90a42 100644 --- a/apps/contracts/vault/src/test/vault/mod.rs +++ b/apps/contracts/vault/src/test/vault/mod.rs @@ -1,11 +1,11 @@ mod admin; -mod deposit_and_invest; +mod budget; mod deposit; +mod deposit_and_invest; mod emergency_withdraw; +mod fees; +mod get_asset_amounts_per_shares; mod initialize; mod invest; mod rebalance; mod withdraw; -mod fees; -mod get_asset_amounts_per_shares; -mod budget; \ No newline at end of file diff --git a/apps/contracts/vault/src/test/vault/rebalance.rs b/apps/contracts/vault/src/test/vault/rebalance.rs index 576a3e44..a53ce4f7 100644 --- a/apps/contracts/vault/src/test/vault/rebalance.rs +++ b/apps/contracts/vault/src/test/vault/rebalance.rs @@ -1,22 +1,25 @@ -use soroban_sdk::{vec as sorobanvec, InvokeError, String, Vec}; +use soroban_sdk::{vec as sorobanvec, Address, InvokeError, Map, String, Vec}; +use crate::test::defindex_vault::ContractError; use crate::test::{ - create_defindex_vault, create_strategy_params_token0, defindex_vault::{ - ActionType, AssetInvestmentAllocation, AssetStrategySet, Instruction, OptionalSwapDetailsExactIn, OptionalSwapDetailsExactOut, StrategyAllocation - }, DeFindexVaultTest + create_defindex_vault, create_strategy_params_token_0, create_strategy_params_token_1, + defindex_vault::{ + AssetInvestmentAllocation, AssetStrategySet, CurrentAssetInvestmentAllocation, Instruction, + StrategyAllocation, + }, + DeFindexVaultTest, }; -use crate::test::defindex_vault::ContractError; #[test] fn multi_instructions() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; @@ -30,15 +33,19 @@ fn multi_instructions() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount = 987654321i128; let users = DeFindexVaultTest::generate_random_users(&test.env, 1); - test.token0_admin_client.mint(&users[0], &amount); - let user_balance = test.token0.balance(&users[0]); + test.token_0_admin_client.mint(&users[0], &amount); + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, amount); let df_balance = defindex_contract.balance(&users[0]); @@ -48,7 +55,7 @@ fn multi_instructions() { &sorobanvec![&test.env, amount], &sorobanvec![&test.env, amount], &users[0], - &false + &false, ); let df_balance = defindex_contract.balance(&users[0]); @@ -57,11 +64,11 @@ fn multi_instructions() { let investments = sorobanvec![ &test.env, Some(AssetInvestmentAllocation { - asset: test.token0.address.clone(), + asset: test.token_0.address.clone(), strategy_allocations: sorobanvec![ &test.env, Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), + strategy_address: test.strategy_client_token_0.address.clone(), amount: amount, }), ], @@ -70,7 +77,7 @@ fn multi_instructions() { defindex_contract.invest(&investments); - let vault_balance = test.token0.balance(&defindex_contract.address); + let vault_balance = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance, 0); // REBALANCE @@ -80,25 +87,19 @@ fn multi_instructions() { let instructions = sorobanvec![ &test.env, - Instruction { - action: ActionType::Withdraw, - strategy: Some(test.strategy_client_token0.address.clone()), - amount: Some(instruction_amount_0), - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, - Instruction { - action: ActionType::Invest, - strategy: Some(test.strategy_client_token0.address.clone()), - amount: Some(instruction_amount_1), - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - } + Instruction::Withdraw( + test.strategy_client_token_0.address.clone(), + instruction_amount_0 + ), + Instruction::Invest( + test.strategy_client_token_0.address.clone(), + instruction_amount_1 + ), ]; defindex_contract.rebalance(&instructions); - let vault_balance = test.token0.balance(&defindex_contract.address); + let vault_balance = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance, instruction_amount_1); } @@ -106,12 +107,12 @@ fn multi_instructions() { fn one_instruction() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; @@ -125,15 +126,19 @@ fn one_instruction() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount = 987654321i128; let users = DeFindexVaultTest::generate_random_users(&test.env, 1); - test.token0_admin_client.mint(&users[0], &amount); - let user_balance = test.token0.balance(&users[0]); + test.token_0_admin_client.mint(&users[0], &amount); + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, amount); let df_balance = defindex_contract.balance(&users[0]); @@ -143,7 +148,7 @@ fn one_instruction() { &sorobanvec![&test.env, amount], &sorobanvec![&test.env, amount], &users[0], - &false + &false, ); let df_balance = defindex_contract.balance(&users[0]); @@ -152,11 +157,11 @@ fn one_instruction() { let investments = sorobanvec![ &test.env, Some(AssetInvestmentAllocation { - asset: test.token0.address.clone(), + asset: test.token_0.address.clone(), strategy_allocations: sorobanvec![ &test.env, Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), + strategy_address: test.strategy_client_token_0.address.clone(), amount: amount, }), ], @@ -165,7 +170,7 @@ fn one_instruction() { defindex_contract.invest(&investments); - let vault_balance = test.token0.balance(&defindex_contract.address); + let vault_balance = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance, 0); // REBALANCE @@ -174,32 +179,29 @@ fn one_instruction() { let instructions = sorobanvec![ &test.env, - Instruction { - action: ActionType::Withdraw, - strategy: Some(test.strategy_client_token0.address.clone()), - amount: Some(instruction_amount_0), - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, + Instruction::Withdraw( + test.strategy_client_token_0.address.clone(), + instruction_amount_0 + ), ]; defindex_contract.rebalance(&instructions); - let vault_balance = test.token0.balance(&defindex_contract.address); + let vault_balance = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance, instruction_amount_0); } #[test] -fn empty_instructions(){ +fn empty_instructions() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; let defindex_contract = create_defindex_vault( @@ -212,12 +214,16 @@ fn empty_instructions(){ test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount: i128 = 987654321; let users = DeFindexVaultTest::generate_random_users(&test.env, 1); - test.token0_admin_client.mint(&users[0], &amount); + test.token_0_admin_client.mint(&users[0], &amount); let vault_balance = defindex_contract.balance(&users[0]); assert_eq!(vault_balance, 0i128); @@ -225,62 +231,23 @@ fn empty_instructions(){ &sorobanvec![&test.env, amount], &sorobanvec![&test.env, amount], &users[0], - &false + &false, ); let df_balance = defindex_contract.balance(&users[0]); assert_eq!(df_balance, amount - 1000); - - let instructions = sorobanvec![ - &test.env, - Instruction { - action: ActionType::Withdraw, - strategy: None, - amount: None, - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, - ]; - let rebalance = defindex_contract.try_rebalance(&instructions); - assert_eq!(rebalance, Err(Ok(ContractError::MissingInstructionData))); - - let no_strategy_instructions = sorobanvec![ - &test.env, - Instruction { - action: ActionType::Withdraw, - strategy: Some(test.strategy_client_token0.address.clone()), - amount: None, - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, - ]; - let rebalance = defindex_contract.try_rebalance(&no_strategy_instructions); - assert_eq!(rebalance, Err(Ok(ContractError::MissingInstructionData))); - - let no_amount_instructions = sorobanvec![ - &test.env, - Instruction { - action: ActionType::Withdraw, - strategy: Some(test.strategy_client_token0.address.clone()), - amount: None, - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, - ]; - let rebalance = defindex_contract.try_rebalance(&no_amount_instructions); - assert_eq!(rebalance, Err(Ok(ContractError::MissingInstructionData))); } #[test] -fn no_instructions(){ +fn no_instructions() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; let defindex_contract = create_defindex_vault( @@ -293,12 +260,16 @@ fn no_instructions(){ test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount: i128 = 987654321; let users = DeFindexVaultTest::generate_random_users(&test.env, 1); - test.token0_admin_client.mint(&users[0], &amount); + test.token_0_admin_client.mint(&users[0], &amount); let vault_balance = defindex_contract.balance(&users[0]); assert_eq!(vault_balance, 0i128); @@ -306,7 +277,7 @@ fn no_instructions(){ &sorobanvec![&test.env, amount], &sorobanvec![&test.env, amount], &users[0], - &false + &false, ); let df_balance = defindex_contract.balance(&users[0]); assert_eq!(df_balance, amount - 1000); @@ -316,16 +287,16 @@ fn no_instructions(){ } #[test] -fn insufficient_balance(){ +fn insufficient_balance() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; let defindex_contract = create_defindex_vault( @@ -338,13 +309,17 @@ fn insufficient_balance(){ test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount: i128 = 987654321; let users = DeFindexVaultTest::generate_random_users(&test.env, 1); - test.token0_admin_client.mint(&users[0], &amount); - + test.token_0_admin_client.mint(&users[0], &amount); + //Balance should be 0 let vault_balance = defindex_contract.balance(&users[0]); assert_eq!(vault_balance, 0i128); @@ -352,29 +327,20 @@ fn insufficient_balance(){ //Withdraw with no funds let withdraw_no_funds_instructions = sorobanvec![ &test.env, - Instruction { - action: ActionType::Withdraw, - strategy: Some(test.strategy_client_token0.address.clone()), - amount: Some(amount + 1), - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, + Instruction::Withdraw(test.strategy_client_token_0.address.clone(), amount + 1), ]; let withdraw_no_funds = defindex_contract.try_rebalance(&withdraw_no_funds_instructions); - assert_eq!(withdraw_no_funds, Err(Ok(ContractError::StrategyWithdrawError))); //Contract should respond 'Insuficient balance'? + assert_eq!( + withdraw_no_funds, + Err(Ok(ContractError::StrategyWithdrawError)) + ); //Contract should respond 'Insuficient balance'? - //Invest with no funds let invest_no_funds_instructions = sorobanvec![ &test.env, - Instruction { - action: ActionType::Invest, - strategy: Some(test.strategy_client_token0.address.clone()), - amount: Some(1), - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, + Instruction::Invest(test.strategy_client_token_0.address.clone(), 1), ]; + let invest_no_funds = defindex_contract.try_rebalance(&invest_no_funds_instructions); //Contract should fail with error #10 no balance or panic the test @@ -387,7 +353,7 @@ fn insufficient_balance(){ &sorobanvec![&test.env, amount], &sorobanvec![&test.env, amount], &users[0], - &false + &false, ); let df_balance: i128 = defindex_contract.balance(&users[0]); assert_eq!(df_balance, amount - 1000); @@ -395,27 +361,16 @@ fn insufficient_balance(){ //Withdraw more than available let withdraw_instructions = sorobanvec![ &test.env, - Instruction { - action: ActionType::Withdraw, - strategy: Some(test.strategy_client_token0.address.clone()), - amount: Some(amount + 1), - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, + Instruction::Withdraw(test.strategy_client_token_0.address.clone(), amount + 1), ]; + let rebalance = defindex_contract.try_rebalance(&withdraw_instructions); assert_eq!(rebalance, Err(Ok(ContractError::StrategyWithdrawError))); - let invest_instructions = sorobanvec!( + let invest_instructions = sorobanvec![ &test.env, - Instruction { - action: ActionType::Invest, - strategy: Some(test.strategy_client_token0.address.clone()), - amount: Some(amount + 1), - swap_details_exact_in: OptionalSwapDetailsExactIn::None, - swap_details_exact_out: OptionalSwapDetailsExactOut::None, - }, - ); + Instruction::Invest(test.strategy_client_token_0.address.clone(), amount + 1), + ]; //Contract should fail with error #10 no balance let rebalance = defindex_contract.try_rebalance(&invest_instructions); @@ -426,5 +381,312 @@ fn insufficient_balance(){ } } +#[test] +fn swap_exact_in() { + 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 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 amount0 = 123456789i128; + let amount1 = 987654321i128; + + let users = DeFindexVaultTest::generate_random_users(&test.env, 2); + + test.token_0_admin_client.mint(&users[0], &amount0); + test.token_1_admin_client.mint(&users[0], &amount1); + + defindex_contract.deposit( + &sorobanvec![&test.env, amount0, amount1], + &sorobanvec![&test.env, amount0, amount1], + &users[0], + &false, + ); + + // check total managed funds + let mut total_managed_funds_expected = Map::new(&test.env); + let strategy_investments_expected_token_0 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, // funds have not been invested yet! + } + ]; + let strategy_investments_expected_token_1 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: 0, // funds have not been invested yet! + } + ]; + total_managed_funds_expected.set( + test.token_0.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_0.address.clone(), + total_amount: amount0, + idle_amount: amount0, + invested_amount: 0i128, + strategy_allocations: strategy_investments_expected_token_0, + }, + ); + total_managed_funds_expected.set( + test.token_1.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_1.address.clone(), + total_amount: amount1, + idle_amount: amount1, + invested_amount: 0i128, + strategy_allocations: strategy_investments_expected_token_1, + }, + ); + let total_managed_funds = defindex_contract.fetch_total_managed_funds(); + assert_eq!(total_managed_funds, total_managed_funds_expected); + + let amount_in = 1_000_000; + //(1000000×997×4000000000000000000)÷(1000000000000000000×1000+997×1000000) = 3987999,9 + let expected_amount_out = 3987999; + + // add one with part 1 and other with part 0 + let mut path: Vec
= Vec::new(&test.env); + path.push_back(test.token_0.address.clone()); + path.push_back(test.token_1.address.clone()); + + // Rebalance from here on + let instructions = sorobanvec![ + &test.env, + Instruction::SwapExactIn( + test.token_0.address.clone(), + test.token_1.address.clone(), + amount_in, + 0, // amount_out_min + test.env.ledger().timestamp() + 3600u64 + ), + ]; + + defindex_contract.rebalance(&instructions); + + // check total managed funds + let mut total_managed_funds_expected = Map::new(&test.env); + let strategy_investments_expected_token_0 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, // funds have not been invested yet! + } + ]; + let strategy_investments_expected_token_1 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: 0, // funds have not been invested yet! + } + ]; + total_managed_funds_expected.set( + test.token_0.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_0.address.clone(), + total_amount: amount0 - amount_in, + idle_amount: amount0 - amount_in, + invested_amount: 0i128, + strategy_allocations: strategy_investments_expected_token_0, + }, + ); + total_managed_funds_expected.set( + test.token_1.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_1.address.clone(), + total_amount: amount1 + expected_amount_out, + idle_amount: amount1 + expected_amount_out, + invested_amount: 0i128, + strategy_allocations: strategy_investments_expected_token_1, + }, + ); + let total_managed_funds = defindex_contract.fetch_total_managed_funds(); + assert_eq!(total_managed_funds, total_managed_funds_expected); +} + +#[test] +fn swap_exact_out() { + 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 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 amount0 = 123456789i128; + let amount1 = 987654321i128; + let users = DeFindexVaultTest::generate_random_users(&test.env, 2); + + test.token_0_admin_client.mint(&users[0], &amount0); + test.token_1_admin_client.mint(&users[0], &amount1); + + defindex_contract.deposit( + &sorobanvec![&test.env, amount0, amount1], + &sorobanvec![&test.env, amount0, amount1], + &users[0], + &false, + ); + + // check total managed funds + let mut total_managed_funds_expected = Map::new(&test.env); + let strategy_investments_expected_token_0 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, // funds have not been invested yet! + } + ]; + let strategy_investments_expected_token_1 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: 0, // funds have not been invested yet! + } + ]; + total_managed_funds_expected.set( + test.token_0.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_0.address.clone(), + total_amount: amount0, + idle_amount: amount0, + invested_amount: 0i128, + strategy_allocations: strategy_investments_expected_token_0, + }, + ); + total_managed_funds_expected.set( + test.token_1.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_1.address.clone(), + total_amount: amount1, + idle_amount: amount1, + invested_amount: 0i128, + strategy_allocations: strategy_investments_expected_token_1, + }, + ); + let total_managed_funds = defindex_contract.fetch_total_managed_funds(); + assert_eq!(total_managed_funds, total_managed_funds_expected); + + let expected_amount_out = 5_000_000; + // (r_in*amount_out)*1000 / (r_out - amount_out)*997 + // (1000000000000000000*5000000)*1000 / ((4000000000000000000 - 5000000)*997) + 1 = 1253762,2 + // because cealing div = 1253763 + let amount_in_should = 1253763; + + // add one with part 1 and other with part 0 + let mut path: Vec
= Vec::new(&test.env); + path.push_back(test.token_0.address.clone()); + path.push_back(test.token_1.address.clone()); + + // Rebalance from here on + let instructions = sorobanvec![ + &test.env, + Instruction::SwapExactOut( + test.token_0.address.clone(), + test.token_1.address.clone(), + expected_amount_out, //amount_out + amount_in_should, // amount_in_max + test.env.ledger().timestamp() + 3600u64 + ), + ]; + + defindex_contract.rebalance(&instructions); + + // check total managed funds + let mut total_managed_funds_expected = Map::new(&test.env); + let strategy_investments_expected_token_0 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, // funds have not been invested yet! + } + ]; + let strategy_investments_expected_token_1 = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: 0, // funds have not been invested yet! + } + ]; + total_managed_funds_expected.set( + test.token_0.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_0.address.clone(), + total_amount: amount0 - amount_in_should, + idle_amount: amount0 - amount_in_should, + invested_amount: 0i128, + strategy_allocations: strategy_investments_expected_token_0, + }, + ); + total_managed_funds_expected.set( + test.token_1.address.clone(), + CurrentAssetInvestmentAllocation { + asset: test.token_1.address.clone(), + total_amount: amount1 + expected_amount_out, + idle_amount: amount1 + expected_amount_out, + invested_amount: 0i128, + strategy_allocations: strategy_investments_expected_token_1, + }, + ); + let total_managed_funds = defindex_contract.fetch_total_managed_funds(); + assert_eq!(total_managed_funds, total_managed_funds_expected); +} diff --git a/apps/contracts/vault/src/test/vault/withdraw.rs b/apps/contracts/vault/src/test/vault/withdraw.rs index 956d0c89..d629543b 100644 --- a/apps/contracts/vault/src/test/vault/withdraw.rs +++ b/apps/contracts/vault/src/test/vault/withdraw.rs @@ -1,10 +1,13 @@ -use soroban_sdk::{vec as sorobanvec, String, Vec, Map}; +use soroban_sdk::{vec as sorobanvec, Map, String, Vec}; // use super::hodl_strategy::StrategyError; use crate::test::{ - create_defindex_vault, create_strategy_params_token0, create_strategy_params_token1, defindex_vault::{ - AssetInvestmentAllocation, AssetStrategySet, ContractError, CurrentAssetInvestmentAllocation, Strategy, StrategyAllocation - }, DeFindexVaultTest + create_defindex_vault, create_strategy_params_token_0, create_strategy_params_token_1, + defindex_vault::{ + AssetInvestmentAllocation, AssetStrategySet, ContractError, + CurrentAssetInvestmentAllocation, Strategy, StrategyAllocation, + }, + DeFindexVaultTest, }; // check that withdraw with negative amount after initialized returns error @@ -12,12 +15,12 @@ use crate::test::{ fn negative_amount() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; @@ -31,8 +34,12 @@ fn negative_amount() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let users = DeFindexVaultTest::generate_random_users(&test.env, 1); @@ -41,18 +48,17 @@ fn negative_amount() { assert_eq!(result, Err(Ok(ContractError::NegativeNotAllowed))); } - // check that withdraw without balance after initialized returns error AmountOverTotalSupply #[test] fn zero_total_supply() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; @@ -66,8 +72,12 @@ fn zero_total_supply() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let users = DeFindexVaultTest::generate_random_users(&test.env, 1); @@ -81,12 +91,12 @@ fn zero_total_supply() { fn not_enough_balance() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; @@ -100,57 +110,66 @@ fn not_enough_balance() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); // We need to generate 2 users, to have more total supply than the amount to withdraw let users = DeFindexVaultTest::generate_random_users(&test.env, 2); let amount_to_deposit = 567890i128; - test.token0_admin_client.mint(&users[0], &amount_to_deposit); - test.token0_admin_client.mint(&users[1], &amount_to_deposit); - - assert_eq!(test.token0.balance(&users[0]), amount_to_deposit); - assert_eq!(test.token0.balance(&users[1]), amount_to_deposit); + test.token_0_admin_client + .mint(&users[0], &amount_to_deposit); + test.token_0_admin_client + .mint(&users[1], &amount_to_deposit); + + assert_eq!(test.token_0.balance(&users[0]), amount_to_deposit); + assert_eq!(test.token_0.balance(&users[1]), amount_to_deposit); // first the user deposits defindex_contract.deposit( &sorobanvec![&test.env, amount_to_deposit], &sorobanvec![&test.env, amount_to_deposit], &users[0], - &false + &false, ); defindex_contract.deposit( &sorobanvec![&test.env, amount_to_deposit], &sorobanvec![&test.env, amount_to_deposit], &users[1], - &false + &false, ); // check that the every user has vault shares - assert_eq!(defindex_contract.balance(&users[0]), amount_to_deposit - 1000); + assert_eq!( + defindex_contract.balance(&users[0]), + amount_to_deposit - 1000 + ); assert_eq!(defindex_contract.balance(&users[1]), amount_to_deposit); // check that total supply of vault shares is indeed amount_to_deposit*2 - assert_eq!(defindex_contract.total_supply(), amount_to_deposit*2); - + assert_eq!(defindex_contract.total_supply(), amount_to_deposit * 2); + // now user 0 tries to withdraw amount_to_deposit - 1000 +1 (more that it has) - let result = defindex_contract.try_withdraw(&(amount_to_deposit - 1000 +1), &users[0]); + let result = defindex_contract.try_withdraw(&(amount_to_deposit - 1000 + 1), &users[0]); assert_eq!(result, Err(Ok(ContractError::InsufficientBalance))); } #[test] -fn from_idle_one_asset_one_strategy_success() { +fn from_idle_one_asset_one_strategy_success() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; @@ -164,15 +183,19 @@ fn from_idle_one_asset_one_strategy_success() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount = 1234567890i128; let users = DeFindexVaultTest::generate_random_users(&test.env, 1); - test.token0_admin_client.mint(&users[0], &amount); - let user_balance = test.token0.balance(&users[0]); + 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 @@ -191,17 +214,17 @@ fn from_idle_one_asset_one_strategy_success() { // Check Balances after deposit // Token balance of user - let user_balance = test.token0.balance(&users[0]); + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, amount - amount_to_deposit); // Token balance of vault should be amount_to_deposit // Because balances are still in indle, balances are not in strategy, but in idle - let vault_balance = test.token0.balance(&defindex_contract.address); + let vault_balance = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance, amount_to_deposit); // Token balance of hodl strategy should be 0 (all in idle) - let strategy_balance = test.token0.balance(&test.strategy_client_token0.address); + let strategy_balance = test.token_0.balance(&test.strategy_client_token_0.address); assert_eq!(strategy_balance, 0); // Df balance of user should be equal to deposited amount @@ -210,44 +233,46 @@ fn from_idle_one_asset_one_strategy_success() { // check total manage funds let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 0, //funds has not been invested yet! - }]; - total_managed_funds_expected.set(test.token0.address.clone(), + let strategy_investments_expected = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, //funds has not been invested yet! + } + ]; + total_managed_funds_expected.set( + test.token_0.address.clone(), CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), + asset: test.token_0.address.clone(), total_amount: amount_to_deposit, idle_amount: amount_to_deposit, invested_amount: 0i128, strategy_allocations: strategy_investments_expected, - } + }, ); let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); - // user decides to withdraw a portion of deposited amount let amount_to_withdraw = 123456i128; - defindex_contract - .withdraw(&amount_to_withdraw, &users[0]); + defindex_contract.withdraw(&amount_to_withdraw, &users[0]); // Check Balances after withdraw // Token balance of user should be amount - amount_to_deposit + amount_to_withdraw - let user_balance = test.token0.balance(&users[0]); + let user_balance = test.token_0.balance(&users[0]); assert_eq!( user_balance, amount - amount_to_deposit + amount_to_withdraw ); // Token balance of vault should be amount_to_deposit - amount_to_withdraw - let vault_balance = test.token0.balance(&defindex_contract.address); + let vault_balance = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance, amount_to_deposit - amount_to_withdraw); // Token balance of hodl strategy should be 0 (all in idle) - let strategy_balance = test.token0.balance(&test.strategy_client_token0.address); + let strategy_balance = test.token_0.balance(&test.strategy_client_token_0.address); assert_eq!(strategy_balance, 0); // Df balance of user should be equal to deposited amount - amount_to_withdraw - 1000 @@ -256,34 +281,36 @@ fn from_idle_one_asset_one_strategy_success() { // check total manage funds let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 0, //funds has not been invested yet! - }]; - total_managed_funds_expected.set(test.token0.address.clone(), + let strategy_investments_expected = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, //funds has not been invested yet! + } + ]; + total_managed_funds_expected.set( + test.token_0.address.clone(), CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), + asset: test.token_0.address.clone(), total_amount: amount_to_deposit - amount_to_withdraw, idle_amount: amount_to_deposit - amount_to_withdraw, invested_amount: 0i128, strategy_allocations: strategy_investments_expected, - } + }, ); let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); - // user tries to withdraw more than deposited amount let amount_to_withdraw_more = amount_to_deposit + 1; - let result = defindex_contract - .try_withdraw(&amount_to_withdraw_more, &users[0]); + let result = defindex_contract.try_withdraw(&amount_to_withdraw_more, &users[0]); assert_eq!(result, Err(Ok(ContractError::AmountOverTotalSupply))); // // withdraw remaining balance - let result = defindex_contract - .withdraw(&(amount_to_deposit - amount_to_withdraw - 1000), &users[0]); + let result = + defindex_contract.withdraw(&(amount_to_deposit - amount_to_withdraw - 1000), &users[0]); assert_eq!( result, @@ -293,45 +320,48 @@ fn from_idle_one_asset_one_strategy_success() { let df_balance = defindex_contract.balance(&users[0]); assert_eq!(df_balance, 0i128); - let user_balance = test.token0.balance(&users[0]); + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, amount - 1000); // check total manage funds let mut total_managed_funds_expected = Map::new(&test.env); - let strategy_investments_expected = sorobanvec![&test.env, StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 0, //funds has not been invested yet! - }]; - total_managed_funds_expected.set(test.token0.address.clone(), + let strategy_investments_expected = sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, //funds has not been invested yet! + } + ]; + total_managed_funds_expected.set( + test.token_0.address.clone(), CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), + asset: test.token_0.address.clone(), total_amount: 1000, idle_amount: 1000, invested_amount: 0i128, strategy_allocations: strategy_investments_expected, - } + }, ); let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); - } #[test] -fn from_idle_two_assets_success() { +fn from_idle_two_assets_success() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); + let strategy_params_token_1 = create_strategy_params_token_1(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; @@ -345,17 +375,21 @@ fn from_idle_two_assets_success() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount = 1234567890i128; let users = DeFindexVaultTest::generate_random_users(&test.env, 1); - test.token0_admin_client.mint(&users[0], &amount); - test.token1_admin_client.mint(&users[0], &amount); - assert_eq!(test.token0.balance(&users[0]), amount); - assert_eq!(test.token0.balance(&users[0]), amount); + test.token_0_admin_client.mint(&users[0], &amount); + test.token_1_admin_client.mint(&users[0], &amount); + assert_eq!(test.token_0.balance(&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); @@ -367,58 +401,82 @@ fn from_idle_two_assets_success() { &sorobanvec![&test.env, amount_to_deposit_0, amount_to_deposit_1], &sorobanvec![&test.env, amount_to_deposit_0, amount_to_deposit_1], &users[0], - &false + &false, ); // Check Balances after deposit // Token balance of user - assert_eq!(test.token0.balance(&users[0]), amount - amount_to_deposit_0); - assert_eq!(test.token1.balance(&users[0]), amount - amount_to_deposit_1); + assert_eq!( + test.token_0.balance(&users[0]), + amount - amount_to_deposit_0 + ); + assert_eq!( + test.token_1.balance(&users[0]), + amount - amount_to_deposit_1 + ); // Token balance of vault should be amount_to_deposit // Because balances are still in indle, balances are not in strategy, but in idle - assert_eq!(test.token0.balance(&defindex_contract.address), amount_to_deposit_0); - assert_eq!(test.token1.balance(&defindex_contract.address), amount_to_deposit_1); + assert_eq!( + test.token_0.balance(&defindex_contract.address), + amount_to_deposit_0 + ); + assert_eq!( + test.token_1.balance(&defindex_contract.address), + amount_to_deposit_1 + ); // Token balance of hodl strategy should be 0 (all in idle) - assert_eq!(test.token0.balance(&test.strategy_client_token0.address), 0); - assert_eq!(test.token1.balance(&test.strategy_client_token1.address), 0); + assert_eq!( + test.token_0.balance(&test.strategy_client_token_0.address), + 0 + ); + assert_eq!( + test.token_1.balance(&test.strategy_client_token_1.address), + 0 + ); // Df balance of user should be equal to amount_to_deposit_0+amount_to_deposit_1 - 1000 // 567890+987654-1000 = 1554544 let df_balance = defindex_contract.balance(&users[0]); - assert_eq!(df_balance, 1554544 ); + assert_eq!(df_balance, 1554544); // check total manage funds let mut total_managed_funds_expected = Map::new(&test.env); - total_managed_funds_expected.set(test.token0.address.clone(), + total_managed_funds_expected.set( + test.token_0.address.clone(), CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), + asset: test.token_0.address.clone(), total_amount: 567890i128, idle_amount: 567890i128, invested_amount: 0i128, - strategy_allocations: sorobanvec![&test.env, - StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 0, //funds has not been invested yet! - }], - } + strategy_allocations: sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, //funds has not been invested yet! + } + ], + }, ); - total_managed_funds_expected.set(test.token1.address.clone(), + total_managed_funds_expected.set( + test.token_1.address.clone(), CurrentAssetInvestmentAllocation { - asset: test.token1.address.clone(), + asset: test.token_1.address.clone(), total_amount: 987654i128, idle_amount: 987654i128, invested_amount: 0i128, - strategy_allocations: sorobanvec![&test.env, - StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), - amount: 0, //funds has not been invested yet! - }], - } + strategy_allocations: sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: 0, //funds has not been invested yet! + } + ], + }, ); let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); @@ -430,8 +488,7 @@ fn from_idle_two_assets_success() { // asset 1 = withdaw_shares*total_asset_1/total_shares = 123456*987654/1555544 = 78385.318720653 = 78385 let amount_to_withdraw = 123456i128; - let result = defindex_contract - .withdraw(&amount_to_withdraw, &users[0]); + let result = defindex_contract.withdraw(&amount_to_withdraw, &users[0]); // expected asset vec Vec // pub struct AssetStrategySet { @@ -443,89 +500,121 @@ fn from_idle_two_assets_success() { // pub name: String, // pub paused: bool, // } - let expected_asset_vec = sorobanvec![&test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: sorobanvec![&test.env, Strategy { - address: test.strategy_client_token0.address.clone(), - name: String::from_str(&test.env, "Strategy 1"), - paused: false, - }], - }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: sorobanvec![&test.env, Strategy { - address: test.strategy_client_token1.address.clone(), - name: String::from_str(&test.env, "Strategy 1"), - paused: false, - }], - }]; + let expected_asset_vec = sorobanvec![ + &test.env, + AssetStrategySet { + address: test.token_0.address.clone(), + strategies: sorobanvec![ + &test.env, + Strategy { + address: test.strategy_client_token_0.address.clone(), + name: String::from_str(&test.env, "Strategy 1"), + paused: false, + } + ], + }, + AssetStrategySet { + address: test.token_1.address.clone(), + strategies: sorobanvec![ + &test.env, + Strategy { + address: test.strategy_client_token_1.address.clone(), + name: String::from_str(&test.env, "Strategy 1"), + paused: false, + } + ], + } + ]; assert_eq!(defindex_contract.get_assets(), expected_asset_vec); let expected_result = sorobanvec![&test.env, 45070, 78385]; assert_eq!(result, expected_result); // Token balance of user - assert_eq!(test.token0.balance(&users[0]), amount - amount_to_deposit_0 + 45070); - assert_eq!(test.token1.balance(&users[0]), amount - amount_to_deposit_1 + 78385); + assert_eq!( + test.token_0.balance(&users[0]), + amount - amount_to_deposit_0 + 45070 + ); + assert_eq!( + test.token_1.balance(&users[0]), + amount - amount_to_deposit_1 + 78385 + ); // Token balance of vault (still idle) - assert_eq!(test.token0.balance(&defindex_contract.address), amount_to_deposit_0 - 45070); - assert_eq!(test.token1.balance(&defindex_contract.address), amount_to_deposit_1 - 78385); + assert_eq!( + test.token_0.balance(&defindex_contract.address), + amount_to_deposit_0 - 45070 + ); + assert_eq!( + test.token_1.balance(&defindex_contract.address), + amount_to_deposit_1 - 78385 + ); // Token balance of hodl strategy should be 0 (all in idle) - assert_eq!(test.token0.balance(&test.strategy_client_token0.address), 0); - assert_eq!(test.token1.balance(&test.strategy_client_token1.address), 0); + assert_eq!( + test.token_0.balance(&test.strategy_client_token_0.address), + 0 + ); + assert_eq!( + test.token_1.balance(&test.strategy_client_token_1.address), + 0 + ); // Df balance of user should be equal to amount_to_deposit_0+amount_to_deposit_1 - 1000 - 123456 // 567890+987654-1000 -123456 = 1434088 let df_balance = defindex_contract.balance(&users[0]); - assert_eq!(df_balance, 1431088 ); + assert_eq!(df_balance, 1431088); // check total manage funds let mut total_managed_funds_expected = Map::new(&test.env); - total_managed_funds_expected.set(test.token0.address.clone(), + total_managed_funds_expected.set( + test.token_0.address.clone(), CurrentAssetInvestmentAllocation { - asset: test.token0.address.clone(), + asset: test.token_0.address.clone(), total_amount: 567890i128 - 45070, idle_amount: 567890i128 - 45070, invested_amount: 0i128, - strategy_allocations: sorobanvec![&test.env, - StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), - amount: 0, //funds has not been invested yet! - }], - } + strategy_allocations: sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_0.address.clone(), + amount: 0, //funds has not been invested yet! + } + ], + }, ); - total_managed_funds_expected.set(test.token1.address.clone(), + total_managed_funds_expected.set( + test.token_1.address.clone(), CurrentAssetInvestmentAllocation { - asset: test.token1.address.clone(), + asset: test.token_1.address.clone(), total_amount: 987654i128 - 78385, idle_amount: 987654i128 - 78385, invested_amount: 0i128, - strategy_allocations: sorobanvec![&test.env, - StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), - amount: 0, //funds has not been invested yet! - }], - } + strategy_allocations: sorobanvec![ + &test.env, + StrategyAllocation { + strategy_address: test.strategy_client_token_1.address.clone(), + amount: 0, //funds has not been invested yet! + } + ], + }, ); let total_managed_funds = defindex_contract.fetch_total_managed_funds(); assert_eq!(total_managed_funds, total_managed_funds_expected); - } - #[test] fn from_strategy_one_asset_one_strategy_success() { let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() } ]; @@ -539,15 +628,19 @@ fn from_strategy_one_asset_one_strategy_success() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); let amount = 1000i128; let users = DeFindexVaultTest::generate_random_users(&test.env, 1); - test.token0_admin_client.mint(&users[0], &amount); - let user_balance = test.token0.balance(&users[0]); + 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 @@ -567,11 +660,11 @@ fn from_strategy_one_asset_one_strategy_success() { let investments = sorobanvec![ &test.env, Some(AssetInvestmentAllocation { - asset: test.token0.address.clone(), + asset: test.token_0.address.clone(), strategy_allocations: sorobanvec![ &test.env, Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), + strategy_address: test.strategy_client_token_0.address.clone(), amount: amount, }), ], @@ -580,7 +673,7 @@ fn from_strategy_one_asset_one_strategy_success() { defindex_contract.invest(&investments); - let vault_balance = test.token0.balance(&defindex_contract.address); + let vault_balance = test.token_0.balance(&defindex_contract.address); assert_eq!(vault_balance, 0); defindex_contract.withdraw(&df_balance, &users[0]); @@ -588,7 +681,7 @@ fn from_strategy_one_asset_one_strategy_success() { let df_balance = defindex_contract.balance(&users[0]); assert_eq!(df_balance, 0i128); - let user_balance = test.token0.balance(&users[0]); + let user_balance = test.token_0.balance(&users[0]); assert_eq!(user_balance, amount - 1000); } @@ -600,12 +693,12 @@ fn from_strategies_one_asset_two_strategies_success() { // let assets: Vec = sorobanvec![ // &test.env, // AssetStrategySet { - // address: test.token0.address.clone(), + // address: test.token_0.address.clone(), // strategies: sorobanvec![ - // &test.env, + // &test.env, // Strategy { // name: String::from_str(&test.env, "Strategy 1"), - // address: test.strategy_client_token0.address.clone(), + // address: test.strategy_client_token_0.address.clone(), // paused: false, // } // ] @@ -627,15 +720,15 @@ fn from_strategies_one_asset_two_strategies_success() { // let users = DeFindexVaultTest::generate_random_users(&test.env, 1); - // test.token0_admin_client.mint(&users[0], &amount); - // assert_eq!(test.token0.balance(&users[0]), amount); + // 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 + // // Deposit // let amount_to_deposit = 987654321i128; - + // defindex_contract.deposit( // &sorobanvec![&test.env, amount_to_deposit], // &sorobanvec![&test.env, amount_to_deposit], @@ -644,26 +737,24 @@ fn from_strategies_one_asset_two_strategies_success() { // ); // FIX invest in 2 stretegies for the same asset - } - #[test] fn from_strategies_two_asset_each_one_strategy_success() { // We will have two assets, each asset with one strategy let test = DeFindexVaultTest::setup(); test.env.mock_all_auths(); - let strategy_params_token0 = create_strategy_params_token0(&test); - let strategy_params_token1 = create_strategy_params_token1(&test); + let strategy_params_token_0 = create_strategy_params_token_0(&test); + let strategy_params_token_1 = create_strategy_params_token_1(&test); let assets: Vec = sorobanvec![ &test.env, AssetStrategySet { - address: test.token0.address.clone(), - strategies: strategy_params_token0.clone() + address: test.token_0.address.clone(), + strategies: strategy_params_token_0.clone() }, AssetStrategySet { - address: test.token1.address.clone(), - strategies: strategy_params_token1.clone() + address: test.token_1.address.clone(), + strategies: strategy_params_token_1.clone() } ]; // initialize @@ -677,16 +768,20 @@ fn from_strategies_two_asset_each_one_strategy_success() { test.defindex_protocol_receiver.clone(), 2500u32, test.defindex_factory.clone(), - String::from_str(&test.env, "dfToken"), - String::from_str(&test.env, "DFT"), + test.soroswap_router.address.clone(), + sorobanvec![ + &test.env, + String::from_str(&test.env, "dfToken"), + String::from_str(&test.env, "DFT") + ], ); - // mint + // mint let amount = 987654321i128; let users = DeFindexVaultTest::generate_random_users(&test.env, 1); - test.token0_admin_client.mint(&users[0], &amount); - test.token1_admin_client.mint(&users[0], &amount); - assert_eq!(test.token0.balance(&users[0]), amount); - assert_eq!(test.token1.balance(&users[0]), amount); + test.token_0_admin_client.mint(&users[0], &amount); + test.token_1_admin_client.mint(&users[0], &amount); + assert_eq!(test.token_0.balance(&users[0]), amount); + assert_eq!(test.token_1.balance(&users[0]), amount); // deposit let amount_to_deposit_0 = 123456789i128; @@ -696,47 +791,70 @@ fn from_strategies_two_asset_each_one_strategy_success() { &sorobanvec![&test.env, amount_to_deposit_0, amount_to_deposit_1], &sorobanvec![&test.env, amount_to_deposit_0, amount_to_deposit_1], &users[0], - &false + &false, ); // check deposit result. Ok((amounts, shares_to_mint)) // shares to mint = 123456789 + 234567890 = 358024679 assert_eq!(defindex_contract.total_supply(), 358024679); - assert_eq!(deposit_result, (sorobanvec![&test.env, amount_to_deposit_0, amount_to_deposit_1], 358024679)); - + assert_eq!( + deposit_result, + ( + sorobanvec![&test.env, amount_to_deposit_0, amount_to_deposit_1], + 358024679 + ) + ); // check balances - assert_eq!(test.token0.balance(&users[0]), amount - amount_to_deposit_0); - assert_eq!(test.token1.balance(&users[0]), amount - amount_to_deposit_1); + assert_eq!( + test.token_0.balance(&users[0]), + amount - amount_to_deposit_0 + ); + assert_eq!( + test.token_1.balance(&users[0]), + amount - amount_to_deposit_1 + ); // check vault balances - assert_eq!(test.token0.balance(&defindex_contract.address), amount_to_deposit_0); - assert_eq!(test.token1.balance(&defindex_contract.address), amount_to_deposit_1); + assert_eq!( + test.token_0.balance(&defindex_contract.address), + amount_to_deposit_0 + ); + assert_eq!( + test.token_1.balance(&defindex_contract.address), + amount_to_deposit_1 + ); // check strategy balances - assert_eq!(test.token0.balance(&test.strategy_client_token0.address), 0); - assert_eq!(test.token1.balance(&test.strategy_client_token1.address), 0); + assert_eq!( + test.token_0.balance(&test.strategy_client_token_0.address), + 0 + ); + assert_eq!( + test.token_1.balance(&test.strategy_client_token_1.address), + 0 + ); // invest in strategies. We will invest 100% of the idle funds let investments = sorobanvec![ &test.env, Some(AssetInvestmentAllocation { - asset: test.token0.address.clone(), + asset: test.token_0.address.clone(), strategy_allocations: sorobanvec![ &test.env, Some(StrategyAllocation { - strategy_address: test.strategy_client_token0.address.clone(), + strategy_address: test.strategy_client_token_0.address.clone(), amount: amount_to_deposit_0, }), ], }), Some(AssetInvestmentAllocation { - asset: test.token1.address.clone(), + asset: test.token_1.address.clone(), strategy_allocations: sorobanvec![ &test.env, Some(StrategyAllocation { - strategy_address: test.strategy_client_token1.address.clone(), + strategy_address: test.strategy_client_token_1.address.clone(), amount: amount_to_deposit_1, }), ], @@ -746,12 +864,18 @@ fn from_strategies_two_asset_each_one_strategy_success() { defindex_contract.invest(&investments); // check vault balances - assert_eq!(test.token0.balance(&defindex_contract.address), 0); - assert_eq!(test.token1.balance(&defindex_contract.address), 0); + assert_eq!(test.token_0.balance(&defindex_contract.address), 0); + assert_eq!(test.token_1.balance(&defindex_contract.address), 0); // check strategy balances - assert_eq!(test.token0.balance(&test.strategy_client_token0.address), amount_to_deposit_0); - assert_eq!(test.token1.balance(&test.strategy_client_token1.address), amount_to_deposit_1); + assert_eq!( + test.token_0.balance(&test.strategy_client_token_0.address), + amount_to_deposit_0 + ); + assert_eq!( + test.token_1.balance(&test.strategy_client_token_1.address), + amount_to_deposit_1 + ); //check user vault shares let df_balance = defindex_contract.balance(&users[0]); @@ -776,16 +900,28 @@ fn from_strategies_two_asset_each_one_strategy_success() { assert_eq!(result, expected_result); // check user balances - assert_eq!(test.token0.balance(&users[0]), amount - amount_to_deposit_0 + 12190874); - assert_eq!(test.token1.balance(&users[0]), amount - amount_to_deposit_1 + 23162660); + assert_eq!( + test.token_0.balance(&users[0]), + amount - amount_to_deposit_0 + 12190874 + ); + assert_eq!( + test.token_1.balance(&users[0]), + amount - amount_to_deposit_1 + 23162660 + ); // check vault balances - assert_eq!(test.token0.balance(&defindex_contract.address), 0); - assert_eq!(test.token1.balance(&defindex_contract.address), 0); + assert_eq!(test.token_0.balance(&defindex_contract.address), 0); + assert_eq!(test.token_1.balance(&defindex_contract.address), 0); // check strategy balances - assert_eq!(test.token0.balance(&test.strategy_client_token0.address), amount_to_deposit_0 - 12190874); - assert_eq!(test.token1.balance(&test.strategy_client_token1.address), amount_to_deposit_1 - 23162660); + assert_eq!( + test.token_0.balance(&test.strategy_client_token_0.address), + amount_to_deposit_0 - 12190874 + ); + assert_eq!( + test.token_1.balance(&test.strategy_client_token_1.address), + amount_to_deposit_1 - 23162660 + ); // check user vault shares // should be 358023679−35353535 = 322670144 let df_balance = defindex_contract.balance(&users[0]); @@ -803,10 +939,18 @@ fn from_strategies_two_asset_each_one_strategy_success() { let amount_to_deposit_1_new = 4222221i128; let (amounts, shares_minted) = defindex_contract.deposit( - &sorobanvec![&test.env, amount_to_deposit_0_new, amount_to_deposit_1_new+100], - &sorobanvec![&test.env, amount_to_deposit_0_new, amount_to_deposit_1_new-100], + &sorobanvec![ + &test.env, + amount_to_deposit_0_new, + amount_to_deposit_1_new + 100 + ], + &sorobanvec![ + &test.env, + amount_to_deposit_0_new, + amount_to_deposit_1_new - 100 + ], &users[0], - &false + &false, ); // expected amounts @@ -822,19 +966,30 @@ fn from_strategies_two_asset_each_one_strategy_success() { assert_eq!(shares_minted, 6444443); assert_eq!(defindex_contract.total_supply(), 329115587); //358024679- 35353535 + 6444443 - // check user balances - assert_eq!(test.token0.balance(&users[0]), amount - amount_to_deposit_0 + 12190874 - 2222222); - assert_eq!(test.token1.balance(&users[0]), amount - amount_to_deposit_1 + 23162660 - 4222221); + assert_eq!( + test.token_0.balance(&users[0]), + amount - amount_to_deposit_0 + 12190874 - 2222222 + ); + assert_eq!( + test.token_1.balance(&users[0]), + amount - amount_to_deposit_1 + 23162660 - 4222221 + ); // check vault balance - assert_eq!(test.token0.balance(&defindex_contract.address), 2222222); - assert_eq!(test.token1.balance(&defindex_contract.address), 4222221); + assert_eq!(test.token_0.balance(&defindex_contract.address), 2222222); + assert_eq!(test.token_1.balance(&defindex_contract.address), 4222221); // check strategies balance - assert_eq!(test.token0.balance(&test.strategy_client_token0.address), amount_to_deposit_0 - 12190874); - assert_eq!(test.token1.balance(&test.strategy_client_token1.address), amount_to_deposit_1 - 23162660); + assert_eq!( + test.token_0.balance(&test.strategy_client_token_0.address), + amount_to_deposit_0 - 12190874 + ); + assert_eq!( + test.token_1.balance(&test.strategy_client_token_1.address), + amount_to_deposit_1 - 23162660 + ); // user withdraws only from idle funds 644444 (10% of what just deposited) // this should only affect idle funds @@ -843,7 +998,6 @@ fn from_strategies_two_asset_each_one_strategy_success() { let result = defindex_contract.withdraw(&amount_to_withdraw, &users[0]); assert_eq!(defindex_contract.total_supply(), 328471143); //358024679- 35353535 + 6444443 - 644444 - // the new totqal supply was 322671144+6444443 = 329115587 // the total managed funds for asset 0 was 2222222 (idle) + amount_to_deposit_0 - 12190874 @@ -862,17 +1016,35 @@ fn from_strategies_two_asset_each_one_strategy_success() { assert_eq!(result, expected_result); // check balances - assert_eq!(test.token0.balance(&users[0]), amount - amount_to_deposit_0 + 12190874 - 2222222 + 222222); - assert_eq!(test.token1.balance(&users[0]), amount - amount_to_deposit_1 + 23162660 - 4222221 + 422221); + assert_eq!( + test.token_0.balance(&users[0]), + amount - amount_to_deposit_0 + 12190874 - 2222222 + 222222 + ); + assert_eq!( + test.token_1.balance(&users[0]), + amount - amount_to_deposit_1 + 23162660 - 4222221 + 422221 + ); // check vault balance - assert_eq!(test.token0.balance(&defindex_contract.address), 2222222 - 222222); - assert_eq!(test.token1.balance(&defindex_contract.address), 4222221 - 422221); + assert_eq!( + test.token_0.balance(&defindex_contract.address), + 2222222 - 222222 + ); + assert_eq!( + test.token_1.balance(&defindex_contract.address), + 4222221 - 422221 + ); // check strategies balance - assert_eq!(test.token0.balance(&test.strategy_client_token0.address), amount_to_deposit_0 - 12190874); - assert_eq!(test.token1.balance(&test.strategy_client_token1.address), amount_to_deposit_1 - 23162660); + assert_eq!( + test.token_0.balance(&test.strategy_client_token_0.address), + amount_to_deposit_0 - 12190874 + ); + assert_eq!( + test.token_1.balance(&test.strategy_client_token_1.address), + amount_to_deposit_1 - 23162660 + ); assert_eq!(defindex_contract.total_supply(), 328471143); //358024679- 35353535 + 6444443 - 644444 @@ -882,8 +1054,7 @@ fn from_strategies_two_asset_each_one_strategy_success() { // // Now we will wihdraw the total remineder amount of vault shares of the user // // 328471143 - 1000 = 328470143 let result = defindex_contract.withdraw(&328470143, &users[0]); - - + // from the total supply 328471143, the user will take 328470143 (almost all) // for asset 0 this means // 2222222 - 222222 (idle) + amount_to_deposit_0 - 12190874 @@ -893,7 +1064,6 @@ fn from_strategies_two_asset_each_one_strategy_success() { // 4222221 - 422221 (idle) + amount_to_deposit_1 - 23162660 // 3800000 + 234567890 - 23162660 = 215205230 - // amounts to withdraw // for asset 0: total_funds_0 * withdraw_shares / total_shares // 113265915 * 328470143 / 328471143 = 113265570.17240277 = 113265570 @@ -909,9 +1079,8 @@ fn from_strategies_two_asset_each_one_strategy_success() { // CHECK IDLE BALANCES // check vault balance - assert_eq!(test.token0.balance(&defindex_contract.address), 0); - assert_eq!(test.token1.balance(&defindex_contract.address), 0); - + assert_eq!(test.token_0.balance(&defindex_contract.address), 0); + assert_eq!(test.token_1.balance(&defindex_contract.address), 0); // check strategies balance, they will hold the rest // for asset 0: total_funds_0 * 1000 / total_shares @@ -919,11 +1088,16 @@ fn from_strategies_two_asset_each_one_strategy_success() { // for asset 1: total_funds_1 * withdraw_shares / total_shares // 215205230- 215204574 = 656 - assert_eq!(test.token0.balance(&test.strategy_client_token0.address), 345); - assert_eq!(test.token1.balance(&test.strategy_client_token1.address), 656); + assert_eq!( + test.token_0.balance(&test.strategy_client_token_0.address), + 345 + ); + assert_eq!( + test.token_1.balance(&test.strategy_client_token_1.address), + 656 + ); } - // test withdraw without mock all auths #[test] fn from_strategy_success_no_mock_all_auths() { diff --git a/apps/contracts/vault/src/token/balance.rs b/apps/contracts/vault/src/token/balance.rs index 4398b08f..b0eebc43 100644 --- a/apps/contracts/vault/src/token/balance.rs +++ b/apps/contracts/vault/src/token/balance.rs @@ -1,6 +1,6 @@ use crate::token::storage_types::{DataKey, BALANCE_BUMP_AMOUNT, BALANCE_LIFETIME_THRESHOLD}; use crate::ContractError; -use soroban_sdk::{Address, Env, panic_with_error}; +use soroban_sdk::{panic_with_error, Address, Env}; pub fn read_balance(e: &Env, addr: Address) -> i128 { let key = DataKey::Balance(addr); diff --git a/apps/contracts/vault/src/utils.rs b/apps/contracts/vault/src/utils.rs index bcac091c..f12ae454 100644 --- a/apps/contracts/vault/src/utils.rs +++ b/apps/contracts/vault/src/utils.rs @@ -1,8 +1,8 @@ use soroban_sdk::{panic_with_error, Address, Env, Map, Vec}; use crate::{ - models::{CurrentAssetInvestmentAllocation}, access::{AccessControl, AccessControlTrait, RolesDataKey}, + models::CurrentAssetInvestmentAllocation, token::VaultToken, ContractError, }; @@ -96,7 +96,8 @@ pub fn calculate_asset_amounts_per_vault_shares( for (asset_address, current_asset_allocation) in total_managed_funds.iter() { // Calculate the proportional asset amount per the given number of shares let asset_amount = if total_shares_supply != 0 { - current_asset_allocation.total_amount + current_asset_allocation + .total_amount .checked_mul(shares_amount) .ok_or(ContractError::ArithmeticError)? .checked_div(total_shares_supply) @@ -158,7 +159,12 @@ pub fn calculate_optimal_amounts_and_shares_with_enforced_asset( // we need the total amount managed by this vault in order for the deposit to be proportional // reserve (total manage funds) of the asset we are enforcing let reserve_target = total_managed_funds - .get(assets.get(*i).unwrap_or_else(|| panic_with_error!(&e, ContractError::WrongAmountsLength)).address) + .get( + assets + .get(*i) + .unwrap_or_else(|| panic_with_error!(&e, ContractError::WrongAmountsLength)) + .address, + ) .unwrap_or_else(|| panic_with_error!(&e, ContractError::WrongAmountsLength)) .total_amount; @@ -167,33 +173,36 @@ pub fn calculate_optimal_amounts_and_shares_with_enforced_asset( panic_with_error!(&e, ContractError::InsufficientManagedFunds); } - let amount_desired_target = amounts_desired.get(*i).unwrap_or_else(|| panic_with_error!(&e, ContractError::WrongAmountsLength)); + let amount_desired_target = amounts_desired + .get(*i) + .unwrap_or_else(|| panic_with_error!(&e, ContractError::WrongAmountsLength)); let mut optimal_amounts = Vec::new(e); - + for (j, asset) in assets.iter().enumerate() { if j == (*i as usize) { optimal_amounts.push_back(amount_desired_target); } else { let reserve = total_managed_funds - .get(asset.address).unwrap_or_else(|| panic_with_error!(&e, ContractError::WrongAmountsLength)) - .total_amount; - let amount = reserve.checked_mul(amount_desired_target) + .get(asset.address) + .unwrap_or_else(|| panic_with_error!(&e, ContractError::WrongAmountsLength)) + .total_amount; + let amount = reserve + .checked_mul(amount_desired_target) .unwrap_or_else(|| panic_with_error!(&e, ContractError::ArithmeticError)) .checked_div(reserve_target) .unwrap_or_else(|| panic_with_error!(&e, ContractError::ArithmeticError)); - optimal_amounts.push_back(amount); + optimal_amounts.push_back(amount); } } //TODO: calculate the shares to mint = total_supply * amount_desired_target / reserve_target - let shares_to_mint = - VaultToken::total_supply(e.clone()) + let shares_to_mint = VaultToken::total_supply(e.clone()) .checked_mul(amount_desired_target) .unwrap_or_else(|| panic_with_error!(&e, ContractError::ArithmeticError)) .checked_div(reserve_target) .unwrap_or_else(|| panic_with_error!(&e, ContractError::ArithmeticError)); - + (optimal_amounts, shares_to_mint) } /// Calculates the optimal amounts to deposit for a set of assets, along with the shares to mint. @@ -228,31 +237,38 @@ pub fn calculate_deposit_amounts_and_shares_to_mint( amounts_desired: &Vec, amounts_min: &Vec, ) -> Result<(Vec, i128), ContractError> { - for i in 0..assets.len() { // Calculate the optimal amounts and shares to mint for asset `i`. - let (optimal_amounts, shares_to_mint) = calculate_optimal_amounts_and_shares_with_enforced_asset( - &e, - &total_managed_funds, - &assets, - &amounts_desired, - &i, - ); + let (optimal_amounts, shares_to_mint) = + calculate_optimal_amounts_and_shares_with_enforced_asset( + &e, + &total_managed_funds, + &assets, + &amounts_desired, + &i, + ); let mut should_skip = false; for j in i + 1..assets.len() { // Retrieve the desired and minimum amounts, returning an error if unavailable. - let desired_amount = amounts_desired.get(j).ok_or(ContractError::WrongAmountsLength)?; - let min_amount = amounts_min.get(j).ok_or(ContractError::WrongAmountsLength)?; - let optimal_amount = optimal_amounts.get(j).ok_or(ContractError::WrongAmountsLength)?; + let desired_amount = amounts_desired + .get(j) + .ok_or(ContractError::WrongAmountsLength)?; + let min_amount = amounts_min + .get(j) + .ok_or(ContractError::WrongAmountsLength)?; + let optimal_amount = optimal_amounts + .get(j) + .ok_or(ContractError::WrongAmountsLength)?; // Check if optimal amount meets the desired or minimum requirements. if optimal_amount <= desired_amount { if optimal_amount < min_amount { return Err(ContractError::InsufficientAmount); // Insufficient amount error. } - } else { // if not, we should try the next asset as enforced asset + } else { + // if not, we should try the next asset as enforced asset should_skip = true; // If we have already analized all assets as enforced (i), return an error. if i == assets.len() - 1 {