diff --git a/src/interfaces.cairo b/src/interfaces.cairo index 24c192b..0dd54a8 100644 --- a/src/interfaces.cairo +++ b/src/interfaces.cairo @@ -110,6 +110,12 @@ trait IMarket { fn set_treasury(ref self: TContractState, new_treasury: ContractAddress); + fn set_collateral_factor( + ref self: TContractState, token: ContractAddress, collateral_factor: felt252 + ); + + fn set_borrow_factor(ref self: TContractState, token: ContractAddress, borrow_factor: felt252); + fn set_debt_limit(ref self: TContractState, token: ContractAddress, limit: felt252); fn transfer_ownership(ref self: TContractState, new_owner: ContractAddress); diff --git a/src/market.cairo b/src/market.cairo index d29829b..8c6367c 100644 --- a/src/market.cairo +++ b/src/market.cairo @@ -47,6 +47,8 @@ mod Market { TreasuryUpdate: TreasuryUpdate, AccumulatorsSync: AccumulatorsSync, InterestRatesSync: InterestRatesSync, + CollateralFactorUpdate: CollateralFactorUpdate, + BorrowFactorUpdate: BorrowFactorUpdate, DebtLimitUpdate: DebtLimitUpdate, Deposit: Deposit, Withdrawal: Withdrawal, @@ -92,6 +94,18 @@ mod Market { borrowing_rate: felt252 } + #[derive(Drop, PartialEq, starknet::Event)] + struct CollateralFactorUpdate { + token: ContractAddress, + collateral_factor: felt252 + } + + #[derive(Drop, PartialEq, starknet::Event)] + struct BorrowFactorUpdate { + token: ContractAddress, + borrow_factor: felt252 + } + #[derive(Drop, PartialEq, starknet::Event)] struct DebtLimitUpdate { token: ContractAddress, @@ -323,6 +337,18 @@ mod Market { external::set_treasury(ref self, new_treasury) } + fn set_collateral_factor( + ref self: ContractState, token: ContractAddress, collateral_factor: felt252 + ) { + external::set_collateral_factor(ref self, token, collateral_factor) + } + + fn set_borrow_factor( + ref self: ContractState, token: ContractAddress, borrow_factor: felt252 + ) { + external::set_borrow_factor(ref self, token, borrow_factor) + } + fn set_debt_limit(ref self: ContractState, token: ContractAddress, limit: felt252) { external::set_debt_limit(ref self, token, limit) } diff --git a/src/market/external.cairo b/src/market/external.cairo index f0834e0..068de23 100644 --- a/src/market/external.cairo +++ b/src/market/external.cairo @@ -253,6 +253,34 @@ fn set_treasury(ref self: ContractState, new_treasury: ContractAddress) { self.emit(contract::Event::TreasuryUpdate(contract::TreasuryUpdate { new_treasury })); } +fn set_collateral_factor( + ref self: ContractState, token: ContractAddress, collateral_factor: felt252 +) { + ownable::assert_only_owner(@self); + + internal::assert_reserve_exists(@self, token); + self.reserves.write_collateral_factor(token, collateral_factor); + self + .emit( + contract::Event::CollateralFactorUpdate( + contract::CollateralFactorUpdate { token, collateral_factor } + ) + ); +} + +fn set_borrow_factor(ref self: ContractState, token: ContractAddress, borrow_factor: felt252) { + ownable::assert_only_owner(@self); + + internal::assert_reserve_exists(@self, token); + self.reserves.write_borrow_factor(token, borrow_factor); + self + .emit( + contract::Event::BorrowFactorUpdate( + contract::BorrowFactorUpdate { token, borrow_factor } + ) + ); +} + fn set_debt_limit(ref self: ContractState, token: ContractAddress, limit: felt252) { ownable::assert_only_owner(@self); diff --git a/src/market/storage.cairo b/src/market/storage.cairo index 16d80a6..076ac2b 100644 --- a/src/market/storage.cairo +++ b/src/market/storage.cairo @@ -102,6 +102,10 @@ trait ReservesStorageShortcuts { fn write_raw_total_debt(self: @T, token: ContractAddress, raw_total_debt: felt252); + fn write_collateral_factor(self: @T, token: ContractAddress, collateral_factor: felt252); + + fn write_borrow_factor(self: @T, token: ContractAddress, borrow_factor: felt252); + fn write_debt_limit(self: @T, token: ContractAddress, debt_limit: felt252); fn write_accumulators( @@ -273,6 +277,20 @@ impl ReservesStorageShortcutsImpl of ReservesStorageShortcuts { Store::::write_at_offset(D, base, 12, raw_total_debt).expect(E); } + fn write_collateral_factor( + self: @Reserves, token: ContractAddress, collateral_factor: felt252 + ) { + let base = self.address(token); + + Store::::write_at_offset(D, base, 4, collateral_factor).expect(E); + } + + fn write_borrow_factor(self: @Reserves, token: ContractAddress, borrow_factor: felt252) { + let base = self.address(token); + + Store::::write_at_offset(D, base, 5, borrow_factor).expect(E); + } + fn write_debt_limit(self: @Reserves, token: ContractAddress, debt_limit: felt252) { let base = self.address(token); diff --git a/tests/market.cairo b/tests/market.cairo index ff1ce33..113f5d8 100644 --- a/tests/market.cairo +++ b/tests/market.cairo @@ -1376,3 +1376,65 @@ fn test_flashloan_fee_distribution() { assert_eq(@reserve_data.current_lending_rate, @112626825801392020390157, 'FAILED'); assert_eq(@reserve_data.current_borrowing_rate, @50556930693069306930693069, 'FAILED'); } + +#[test] +#[available_gas(90000000)] +#[should_panic(expected: ('MKT_INSUFFICIENT_COLLATERAL', 'ENTRYPOINT_FAILED', 'ENTRYPOINT_FAILED'))] +fn test_change_collateral_factor() { + let setup = setup_with_alice_and_bob_deposit(); + + setup + .alice + .market_set_collateral_factor( + setup.market.contract_address, + setup.token_a.contract_address, // token + 400000000000000000000000000 // collateral_factor + ); + + // With original collateral factor of 0.5: + // TST_A collteral: 100 TST_A * 0.5 = 2,500 USD + // For borrowing TST_B: 2,500 * 0.9 = 2,250 USD + // Maximum borrow: 22.5 TST_B + // With updated collateral factor or 0.4: + // TST_A collteral: 100 TST_A * 0.4 = 2,000 USD + // For borrowing TST_B: 2,000 * 0.9 = 1,800 USD + // Maximum borrow: 18 TST_B + setup + .alice + .market_borrow( + setup.market.contract_address, + setup.token_b.contract_address, // token + 18100000000000000000 // amount + ); +} + +#[test] +#[available_gas(90000000)] +#[should_panic(expected: ('MKT_INSUFFICIENT_COLLATERAL', 'ENTRYPOINT_FAILED', 'ENTRYPOINT_FAILED'))] +fn test_change_borrow_factor() { + let setup = setup_with_alice_and_bob_deposit(); + + setup + .alice + .market_set_borrow_factor( + setup.market.contract_address, + setup.token_b.contract_address, // token + 800000000000000000000000000 // borrow_factor + ); + + // With original borrow factor of 0.9: + // TST_A collteral: 100 TST_A * 0.5 = 2,500 USD + // For borrowing TST_B: 2,500 * 0.9 = 2,250 USD + // Maximum borrow: 22.5 TST_B + // With updated borrow factor of 0.8: + // TST_A collteral: 100 TST_A * 0.5 = 2,500 USD + // For borrowing TST_B: 2,500 * 0.8 = 2,000 USD + // Maximum borrow: 20 TST_B + setup + .alice + .market_borrow( + setup.market.contract_address, + setup.token_b.contract_address, // token + 20100000000000000000 // amount + ); +} diff --git a/tests/mock.cairo b/tests/mock.cairo index fa6dfc0..3324e1f 100644 --- a/tests/mock.cairo +++ b/tests/mock.cairo @@ -67,6 +67,20 @@ trait IAccount { ref self: TContractState, contract_address: ContractAddress, new_treasury: ContractAddress ); + fn market_set_collateral_factor( + ref self: TContractState, + contract_address: ContractAddress, + token: ContractAddress, + collateral_factor: felt252 + ); + + fn market_set_borrow_factor( + ref self: TContractState, + contract_address: ContractAddress, + token: ContractAddress, + borrow_factor: felt252 + ); + fn market_set_debt_limit( ref self: TContractState, contract_address: ContractAddress, diff --git a/tests/mock/account.cairo b/tests/mock/account.cairo index a500818..faff27f 100644 --- a/tests/mock/account.cairo +++ b/tests/mock/account.cairo @@ -56,6 +56,24 @@ mod Account { IMarketDispatcher { contract_address }.set_treasury(new_treasury) } + fn market_set_collateral_factor( + ref self: ContractState, + contract_address: ContractAddress, + token: ContractAddress, + collateral_factor: felt252 + ) { + IMarketDispatcher { contract_address }.set_collateral_factor(token, collateral_factor) + } + + fn market_set_borrow_factor( + ref self: ContractState, + contract_address: ContractAddress, + token: ContractAddress, + borrow_factor: felt252 + ) { + IMarketDispatcher { contract_address }.set_borrow_factor(token, borrow_factor) + } + fn market_set_debt_limit( ref self: ContractState, contract_address: ContractAddress,