Skip to content

Commit

Permalink
blend strategy, rust tests
Browse files Browse the repository at this point in the history
  • Loading branch information
joaquinsoza committed Dec 3, 2024
1 parent 2ccd647 commit 7a65c7f
Show file tree
Hide file tree
Showing 14 changed files with 712 additions and 79 deletions.
20 changes: 20 additions & 0 deletions apps/contracts/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions apps/contracts/strategies/blend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ soroban-fixed-point-math = "1.2.0"

[dev-dependencies]
soroban-sdk = { workspace = true, features = ["testutils"] }
sep-40-oracle = { version = "1.0.0", features = ["testutils"] }
sep-41-token = { version = " 1.0.0", features = ["testutils"] }
42 changes: 41 additions & 1 deletion apps/contracts/strategies/blend/src/blend_pool.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
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::storage::Config;
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"
Expand Down Expand Up @@ -114,4 +114,44 @@ pub fn claim(e: &Env, from: &Address, config: &Config) -> i128 {

// TODO: Check reserve_token_ids and how to get the correct one
pool_client.claim(from, &vec![&e, config.reserve_id], from)
}

pub fn perform_reinvest(e: &Env, config: &Config) -> Result<bool, StrategyError>{
// Check the current BLND balance
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<Address> = vec![&e];
swap_path.push_back(config.blend_token.clone());
swap_path.push_back(config.asset.clone());

let deadline = e.ledger().timestamp() + 600;

// Swapping BLND tokens to Underlying Asset
let swapped_amounts = internal_swap_exact_tokens_for_tokens(
e,
&blnd_balance,
&0i128,
swap_path,
&e.current_contract_address(),
&deadline,
config,
)?;
let amount_out: i128 = swapped_amounts
.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);

let reserves = storage::get_strategy_reserves(&e);
reserves::harvest(&e, reserves, amount_out, b_tokens_minted);

Ok(true)
}
2 changes: 2 additions & 0 deletions apps/contracts/strategies/blend/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ pub const SCALAR_7: i128 = 1_0000000;
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;
59 changes: 38 additions & 21 deletions apps/contracts/strategies/blend/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
#![no_std]
use constants::MIN_DUST;
use blend_pool::perform_reinvest;
use constants::{MIN_DUST, SCALAR_9};
use soroban_sdk::{
contract, contractimpl, panic_with_error, token::TokenClient, Address, Env, IntoVal, String, Val, Vec};
contract, contractimpl, token::TokenClient, vec, Address, Env, IntoVal, String, Val, Vec};

mod blend_pool;
mod constants;
mod reserves;
mod soroswap;
mod storage;

use soroswap::internal_swap_exact_tokens_for_tokens;
use storage::{extend_instance_ttl, is_initialized, set_initialized, Config};

pub use defindex_strategy_core::{
Expand Down Expand Up @@ -49,13 +52,17 @@ impl DeFindexStrategyTrait for BlendStrategy {

let blend_pool_address: Address = init_args.get(0).ok_or(StrategyError::InvalidArgument)?.into_val(&e);
let reserve_id: u32 = init_args.get(1).ok_or(StrategyError::InvalidArgument)?.into_val(&e);
let blend_token: Address = init_args.get(2).ok_or(StrategyError::InvalidArgument)?.into_val(&e);
let soroswap_router: Address = init_args.get(3).ok_or(StrategyError::InvalidArgument)?.into_val(&e);

set_initialized(&e);

let config = Config {
asset: asset.clone(),
pool: blend_pool_address.clone(),
reserve_id: reserve_id.clone(),
pool: blend_pool_address,
reserve_id,
blend_token,
router: soroswap_router,
};

storage::set_config(&e, config);
Expand Down Expand Up @@ -88,15 +95,11 @@ impl DeFindexStrategyTrait for BlendStrategy {
return Err(StrategyError::InvalidArgument); //TODO: create a new error type for this
}

// Harvest if rewards exceed threshold
// let rewards = blend_pool::claim_rewards(&e);
// if rewards > REWARD_THRESHOLD {
// blend_pool::reinvest_rewards(&e, rewards);
// }
let config = storage::get_config(&e);
perform_reinvest(&e, &config)?;

let reserves = storage::get_strategy_reserves(&e);

let config = storage::get_config(&e);
// transfer tokens from the vault to the strategy contract
TokenClient::new(&e, &config.asset).transfer(&from, &e.current_contract_address(), &amount);

Expand All @@ -112,17 +115,13 @@ impl DeFindexStrategyTrait for BlendStrategy {
fn harvest(e: Env, from: Address) -> Result<(), StrategyError> {
check_initialized(&e)?;
extend_instance_ttl(&e);
from.require_auth();

let config = storage::get_config(&e);
let _harvested_blend = blend_pool::claim(&e, &from, &config);
let harvested_blend = blend_pool::claim(&e, &e.current_contract_address(), &config);

// should swap to usdc
// should supply to the pool
perform_reinvest(&e, &config)?;

// etcetc

event::emit_harvest(&e, String::from_str(&e, STARETEGY_NAME), 0i128, from);
event::emit_harvest(&e, String::from_str(&e, STARETEGY_NAME), harvested_blend, from);
Ok(())
}

Expand Down Expand Up @@ -161,11 +160,29 @@ impl DeFindexStrategyTrait for BlendStrategy {
) -> Result<i128, StrategyError> {
check_initialized(&e)?;
extend_instance_ttl(&e);


// Get the vault's shares
let vault_shares = storage::get_vault_shares(&e, &from);

Ok(vault_shares)

// Get the strategy's total shares and bTokens
let reserves = storage::get_strategy_reserves(&e);
let total_shares = reserves.total_shares;
let total_b_tokens = reserves.total_b_tokens;

if total_shares == 0 || total_b_tokens == 0 {
// No shares or bTokens in the strategy
return Ok(0);
}

// Calculate the bTokens corresponding to the vault's shares
let vault_b_tokens = (vault_shares * total_b_tokens) / total_shares;

// Use the b_rate to convert bTokens to underlying assets
let underlying_balance = (vault_b_tokens * reserves.b_rate) / SCALAR_9;

Ok(underlying_balance)
}
}

// mod test;
#[cfg(any(test, feature = "testutils"))]
mod test;
21 changes: 21 additions & 0 deletions apps/contracts/strategies/blend/src/reserves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,25 @@ pub fn withdraw(
storage::set_vault_shares(&e, &from, vault_shares);

share_amount
}

pub fn harvest(
e: &Env,
mut reserves: StrategyReserves,
underlying_amount: i128,
b_tokens_amount: i128,
) {
if underlying_amount <= 0 {
panic_with_error!(e, StrategyError::InvalidArgument); //TODO: create a new error type for this
}

if b_tokens_amount <= 0 {
panic_with_error!(e, StrategyError::InvalidArgument); //TODO: create a new error type for this
}

reserves.update_rate(underlying_amount, b_tokens_amount);

reserves.total_b_tokens += b_tokens_amount;

storage::set_strategy_reserves(&e, reserves);
}
27 changes: 27 additions & 0 deletions apps/contracts/strategies/blend/src/soroswap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use defindex_strategy_core::StrategyError;
use soroban_sdk::{vec, Address, Env, IntoVal, Symbol, Val, Vec};

use crate::storage::Config;

pub fn internal_swap_exact_tokens_for_tokens(
e: &Env,
amount_in: &i128,
amount_out_min: &i128,
path: Vec<Address>,
to: &Address,
deadline: &u64,
config: &Config,
) -> Result<Vec<i128>, StrategyError> {
let mut swap_args: Vec<Val> = vec![&e];
swap_args.push_back(amount_in.into_val(e));
swap_args.push_back(amount_out_min.into_val(e));
swap_args.push_back(path.into_val(e));
swap_args.push_back(to.to_val());
swap_args.push_back(deadline.into_val(e));

e.invoke_contract(
&config.router,
&Symbol::new(&e, "swap_exact_tokens_for_tokens"),
swap_args,
)
}
4 changes: 3 additions & 1 deletion apps/contracts/strategies/blend/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ pub struct Config {
pub asset: Address,
pub pool: Address,
pub reserve_id: u32,
pub blend_token: Address,
pub router: Address,
}

#[derive(Clone)]
Expand All @@ -19,7 +21,7 @@ pub enum DataKey {
VaultPos(Address) // Vaults Positions
}

const DAY_IN_LEDGERS: u32 = 17280;
pub const DAY_IN_LEDGERS: u32 = 17280;
pub const INSTANCE_BUMP_AMOUNT: u32 = 30 * DAY_IN_LEDGERS;
pub const INSTANCE_LIFETIME_THRESHOLD: u32 = INSTANCE_BUMP_AMOUNT - DAY_IN_LEDGERS;
const LEDGER_BUMP: u32 = 120 * DAY_IN_LEDGERS;
Expand Down
Loading

0 comments on commit 7a65c7f

Please sign in to comment.