Skip to content

Commit

Permalink
feat:vessel_manager
Browse files Browse the repository at this point in the history
  • Loading branch information
0xTitan committed Feb 5, 2024
1 parent a4411bf commit d09f6f5
Show file tree
Hide file tree
Showing 25 changed files with 627 additions and 72 deletions.
3 changes: 2 additions & 1 deletion src/core/admin_contract.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -657,8 +657,9 @@ mod AdminContract {
CommunErrors::OnlyTimelock
);
return;
} else {
self.ownable.assert_only_owner();
}
self.ownable.assert_only_owner();
}

#[inline(always)]
Expand Down
20 changes: 16 additions & 4 deletions src/pools/vessel_manager.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ trait IVesselManager<TContractState> {
fn set_vessel_status(
ref self: TContractState, asset: ContractAddress, borrower: ContractAddress, status: Status
);
fn set_base_rate(ref self: TContractState, asset: ContractAddress, rate: u256);
fn increase_vessel_coll(
ref self: TContractState,
asset: ContractAddress,
Expand Down Expand Up @@ -630,6 +631,8 @@ mod VesselManager {
// TODO IActivePool(activePool).sendAsset(_asset, _receiver, collToSendToRedeemer);
}

// Decay the baseRate due to time passed and then increase it according to the size of this redemption
// Use the saved total GRAI supply value from before it was reduced by redemption
fn update_base_rate_from_redemption(
ref self: ContractState,
asset: ContractAddress,
Expand Down Expand Up @@ -864,6 +867,14 @@ mod VesselManager {
self.vessels.write((borrower, asset), vessel);
}

fn set_base_rate(ref self: ContractState, asset: ContractAddress, rate: u256) {
self.only_vessel_manager_operations_or_borrower_operations();
let mut old_rate = self.base_rate.read(asset);
if (old_rate != rate) {
self.base_rate.write(asset, rate);
}
}

fn increase_vessel_coll(
ref self: ContractState,
asset: ContractAddress,
Expand Down Expand Up @@ -966,7 +977,7 @@ mod VesselManager {
.get_address(AddressesKey::borrower_operations);

assert(
caller != vessel_manager_operations && caller != borrower_operations,
caller == vessel_manager_operations || caller == borrower_operations,
Errors::VesselManager__OnlyVesselManagerOperationsOrBorrowerOperations
)
}
Expand Down Expand Up @@ -1120,7 +1131,7 @@ mod VesselManager {

fn minutes_passed_since_last_fee_op(self: @ContractState, asset: ContractAddress) -> u256 {
let time_stamp: u256 = get_block_timestamp().into();
time_stamp - self.last_fee_operation_time.read(asset) / SECONDS_IN_ONE_MINUTE.into()
(time_stamp - self.last_fee_operation_time.read(asset)) / SECONDS_IN_ONE_MINUTE.into()
}

// TODO implement function
Expand Down Expand Up @@ -1181,20 +1192,21 @@ mod VesselManager {
vessel.debt = vessel.debt + pending_debt_reward;
self.vessels.write((borrower, asset), vessel);

self.update_vessel_reward_snapshots(asset, borrower);
self.update_vessel_reward_snapshots_internal(asset, borrower);

// Transfer from DefaultPool to ActivePool
self
.move_pending_vessel_rewards_to_active_pool(
asset, pending_debt_reward, pending_coll_reward
);

self
.emit(
VesselUpdated {
asset,
borrower,
debt: vessel.debt,
coll: vessel.debt,
coll: vessel.coll,
stake: vessel.stake,
operation: VesselManagerOperation::ApplyPendingRewards
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ fn when_caller_is_not_borrower_operations_it_should_revert() {
pragma_mock,
active_pool,
default_pool,
asset
asset,
vessel_manager_operations_address
) =
deploy_main_contracts();

Expand All @@ -54,7 +55,8 @@ fn when_caller_is_borrower_operations_it_add_vessel_to_owner_array() {
pragma_mock,
active_pool,
default_pool,
asset
asset,
vessel_manager_operations_address
) =
deploy_main_contracts();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
test_apply_pending_rewards.cairo
├── when caller is not borrower or vessel manager operation
│ └── it should revert
├── when caller is vessel manager operation and vessel has no pending rewards
│ ├── it should not update vessel
│ ├── it should not raised VesselSnapshotsUpdated event
│ └── it should not raised VesselUpdated event
└── when caller is vessel manager operation and vessel has pending rewards
├── it should update vessel coll
├── it should update vessel debt
├── it should raise VesselSnapshotsUpdated event
└── it should raise VesselUpdated event
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
use tests::tests_lib::{deploy_main_contracts};
use super::super::setup::open_vessel;
use shisui::core::{
address_provider::{IAddressProviderDispatcher, IAddressProviderDispatcherTrait, AddressesKey},
admin_contract::{IAdminContractDispatcher, IAdminContractDispatcherTrait},
fee_collector::{IFeeCollectorDispatcher, IFeeCollectorDispatcherTrait},
debt_token::{IDebtTokenDispatcher, IDebtTokenDispatcherTrait},
price_feed::{IPriceFeedDispatcher, IPriceFeedDispatcherTrait},
};
use shisui::pools::{
borrower_operations::{IBorrowerOperationsDispatcher, IBorrowerOperationsDispatcherTrait},
vessel_manager::{
IVesselManagerDispatcher, IVesselManagerDispatcherTrait, VesselManager,
VesselManagerOperation, Status
},
};
use snforge_std::{
start_prank, stop_prank, store, map_entry_address, CheatTarget, spy_events, SpyOn, EventSpy,
EventAssertions, start_mock_call, PrintTrait
};
use starknet::{ContractAddress, contract_address_const, get_caller_address};

#[test]
#[should_panic(expected: ('Only vessel mngr op or borrower',))]
fn when_caller_is_not_borrower_operation_it_should_revert() {
let (
borrower_operations,
vessel_manager,
adress_provider,
admin_contract,
fee_collector,
debt_token,
price_feed,
pragma_mock,
active_pool,
default_pool,
asset,
vessel_manager_operations_address
) =
deploy_main_contracts();

let caller = contract_address_const::<'caller'>();
let borrower = contract_address_const::<'borrower'>();
start_prank(CheatTarget::One(vessel_manager.contract_address), caller);
vessel_manager.apply_pending_rewards(asset.contract_address, borrower);
stop_prank(CheatTarget::One(vessel_manager.contract_address));
}

#[test]
fn when_vessel_has_no_pending_reward_should_return() {
let (
borrower_operations,
vessel_manager,
adress_provider,
admin_contract,
fee_collector,
debt_token,
price_feed,
pragma_mock,
active_pool,
default_pool,
asset,
vessel_manager_operations_address
) =
deploy_main_contracts();

let mut asset_price: u256 = 1600_000000000000000000;
let deposit_amount: u256 = 1_890000000000000000;
let debt_token_amount: u256 = 2000_000000000000000000;

let borrower = open_vessel(
asset,
price_feed,
admin_contract,
active_pool,
default_pool,
debt_token,
borrower_operations,
vessel_manager,
pragma_mock,
asset_price,
deposit_amount,
debt_token_amount
);

let coll = vessel_manager.get_vessel_coll(asset.contract_address, borrower);
let debt = vessel_manager.get_vessel_debt(asset.contract_address, borrower);
let stake = vessel_manager.get_vessel_stake(asset.contract_address, borrower);

// update vessel status to siulate vessel has no pending reward
start_prank(
CheatTarget::One(vessel_manager.contract_address), borrower_operations.contract_address
);
vessel_manager.set_vessel_status(asset.contract_address, borrower, Status::NonExistent);
stop_prank(CheatTarget::One(vessel_manager.contract_address));

let rewards: u8 = 10;

store(
vessel_manager.contract_address,
map_entry_address(selector!("l_colls"), array![asset.contract_address.into()].span()),
array![rewards.into()].span()
);

store(
vessel_manager.contract_address,
map_entry_address(selector!("l_debts"), array![asset.contract_address.into()].span()),
array![rewards.into()].span()
);

let mut spy = spy_events(SpyOn::One(vessel_manager.contract_address));
start_prank(
CheatTarget::One(vessel_manager.contract_address), vessel_manager_operations_address
);
vessel_manager.apply_pending_rewards(asset.contract_address, borrower);
stop_prank(CheatTarget::One(vessel_manager.contract_address));

let asset_address = asset.contract_address;

// event check
spy
.assert_not_emitted(
@array![
(
vessel_manager.contract_address,
VesselManager::Event::VesselUpdated(
VesselManager::VesselUpdated {
asset: asset_address,
borrower,
debt,
coll,
stake,
operation: VesselManagerOperation::ApplyPendingRewards
}
)
),
(
vessel_manager.contract_address,
VesselManager::Event::VesselSnapshotsUpdated(
VesselManager::VesselSnapshotsUpdated {
asset: asset_address,
borrower,
l_coll: rewards.into(),
l_debt: rewards.into()
}
)
)
]
);

let new_coll = vessel_manager.get_vessel_coll(asset.contract_address, borrower);
let new_debt = vessel_manager.get_vessel_debt(asset.contract_address, borrower);

assert(new_coll == coll, 'Wrong coll');
assert(new_debt == debt, 'Wrong debt');
}

#[test]
fn when_vessel_has_pending_reward_it_should_update_vessel() {
let (
borrower_operations,
vessel_manager,
adress_provider,
admin_contract,
fee_collector,
debt_token,
price_feed,
pragma_mock,
active_pool,
default_pool,
asset,
vessel_manager_operations_address
) =
deploy_main_contracts();

let mut asset_price: u256 = 1600_000000000000000000;
let deposit_amount: u256 = 1_890000000000000000;
let debt_token_amount: u256 = 2000_000000000000000000;

let borrower = open_vessel(
asset,
price_feed,
admin_contract,
active_pool,
default_pool,
debt_token,
borrower_operations,
vessel_manager,
pragma_mock,
asset_price,
deposit_amount,
debt_token_amount
);

let rewards: u8 = 10;

store(
vessel_manager.contract_address,
map_entry_address(selector!("l_colls"), array![asset.contract_address.into()].span()),
array![rewards.into()].span()
);

store(
vessel_manager.contract_address,
map_entry_address(selector!("l_debts"), array![asset.contract_address.into()].span()),
array![rewards.into()].span()
);

let coll = vessel_manager.get_vessel_coll(asset.contract_address, borrower);
let debt = vessel_manager.get_vessel_debt(asset.contract_address, borrower);
let stake = vessel_manager.get_vessel_stake(asset.contract_address, borrower);

start_prank(
CheatTarget::One(vessel_manager.contract_address), vessel_manager_operations_address
);
let mut spy = spy_events(SpyOn::One(vessel_manager.contract_address));
vessel_manager.apply_pending_rewards(asset.contract_address, borrower);
stop_prank(CheatTarget::One(vessel_manager.contract_address));

let new_debt = debt + 18; // deposit_amount * rewards / precision=18
let new_coll = coll + 18; // deposit_amount * rewards / precision=18

assert(
new_coll == vessel_manager.get_vessel_coll(asset.contract_address, borrower), 'Wrong coll'
);
assert(
new_debt == vessel_manager.get_vessel_debt(asset.contract_address, borrower), 'Wrong debt'
);

let asset_address = asset.contract_address;

// event check
spy
.assert_emitted(
@array![
(
vessel_manager.contract_address,
VesselManager::Event::VesselUpdated(
VesselManager::VesselUpdated {
asset: asset_address,
borrower,
debt: new_debt,
coll: new_coll,
stake,
operation: VesselManagerOperation::ApplyPendingRewards
}
)
),
(
vessel_manager.contract_address,
VesselManager::Event::VesselSnapshotsUpdated(
VesselManager::VesselSnapshotsUpdated {
asset: asset_address,
borrower,
l_coll: rewards.into(),
l_debt: rewards.into()
}
)
)
]
);
}

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
test_frcrease_vessel_coll.cairo
test_decrease_vessel_coll.cairo
├── When caller is not borrower operation
│ └── it should revert
└── when caller is borrower operation
Expand Down
Loading

0 comments on commit d09f6f5

Please sign in to comment.