Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Vault] Performance Fees #306

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
8 changes: 4 additions & 4 deletions apps/contracts/strategies/blend/src/blend_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub fn supply(e: &Env, from: &Address, amount: &i128, config: &Config) -> i128 {
b_tokens_amount
}

pub fn withdraw(e: &Env, from: &Address, amount: &i128, config: &Config) -> (i128, i128) {
pub fn withdraw(e: &Env, to: &Address, amount: &i128, config: &Config) -> (i128, i128) {
let pool_client = BlendPoolClient::new(e, &config.pool);

let pre_supply = pool_client
Expand All @@ -84,7 +84,7 @@ pub fn withdraw(e: &Env, from: &Address, amount: &i128, config: &Config) -> (i12
.unwrap_or_else(|| panic_with_error!(e, StrategyError::InsufficientBalance));

// Get balance pre-withdraw, as the pool can modify the withdrawal amount
let pre_withdrawal_balance = TokenClient::new(&e, &config.asset).balance(&from);
let pre_withdrawal_balance = TokenClient::new(&e, &config.asset).balance(&to);

let requests: Vec<Request> = vec![&e, Request {
address: config.asset.clone(),
Expand All @@ -96,12 +96,12 @@ pub fn withdraw(e: &Env, from: &Address, amount: &i128, config: &Config) -> (i12
let new_positions = pool_client.submit(
&e.current_contract_address(),
&e.current_contract_address(),
&from,
&to,
&requests
);

// Calculate the amount of tokens withdrawn and bTokens burnt
let post_withdrawal_balance = TokenClient::new(&e, &config.asset).balance(&from);
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
Expand Down
44 changes: 26 additions & 18 deletions apps/contracts/strategies/blend/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![no_std]
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};

Expand Down Expand Up @@ -72,7 +73,7 @@ impl DeFindexStrategyTrait for BlendStrategy {
e: Env,
amount: i128,
from: Address,
) -> Result<(), StrategyError> {
) -> Result<i128, StrategyError> {
check_initialized(&e)?;
check_nonnegative_amount(amount)?;
extend_instance_ttl(&e);
Expand All @@ -96,10 +97,12 @@ impl DeFindexStrategyTrait for BlendStrategy {
let b_tokens_minted = blend_pool::supply(&e, &from, &amount, &config);

// Keeping track of the total deposited amount and the total bTokens owned by the strategy depositors
reserves::deposit(&e, reserves, &from, amount, b_tokens_minted);
let vault_shares = reserves::deposit(&e, reserves.clone(), &from, amount, b_tokens_minted);

let underlying_balance = shares_to_underlying(vault_shares, reserves);

event::emit_deposit(&e, String::from_str(&e, STARETEGY_NAME), amount, from);
Ok(())
Ok(underlying_balance)
}

fn harvest(e: Env, from: Address) -> Result<(), StrategyError> {
Expand All @@ -119,6 +122,7 @@ impl DeFindexStrategyTrait for BlendStrategy {
e: Env,
amount: i128,
from: Address,
to: Address,
) -> Result<i128, StrategyError> {
check_initialized(&e)?;
check_nonnegative_amount(amount)?;
Expand All @@ -135,13 +139,14 @@ impl DeFindexStrategyTrait for BlendStrategy {

let config = storage::get_config(&e);

let (tokens_withdrawn, b_tokens_burnt) = blend_pool::withdraw(&e, &from, &amount, &config);
let (tokens_withdrawn, b_tokens_burnt) = blend_pool::withdraw(&e, &to, &amount, &config);

let _burnt_shares = reserves::withdraw(&e, reserves, &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);

Ok(tokens_withdrawn)
Ok(underlying_balance)
}

fn balance(
Expand All @@ -156,22 +161,25 @@ impl DeFindexStrategyTrait for BlendStrategy {

// 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;
let underlying_balance = shares_to_underlying(vault_shares, reserves);

Ok(underlying_balance)
}
}

fn shares_to_underlying(shares: i128, reserves: StrategyReserves) -> i128 {
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 0i128;
}
// 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;
5 changes: 3 additions & 2 deletions apps/contracts/strategies/blend/src/reserves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use soroban_sdk::{contracttype, panic_with_error, Address, Env};
use crate::{constants::SCALAR_9, storage};

#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct StrategyReserves {
/// The total deposited amount of the underlying asset
pub total_shares: i128,
Expand Down Expand Up @@ -83,7 +84,7 @@ pub fn deposit(

storage::set_strategy_reserves(&e, reserves);
storage::set_vault_shares(&e, &from, vault_shares);
share_amount
vault_shares
}

/// Withdraw from the reserve vault. This function expects the withdraw to have already been made
Expand Down Expand Up @@ -122,7 +123,7 @@ pub fn withdraw(
storage::set_strategy_reserves(&e, reserves);
storage::set_vault_shares(&e, &from, vault_shares);

share_amount
vault_shares
}

pub fn harvest(
Expand Down
7 changes: 4 additions & 3 deletions apps/contracts/strategies/blend/src/test/blend/success.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,10 @@ fn success() {
// withdraw_amount = 100_0958904

// -> verify over withdraw fails
let result = strategy_client.try_withdraw(&(withdraw_amount + 100_000_000_0000000), &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);
strategy_client.withdraw(&withdraw_amount, &user_2, &user_2);
// -> verify withdraw auth
assert_eq!(
e.auths()[0],
Expand All @@ -201,6 +201,7 @@ fn success() {
&e,
withdraw_amount.into_val(&e),
user_2.to_val(),
user_2.to_val(),
]
)),
sub_invocations: std::vec![]
Expand All @@ -213,7 +214,7 @@ fn success() {
assert_eq!(strategy_client.balance(&user_2), 0);

// -> verify withdraw from empty vault fails
let result = strategy_client.try_withdraw(&MIN_DUST, &user_2);
let result = strategy_client.try_withdraw(&MIN_DUST, &user_2, &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
Expand Down
3 changes: 2 additions & 1 deletion apps/contracts/strategies/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub trait DeFindexStrategyTrait {
env: Env,
amount: i128,
from: Address
) -> Result<(), StrategyError>;
) -> Result<i128, StrategyError>;

/// Harvests yields generated by the strategy.
///
Expand Down Expand Up @@ -114,5 +114,6 @@ pub trait DeFindexStrategyTrait {
env: Env,
amount: i128, // Specify the amount to withdraw.
from: Address,
to: Address,
) -> Result<i128, StrategyError>;
}
13 changes: 7 additions & 6 deletions apps/contracts/strategies/fixed_apr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl DeFindexStrategyTrait for FixAprStrategy {
e: Env,
amount: i128,
from: Address,
) -> Result<(), StrategyError> {
) -> Result<i128, StrategyError> {
check_initialized(&e)?;
check_nonnegative_amount(amount)?;
extend_instance_ttl(&e);
Expand All @@ -79,9 +79,9 @@ 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);
event::emit_deposit(&e, String::from_str(&e, STRATEGY_NAME), amount, from.clone());

Ok(())
Ok(read_balance(&e, from))
}

fn harvest(e: Env, from: Address) -> Result<(), StrategyError> {
Expand All @@ -107,6 +107,7 @@ impl DeFindexStrategyTrait for FixAprStrategy {
e: Env,
amount: i128,
from: Address,
to: Address,
) -> Result<i128, StrategyError> {
from.require_auth();
check_initialized(&e)?;
Expand All @@ -117,10 +118,10 @@ impl DeFindexStrategyTrait for FixAprStrategy {

let contract_address = e.current_contract_address();
let underlying_asset = get_underlying_asset(&e);
TokenClient::new(&e, &underlying_asset).transfer(&contract_address, &from, &amount);
event::emit_withdraw(&e, String::from_str(&e, STRATEGY_NAME), amount, from);
TokenClient::new(&e, &underlying_asset).transfer(&contract_address, &to, &amount);
event::emit_withdraw(&e, String::from_str(&e, STRATEGY_NAME), amount, from.clone());

Ok(amount)
Ok(read_balance(&e, from))
}

fn balance(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fn withdraw() {
let user_balance = test.token.balance(&users[0]);
assert_eq!(user_balance, 0);

strategy.withdraw(&amount, &users[0]);
strategy.withdraw(&amount, &users[0], &users[0]);
let user_balance_after_withdraw = test.token.balance(&users[0]);
assert_eq!(user_balance_after_withdraw, amount);
}
Expand Down Expand Up @@ -49,7 +49,7 @@ fn withdraw_with_harvest() {
let user_balance_after_harvest = strategy.balance(&users[0]);
assert_eq!(user_balance_after_harvest, amount + expected_reward);

strategy.withdraw(&amount, &users[0]);
strategy.withdraw(&amount, &users[0], &users[0]);
let user_balance_after_withdraw = test.token.balance(&users[0]);
assert_eq!(user_balance_after_withdraw, amount);
}
Expand All @@ -76,7 +76,7 @@ fn withdraw_then_harvest_then_withdraw_again() {
let user_balance_before_harvest = strategy.balance(&users[0]);
assert_eq!(user_balance_before_harvest, amount);

strategy.withdraw(&amount, &users[0]);
strategy.withdraw(&amount, &users[0], &users[0]);
let user_balance_after_withdraw = test.token.balance(&users[0]);
assert_eq!(user_balance_after_withdraw, amount);

Expand All @@ -101,6 +101,6 @@ fn withdraw_with_no_balance() {

let amount = 1_000_0_00_000;

let result = strategy.try_withdraw(&amount, &users[0]);
let result = strategy.try_withdraw(&amount, &users[0], &users[0]);
assert_eq!(result, Err(Ok(StrategyError::InsufficientBalance)));
}
13 changes: 7 additions & 6 deletions apps/contracts/strategies/hodl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl DeFindexStrategyTrait for HodlStrategy {
e: Env,
amount: i128,
from: Address,
) -> Result<(), StrategyError> {
) -> Result<i128, StrategyError> {
check_nonnegative_amount(amount)?;
extend_instance_ttl(&e);
from.require_auth();
Expand All @@ -72,9 +72,9 @@ impl DeFindexStrategyTrait for HodlStrategy {
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);
event::emit_deposit(&e, String::from_str(&e, STARETEGY_NAME), amount, from.clone());

Ok(())
Ok(read_balance(&e, from))
}

fn harvest(e: Env, from: Address) -> Result<(), StrategyError> {
Expand All @@ -88,6 +88,7 @@ impl DeFindexStrategyTrait for HodlStrategy {
e: Env,
amount: i128,
from: Address,
to: Address,
) -> Result<i128, StrategyError> {
from.require_auth();
check_nonnegative_amount(amount)?;
Expand All @@ -97,10 +98,10 @@ impl DeFindexStrategyTrait for HodlStrategy {

let contract_address = e.current_contract_address();
let underlying_asset = get_underlying_asset(&e);
TokenClient::new(&e, &underlying_asset).transfer(&contract_address, &from, &amount);
event::emit_withdraw(&e, String::from_str(&e, STARETEGY_NAME), amount, from);
TokenClient::new(&e, &underlying_asset).transfer(&contract_address, &to, &amount);
event::emit_withdraw(&e, String::from_str(&e, STARETEGY_NAME), amount, from.clone());

Ok(amount)
Ok(read_balance(&e, from))
}

fn balance(
Expand Down
6 changes: 3 additions & 3 deletions apps/contracts/strategies/hodl/src/test/hodl/deposit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ fn deposit_and_withdrawal_flow() {

let amount_to_withdraw = 100_000;
// Withdrawing token from the strategy to user
strategy.withdraw(&amount_to_withdraw, &test.user);
strategy.withdraw(&amount_to_withdraw, &test.user, &test.user);

// Reading user balance in token
let balance = test.token.balance(&test.user);
Expand All @@ -66,7 +66,7 @@ fn deposit_and_withdrawal_flow() {

// now we will want to withdraw more of the remaining balance
let amount_to_withdraw = 200_000;
let result = strategy.try_withdraw(&amount_to_withdraw, &test.user);
let result = strategy.try_withdraw(&amount_to_withdraw, &test.user, &test.user);
assert_eq!(result, Err(Ok(StrategyError::InsufficientBalance)));

}
Expand Down Expand Up @@ -98,6 +98,6 @@ fn deposit_from_a_withdrawal_from_b() {

let amount_to_withdraw = 100_000;
// Withdrawing token from the strategy to user
let result = strategy.try_withdraw(&amount_to_withdraw, &test.user1);
let result = strategy.try_withdraw(&amount_to_withdraw, &test.user1, &test.user1);
assert_eq!(result, Err(Ok(StrategyError::InsufficientBalance)));
}
2 changes: 1 addition & 1 deletion apps/contracts/strategies/hodl/src/test/hodl/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn withdraw() {
strategy.deposit(&amount_to_deposit, &test.user);

let amount_to_withdraw = 123456;
strategy.withdraw(&amount_to_withdraw, &test.user);
strategy.withdraw(&amount_to_withdraw, &test.user, &test.user);
let withdraw_event = test.env.events().all().last().unwrap();
let expected_withdraw_event = WithdrawEvent {
amount: amount_to_withdraw,
Expand Down
6 changes: 3 additions & 3 deletions apps/contracts/strategies/hodl/src/test/hodl/withdraw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn withdraw() {
let amount = 123456;

//Try to withdraw before depositing
let result = strategy.try_withdraw(&amount, &test.user);
let result = strategy.try_withdraw(&amount, &test.user, &test.user);
assert_eq!(result, Err(Ok(StrategyError::InsufficientBalance)));

// Deposit amount of token from the user to the strategy
Expand All @@ -33,7 +33,7 @@ fn withdraw() {

let amount_to_withdraw = 100_000;
// Withdrawing token from the strategy to user
strategy.withdraw(&amount_to_withdraw, &test.user);
strategy.withdraw(&amount_to_withdraw, &test.user, &test.user);

// Reading user balance in token
let balance = test.token.balance(&test.user);
Expand All @@ -49,7 +49,7 @@ fn withdraw() {

//withdraw more than the user has
let amount_to_withdraw = user_balance + 1;
let result = strategy.try_withdraw(&amount_to_withdraw, &test.user);
let result = strategy.try_withdraw(&amount_to_withdraw, &test.user, &test.user);
assert_eq!(result, Err(Ok(StrategyError::InsufficientBalance)));

}
Loading
Loading