diff --git a/apps/contracts/strategies/blend/src/blend_pool.rs b/apps/contracts/strategies/blend/src/blend_pool.rs index f99f4a6..e3cf662 100644 --- a/apps/contracts/strategies/blend/src/blend_pool.rs +++ b/apps/contracts/strategies/blend/src/blend_pool.rs @@ -112,8 +112,8 @@ pub fn withdraw(e: &Env, from: &Address, amount: &i128, config: &Config) -> (i12 pub fn claim(e: &Env, from: &Address, config: &Config) -> i128 { let pool_client = BlendPoolClient::new(e, &config.pool); - // TODO: Check reserve_token_ids and how to get the correct one - pool_client.claim(from, &vec![&e, config.reserve_id], from) + // TODO: Hardcoded reserve_token_ids for now + pool_client.claim(from, &vec![&e, 0u32, 1u32, 2u32, 3u32], from) } pub fn perform_reinvest(e: &Env, config: &Config) -> Result<bool, StrategyError>{ diff --git a/apps/contracts/strategies/blend/src/constants.rs b/apps/contracts/strategies/blend/src/constants.rs index 1a61405..f4ef1ef 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 = 500_0000000; \ No newline at end of file +pub const REWARD_THRESHOLD: i128 = 40_0000000; \ 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 7a9318e..3e8e10f 100644 --- a/apps/contracts/strategies/blend/src/soroswap.rs +++ b/apps/contracts/strategies/blend/src/soroswap.rs @@ -1,5 +1,5 @@ use defindex_strategy_core::StrategyError; -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 crate::storage::Config; @@ -19,6 +19,28 @@ pub fn internal_swap_exact_tokens_for_tokens( swap_args.push_back(to.to_val()); swap_args.push_back(deadline.into_val(e)); + // Maybe instead of using the router directly, we should use the pair for swaps + 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)] + ); + + e.authorize_as_current_contract(vec![ + &e, + InvokerContractAuthEntry::Contract(SubContractInvocation { + context: ContractContext { + contract: path.get(0).unwrap().clone(), + fn_name: Symbol::new(&e, "transfer"), + args: ( + e.current_contract_address(), + pair_address, + amount_in.clone()).into_val(e), + }, + sub_invocations: vec![&e], + }), + ]); + e.invoke_contract( &config.router, &Symbol::new(&e, "swap_exact_tokens_for_tokens"), diff --git a/apps/contracts/strategies/blend/src/test/blend/mod.rs b/apps/contracts/strategies/blend/src/test/blend/mod.rs index 916f912..901248a 100644 --- a/apps/contracts/strategies/blend/src/test/blend/mod.rs +++ b/apps/contracts/strategies/blend/src/test/blend/mod.rs @@ -1 +1,2 @@ -mod success; \ No newline at end of file +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 new file mode 100644 index 0000000..0f1535d --- /dev/null +++ b/apps/contracts/strategies/blend/src/test/blend/soroswap_setup.rs @@ -0,0 +1,60 @@ +use soroban_sdk::{ + Env, BytesN, Address, + testutils::{Address as _} +}; + +fn pair_contract_wasm(e: &Env) -> BytesN<32> { + 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"); + pub type SoroswapFactoryClient<'a> = Client<'a>; +} +use factory::SoroswapFactoryClient; + +pub fn create_soroswap_factory<'a>(e: &Env, setter: &Address) -> SoroswapFactoryClient<'a> { + let pair_hash = pair_contract_wasm(&e); + let factory_address = &e.register(factory::WASM, ()); + let factory = SoroswapFactoryClient::new(e, factory_address); + factory.initialize(&setter, &pair_hash); + factory +} + +// SoroswapRouter Contract +mod router { + soroban_sdk::contractimport!(file = "../external_wasms/soroswap/soroswap_router.optimized.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, 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) + ); + + 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 9831bd7..98c1057 100644 --- a/apps/contracts/strategies/blend/src/test/blend/success.rs +++ b/apps/contracts/strategies/blend/src/test/blend/success.rs @@ -2,6 +2,7 @@ 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::{create_blend_pool, create_blend_strategy, BlendFixture, EnvTestUtils}; use crate::BlendStrategyClient; use defindex_strategy_core::StrategyError; @@ -25,10 +26,19 @@ fn success() { let blnd = e.register_stellar_asset_contract_v2(admin.clone()); let usdc = e.register_stellar_asset_contract_v2(admin.clone()); let xlm = e.register_stellar_asset_contract_v2(admin.clone()); - let _blnd_client = MockTokenClient::new(&e, &blnd.address()); + let blnd_client = MockTokenClient::new(&e, &blnd.address()); let usdc_client = MockTokenClient::new(&e, &usdc.address()); let xlm_client = MockTokenClient::new(&e, &xlm.address()); + // Setting up soroswap pool + let pool_admin = Address::generate(&e); + let amount_a = 100000000_0_000_000; + let amount_b = 50000000_0_000_000; + blnd_client.mint(&pool_admin, &amount_a); + usdc_client.mint(&pool_admin, &amount_b); + 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()); // usdc (0) and xlm (1) charge a fixed 10% borrow rate with 0% backstop take rate @@ -36,7 +46,7 @@ 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(), &Address::generate(&e)); + let strategy = create_blend_strategy(&e, &usdc.address(), &pool, &0u32, &blnd.address(), &soroswap_router.address); let strategy_client = BlendStrategyClient::new(&e, &strategy); /* @@ -51,7 +61,7 @@ fn success() { usdc_client.mint(&user_2, &starting_balance); usdc_client.mint(&user_3, &starting_balance); - let user_3_balance = usdc_client.balance(&user_2); + let user_3_balance = usdc_client.balance(&user_3); assert_eq!(user_3_balance, starting_balance); @@ -198,16 +208,12 @@ fn success() { ) ); - strategy_client.withdraw(&withdraw_amount, &user_3); - // -> verify withdraw assert_eq!(usdc_client.balance(&user_2), withdraw_amount); - assert_eq!(usdc_client.balance(&user_3), withdraw_amount); assert_eq!(strategy_client.balance(&user_2), 0); - assert_eq!(strategy_client.balance(&user_3), 0); // -> verify withdraw from empty vault fails - let result = strategy_client.try_withdraw(&MIN_DUST, &user_3); + let result = strategy_client.try_withdraw(&MIN_DUST, &user_2); assert_eq!(result, Err(Ok(StrategyError::InsufficientBalance))); // TODO: Finish harvest testings, pending soroswap router setup with a blend token pair with the underlying asset @@ -219,8 +225,17 @@ fn success() { */ // harvest - // strategy_client.harvest(&usdc, &user_2, &expected_fees); + let blnd_strategy_balance = blnd_client.balance(&strategy); + assert_eq!(blnd_strategy_balance, 0); - // -> verify harvest - + strategy_client.harvest(&user_3); + + let blnd_strategy_balance = blnd_client.balance(&strategy); + assert_eq!(blnd_strategy_balance, 0); + + let usdc_strategy_balance = usdc_client.balance(&strategy); + assert_eq!(usdc_strategy_balance, 0); + + let user_3_strategy_balance = strategy_client.balance(&user_3); + assert_eq!(user_3_strategy_balance, 1226627059); }