Skip to content

Commit

Permalink
test:invest: without mocking all auths
Browse files Browse the repository at this point in the history
  • Loading branch information
esteblock committed Nov 11, 2024
1 parent 3baafa2 commit 7a24a8c
Show file tree
Hide file tree
Showing 5 changed files with 296 additions and 23 deletions.
4 changes: 3 additions & 1 deletion apps/contracts/vault/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,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<Option<AssetInvestmentAllocation>>) -> Result<(), ContractError>;
fn invest(e: Env,
asset_investments: Vec<Option<AssetInvestmentAllocation>>
) -> Result<(), ContractError>;

/// Rebalances the vault by executing a series of instructions.
///
Expand Down
3 changes: 0 additions & 3 deletions apps/contracts/vault/src/investment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,6 @@ pub fn check_and_execute_investments(
panic_with_error!(&e, ContractError::StrategyPaused);
}

//Reduce idle funds for this asset


// Execute the investment if checks pass
invest_in_strategy(
&e,
Expand Down
15 changes: 4 additions & 11 deletions apps/contracts/vault/src/strategies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,7 @@ pub fn invest_in_strategy(
amount: &i128,
) -> Result<(), ContractError> {


// // Now we will handle funds on behalf of the contract, not the caller (manager or user)
// let mut transfer_args: Vec<Val> = vec![&e];
// transfer_args.push_back(e.current_contract_address().into_val(&e)); //from
// transfer_args.push_back(strategy_address.into_val(&e)); //to
// transfer_args.push_back(amount.into_val(&e)); //amount

// Now we will handle funds on behalf of the contract, not the caller (manager or user)

e.authorize_as_current_contract(vec![
&e,
Expand All @@ -170,8 +164,7 @@ pub fn invest_in_strategy(

let strategy_client = get_strategy_client(&e, strategy_address.clone());

match strategy_client.try_deposit(amount, &e.current_contract_address()) {
Ok(Ok(_)) => Ok(()),
Ok(Err(_)) | Err(_) => Err(ContractError::StrategyInvestError),
}
strategy_client.deposit(amount, &e.current_contract_address());

Ok(())
}
4 changes: 4 additions & 0 deletions apps/contracts/vault/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,10 @@ pub struct DeFindexVaultTest<'a> {
defindex_contract: DeFindexVaultClient<'a>,
token0_admin_client: SorobanTokenAdminClient<'a>,
token0: SorobanTokenClient<'a>,
token0_admin: Address,
token1_admin_client: SorobanTokenAdminClient<'a>,
token1: SorobanTokenClient<'a>,
token1_admin: Address,
emergency_manager: Address,
vault_fee_receiver: Address,
defindex_protocol_receiver: Address,
Expand Down Expand Up @@ -143,8 +145,10 @@ impl<'a> DeFindexVaultTest<'a> {
defindex_contract,
token0_admin_client,
token0,
token0_admin,
token1_admin_client,
token1,
token1_admin,
emergency_manager,
vault_fee_receiver,
defindex_protocol_receiver,
Expand Down
293 changes: 285 additions & 8 deletions apps/contracts/vault/src/test/invest.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use soroban_sdk::{vec as sorobanvec, String, Vec, Map, vec};
use soroban_sdk::{
testutils::{MockAuth, MockAuthInvoke},
IntoVal,
};

use crate::test::defindex_vault::{
AssetStrategySet,
AssetInvestmentAllocation,
AssetInvestmentAllocation,
StrategyInvestment,
Strategy,
ContractError};
Expand Down Expand Up @@ -549,12 +553,285 @@ fn test_invest_in_strategy() {

}

// // check that try to invest without idle funds return error
// 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
fn test_invest_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 assets: Vec<AssetStrategySet> = 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()
}
];

test.defindex_contract.initialize(
&assets,
&test.manager,
&test.emergency_manager,
&test.vault_fee_receiver,
&2000u32,
&test.defindex_protocol_receiver,
&test.defindex_factory,
&String::from_str(&test.env, "dfToken"),
&String::from_str(&test.env, "DFT"),
);

let users = DeFindexVaultTest::generate_random_users(&test.env, 1);
let amount_0 = 987654321i128;
let amount_1 = 123456789i128;

test.env.mock_all_auths();

// mint
test.token0_admin_client.mint(&users[0], &amount_0);
test.token1_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]);

assert_eq!(user_amount_0, amount_0);
assert_eq!(user_amount_1, amount_1);


test.defindex_contract.deposit(
&sorobanvec![&test.env, amount_0, amount_1], // asset 0
&sorobanvec![&test.env, amount_0, amount_1], // asset 1
&users[0],
);

// check vault balances
let vault_balance_0 = test.token0.balance(&test.defindex_contract.address);
let vault_balance_1 = test.token1.balance(&test.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_investments: vec![
&test.env,
Some(StrategyInvestment {
strategy: test.strategy_client_token0.address.clone(),
amount: vault_balance_0 + 1,
}),
],
}),
Some(AssetInvestmentAllocation {
asset: test.token1.address.clone(),
strategy_investments: vec![
&test.env,
Some(StrategyInvestment {
strategy: test.strategy_client_token1.address.clone(),
amount: vault_balance_1 + 1,
}),
],
})];

test.env.mock_all_auths(); // TODO, Mock only Manager

test.defindex_contract.invest(
&asset_investments,
);
}

// invest without mock aut, mocking only specific auths
#[test]
fn test_invest_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 assets: Vec<AssetStrategySet> = 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()
}
];

test.defindex_contract.initialize(
&assets,
&test.manager,
&test.emergency_manager,
&test.vault_fee_receiver,
&2000u32,
&test.defindex_protocol_receiver,
&test.defindex_factory,
&String::from_str(&test.env, "dfToken"),
&String::from_str(&test.env, "DFT"),
);

let 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);

// check user amount
let user_amount_0 = test.token0.balance(&users[0]);
let user_amount_1 = test.token1.balance(&users[0]);

assert_eq!(user_amount_0, amount_0);
assert_eq!(user_amount_1, amount_1);


// mock deposit auth from user and deposit

test.defindex_contract.mock_auths(&[MockAuth {
address: &users[0].clone(),
invoke: &MockAuthInvoke {
contract: &test.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()
).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(),
test.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(),
test.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],
);

// TODO check that the blockchain saw this authorizations

// check vault balances
let vault_balance_0 = test.token0.balance(&test.defindex_contract.address);
let vault_balance_1 = test.token1.balance(&test.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
test.defindex_contract.mock_auths(&[MockAuth {
address: &test.manager.clone(),
invoke: &MockAuthInvoke {
contract: &test.defindex_contract.address.clone(),
fn_name: "invest",
args: (
Vec::from_array(&test.env,[
Some(
AssetInvestmentAllocation {
asset: test.token0.address.clone(),
strategy_investments:
sorobanvec![&test.env,
Some(StrategyInvestment {
strategy: test.strategy_client_token0.address.clone(),
amount: 100,
})]
}
),
Some(
AssetInvestmentAllocation {
asset: test.token1.address.clone(),
strategy_investments: sorobanvec![&test.env,
Some(StrategyInvestment {
strategy: test.strategy_client_token1.address.clone(),
amount: 200,
})]
}
)]),
).into_val(&test.env),
sub_invokes: &[]
},
}]).invest(
&sorobanvec![
&test.env,
Some(
AssetInvestmentAllocation {
asset: test.token0.address.clone(),
strategy_investments: sorobanvec![&test.env,
Some(StrategyInvestment {
strategy: test.strategy_client_token0.address.clone(),
amount: 100,
})]
}
),
Some(
AssetInvestmentAllocation {
asset: test.token1.address.clone(),
strategy_investments: sorobanvec![&test.env,
Some(StrategyInvestment {
strategy: test.strategy_client_token1.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(&test.defindex_contract.address);
let vault_balance_1 = test.token1.balance(&test.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 = test.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);
assert_eq!(current_invested_funds, expected_map);


// // check if initialized vault, can only be called by manaer (todo)
// #[test]
// fn test_invest_initialized_only_by_manager() {
// todo!();

// }
}

0 comments on commit 7a24a8c

Please sign in to comment.