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

feat: set reserve ratio setter #74

Merged
merged 1 commit into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/interfaces.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ trait IMarket<TContractState> {

fn set_borrow_factor(ref self: TContractState, token: ContractAddress, borrow_factor: felt252);

fn set_reserve_factor(
ref self: TContractState, token: ContractAddress, reserve_factor: felt252
);

fn set_debt_limit(ref self: TContractState, token: ContractAddress, limit: felt252);

fn transfer_ownership(ref self: TContractState, new_owner: ContractAddress);
Expand Down
13 changes: 13 additions & 0 deletions src/market.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ mod Market {
InterestRateModelUpdate: InterestRateModelUpdate,
CollateralFactorUpdate: CollateralFactorUpdate,
BorrowFactorUpdate: BorrowFactorUpdate,
ReserveFactorUpdate: ReserveFactorUpdate,
DebtLimitUpdate: DebtLimitUpdate,
Deposit: Deposit,
Withdrawal: Withdrawal,
Expand Down Expand Up @@ -113,6 +114,12 @@ mod Market {
borrow_factor: felt252
}

#[derive(Drop, PartialEq, starknet::Event)]
struct ReserveFactorUpdate {
token: ContractAddress,
reserve_factor: felt252
}

#[derive(Drop, PartialEq, starknet::Event)]
struct DebtLimitUpdate {
token: ContractAddress,
Expand Down Expand Up @@ -362,6 +369,12 @@ mod Market {
external::set_borrow_factor(ref self, token, borrow_factor)
}

fn set_reserve_factor(
ref self: ContractState, token: ContractAddress, reserve_factor: felt252
) {
external::set_reserve_factor(ref self, token, reserve_factor)
}

fn set_debt_limit(ref self: ContractState, token: ContractAddress, limit: felt252) {
external::set_debt_limit(ref self, token, limit)
}
Expand Down
35 changes: 35 additions & 0 deletions src/market/external.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,41 @@ fn set_borrow_factor(ref self: ContractState, token: ContractAddress, borrow_fac
);
}

fn set_reserve_factor(ref self: ContractState, token: ContractAddress, reserve_factor: felt252) {
ownable::assert_only_owner(@self);

// Checks reserve_factor range
assert(
Into::<_, u256>::into(reserve_factor) <= safe_decimal_math::SCALE_U256,
errors::RESERVE_FACTOR_RANGE
);

internal::assert_reserve_exists(@self, token);

// Settles interest payments up until this point to prevent retrospective changes.
let UpdatedAccumulators{debt_accumulator: updated_debt_accumulator, .. } =
internal::update_accumulators(
ref self, token
);
internal::update_rates_and_raw_total_debt(
ref self,
token, // token
updated_debt_accumulator, // updated_debt_accumulator
false, // is_delta_reserve_balance_negative
0, // abs_delta_reserve_balance
false, // is_delta_raw_total_debt_negative
0 // abs_delta_raw_total_debt
);

self.reserves.write_reserve_factor(token, reserve_factor);
self
.emit(
contract::Event::ReserveFactorUpdate(
contract::ReserveFactorUpdate { token, reserve_factor }
)
);
}

fn set_debt_limit(ref self: ContractState, token: ContractAddress, limit: felt252) {
ownable::assert_only_owner(@self);

Expand Down
8 changes: 8 additions & 0 deletions src/market/storage.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ trait ReservesStorageShortcuts<T> {

fn write_borrow_factor(self: @T, token: ContractAddress, borrow_factor: felt252);

fn write_reserve_factor(self: @T, token: ContractAddress, reserve_factor: felt252);

fn write_debt_limit(self: @T, token: ContractAddress, debt_limit: felt252);

fn write_accumulators(
Expand Down Expand Up @@ -304,6 +306,12 @@ impl ReservesStorageShortcutsImpl of ReservesStorageShortcuts<Reserves> {
Store::<felt252>::write_at_offset(D, base, 5, borrow_factor).expect(E);
}

fn write_reserve_factor(self: @Reserves, token: ContractAddress, reserve_factor: felt252) {
let base = self.address(token);

Store::<felt252>::write_at_offset(D, base, 6, reserve_factor).expect(E);
}

fn write_debt_limit(self: @Reserves, token: ContractAddress, debt_limit: felt252) {
let base = self.address(token);

Expand Down
67 changes: 67 additions & 0 deletions tests/market.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -1517,6 +1517,73 @@ fn test_change_borrow_factor() {
);
}

#[test]
#[available_gas(90000000)]
fn test_change_reserve_factor() {
let setup = setup_with_loan();

// (Copied from `test_rates_changed_on_borrow`)
// Borrowing rate:
// Utilization rate = 22.5 / 10,000 = 0.00225
// Borrowing rate = 0.05 + 0.2 * 0.00225 / 0.8 = 0.0505625 => 505625 * 10 ** 20

starknet::testing::set_block_timestamp(100);

// Reserve balance is not updated without an actual settlement. We do a noop IRM change here to
// just for triggering the settlement.
setup
.alice
.market_set_interest_rate_model(
setup.market.contract_address,
setup.token_b.contract_address, // token
setup.irm_b.contract_address // interest_rate_model
);

// Total interest after 100 seconds:
// Interest = 0.0505625 * 22.5 * 100 / (365 * 86400) = 0.000003607484303652
// Reserve interest:
// Interest = 0.000003607484303652 * 20% = 0.000000721496860730
assert_approximatedly_equals(
setup.z_token_b.balanceOf(MOCK_TREASURY_ADDRESS.try_into().unwrap()), 721496860730, 1
);

// Doubles reserve ratio to 40%
setup
.alice
.market_set_reserve_factor(
setup.market.contract_address,
setup.token_b.contract_address, // token
400000000000000000000000000, // reserve_factor
);

// Trigger another settlement after 100 seconds
starknet::testing::set_block_timestamp(200);
setup
.alice
.market_set_interest_rate_model(
setup.market.contract_address,
setup.token_b.contract_address, // token
setup.irm_b.contract_address // interest_rate_model
);

// Borrowing rate:
// Utilization rate = 22.500003607484303652 / 10,000.000003607484303652 = 0.002250000359936746267031683
// Borrowing rate = 0.05 + 0.2 * 0.002250000359936746267031683 / 0.8 = 0.050562500089984186566757920
// New lending rate:
// Lending rate = 0.050562500089984186566757920 * 0.002250000359936746267031683 = 0.000113765643401766185290610
// Total interest after 100 seconds:
// Interest = 0.050562500089984186566757920 * 22.500003607484303652 * 100 / (365 * 86400) = 0.000003607484888470
// Reserve interest:
// Interest = 0.000003607484888470 * 40% = 0.000001442993955388
// Interest on previous reserve balance:
// Interest = 0.000113765643401766185290610 * 0.000000721496860730 * 100 / (365 * 86400) * (1 - 40%) = 0.000000000000000156
// New balance:
// Balance = 0.000000721496860730 + 0.000000000000000156 + 0.000001442993955388 = 0.000002164490816274
assert_approximatedly_equals(
setup.z_token_b.balanceOf(MOCK_TREASURY_ADDRESS.try_into().unwrap()), 2164490816274, 1
);
}

#[test]
#[available_gas(90000000)]
fn test_prelisted_token_may_have_price_source_unset() {
Expand Down
7 changes: 7 additions & 0 deletions tests/mock.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ trait IAccount<TContractState> {
borrow_factor: felt252
);

fn market_set_reserve_factor(
ref self: TContractState,
contract_address: ContractAddress,
token: ContractAddress,
reserve_factor: felt252
);

fn market_set_debt_limit(
ref self: TContractState,
contract_address: ContractAddress,
Expand Down
9 changes: 9 additions & 0 deletions tests/mock/account.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ mod Account {
IMarketDispatcher { contract_address }.set_borrow_factor(token, borrow_factor)
}

fn market_set_reserve_factor(
ref self: ContractState,
contract_address: ContractAddress,
token: ContractAddress,
reserve_factor: felt252
) {
IMarketDispatcher { contract_address }.set_reserve_factor(token, reserve_factor)
}

fn market_set_debt_limit(
ref self: ContractState,
contract_address: ContractAddress,
Expand Down
Loading