Skip to content

Commit

Permalink
feat: set reserve ratio setter (#74)
Browse files Browse the repository at this point in the history
Interest is settled upon reserve ratio changes.
  • Loading branch information
xJonathanLEI committed Mar 13, 2024
1 parent 3477460 commit 9562840
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/interfaces.cairo
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
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
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
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
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
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
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

0 comments on commit 9562840

Please sign in to comment.