diff --git a/contracts/src/BorrowerOperations.sol b/contracts/src/BorrowerOperations.sol index 322b6f2a..d1478df0 100644 --- a/contracts/src/BorrowerOperations.sol +++ b/contracts/src/BorrowerOperations.sol @@ -520,7 +520,7 @@ contract BorrowerOperations is LiquityBase, AddRemoveManagers, IBorrowerOperatio _requireIsNotInBatch(_troveId); address owner = troveNFT.ownerOf(_troveId); _requireSenderIsOwnerOrInterestManager(_troveId, owner); - _requireInterestRateInDelegateRange(_troveId, _newAnnualInterestRate); + _requireInterestRateInDelegateRange(_troveId, _newAnnualInterestRate, owner); _requireTroveIsActive(troveManagerCached, _troveId); LatestTroveData memory trove = troveManagerCached.getLatestTroveData(_troveId); @@ -1287,6 +1287,17 @@ contract BorrowerOperations is LiquityBase, AddRemoveManagers, IBorrowerOperatio } } + function _requireInterestRateInDelegateRange(uint256 _troveId, uint256 _annualInterestRate, address _owner) internal view { + InterestIndividualDelegate memory individualDelegate = interestIndividualDelegateOf[_troveId]; + // We have previously checked that sender is either owner or delegate + // If it’s owner, this restriction doesn’t apply + if (individualDelegate.account == msg.sender) { + _requireInterestRateInRange( + _annualInterestRate, individualDelegate.minInterestRate, individualDelegate.maxInterestRate + ); + } + } + function _requireIsNotInBatch(uint256 _troveId) internal view { if (interestBatchManagerOf[_troveId] != address(0)) { revert TroveInBatch(); @@ -1442,15 +1453,6 @@ contract BorrowerOperations is LiquityBase, AddRemoveManagers, IBorrowerOperatio if (_minInterestRate >= _maxInterestRate) revert MinGeMax(); } - function _requireInterestRateInDelegateRange(uint256 _troveId, uint256 _annualInterestRate) internal view { - InterestIndividualDelegate memory individualDelegate = interestIndividualDelegateOf[_troveId]; - if (individualDelegate.account != address(0)) { - _requireInterestRateInRange( - _annualInterestRate, individualDelegate.minInterestRate, individualDelegate.maxInterestRate - ); - } - } - function _requireInterestRateInBatchManagerRange(address _interestBatchManagerAddress, uint256 _annualInterestRate) internal view diff --git a/contracts/src/test/interestIndividualDelegation.t.sol b/contracts/src/test/interestIndividualDelegation.t.sol index dad517b0..f8a8c5b1 100644 --- a/contracts/src/test/interestIndividualDelegation.t.sol +++ b/contracts/src/test/interestIndividualDelegation.t.sol @@ -102,6 +102,22 @@ contract InterestIndividualDelegationTest is DevTestSetup { vm.stopPrank(); } + function testOwnerCanSetInterestBelowMin() public { + uint256 troveId = openTroveAndSetIndividualDelegate(); + + vm.startPrank(A); + borrowerOperations.adjustTroveInterestRate(troveId, MIN_ANNUAL_INTEREST_RATE, 0, 0, 1e24); + vm.stopPrank(); + } + + function testOwnerCanSetInterestAboveMax() public { + uint256 troveId = openTroveAndSetIndividualDelegate(); + + vm.startPrank(A); + borrowerOperations.adjustTroveInterestRate(troveId, 50e16, 0, 0, 1e24); + vm.stopPrank(); + } + function testSetDelegateRevertsIfTroveIsClosed() public { vm.startPrank(B); borrowerOperations.registerBatchManager(1e16, 20e16, 5e16, 25e14, MIN_INTEREST_RATE_CHANGE_PERIOD);