diff --git a/contracts/src/Interfaces/ITroveManager.sol b/contracts/src/Interfaces/ITroveManager.sol index 8c67e628..f616f4ca 100644 --- a/contracts/src/Interfaces/ITroveManager.sol +++ b/contracts/src/Interfaces/ITroveManager.sol @@ -28,10 +28,10 @@ interface ITroveManager is IERC721, ILiquityBase { function sortedTroves() external view returns(ISortedTroves); function borrowerOperationsAddress() external view returns (address); - function BOOTSTRAP_PERIOD() external view returns (uint256); - // function BOLD_GAS_COMPENSATION() external view returns (uint256); + function baseRate() external view returns (uint256); + function getTroveIdsCount() external view returns (uint); function getTroveFromTroveIdsArray(uint _index) external view returns (uint256); diff --git a/contracts/src/TroveManager.sol b/contracts/src/TroveManager.sol index d8fe8707..c874ec58 100644 --- a/contracts/src/TroveManager.sol +++ b/contracts/src/TroveManager.sol @@ -46,10 +46,9 @@ contract TroveManager is ERC721, LiquityBase, Ownable, CheckContract, ITroveMana */ uint constant public MINUTE_DECAY_FACTOR = 999037758833783000; uint constant public REDEMPTION_FEE_FLOOR = DECIMAL_PRECISION / 1000 * 5; // 0.5% - uint constant public MAX_BORROWING_FEE = DECIMAL_PRECISION / 100 * 5; // 5% + // To prevent redemptions unless Bold depegs below 0.95 and allow the system to take off + uint constant public INITIAL_REDEMPTION_RATE = DECIMAL_PRECISION / 100 * 5; // 5% - // During bootsrap period redemptions are not allowed - uint constant public BOOTSTRAP_PERIOD = 14 days; /* * BETA: 18 digit decimal. Parameter by which to divide the redeemed fraction, in order to calc the new base rate from a redemption. @@ -258,14 +257,19 @@ contract TroveManager is ERC721, LiquityBase, Ownable, CheckContract, ITroveMana event TroveSnapshotsUpdated(uint _L_ETH, uint _L_boldDebt); event TroveIndexUpdated(uint256 _troveId, uint _newIndex); - enum TroveManagerOperation { + enum TroveManagerOperation { getAndApplyRedistributionGains, liquidateInNormalMode, liquidateInRecoveryMode, redeemCollateral } - constructor() ERC721(NAME, SYMBOL) {} + constructor() ERC721(NAME, SYMBOL) { + // Update the baseRate state variable + // To prevent redemptions unless Bold depegs below 0.95 and allow the system to take off + baseRate = INITIAL_REDEMPTION_RATE; + emit BaseRateUpdated(INITIAL_REDEMPTION_RATE); + } // --- Dependency setter --- @@ -919,7 +923,6 @@ contract TroveManager is ERC721, LiquityBase, Ownable, CheckContract, ITroveMana RedemptionTotals memory totals; _requireValidMaxFeePercentage(_maxFeePercentage); - _requireAfterBootstrapPeriod(); totals.price = priceFeed.fetchPrice(); _requireTCRoverMCR(totals.price); _requireAmountGreaterThanZero(_boldamount); @@ -1364,16 +1367,14 @@ contract TroveManager is ERC721, LiquityBase, Ownable, CheckContract, ITroveMana } function getRedemptionRateWithDecay() public view override returns (uint) { - return 0; - // return _calcRedemptionRate(_calcDecayedBaseRate()); + return _calcRedemptionRate(_calcDecayedBaseRate()); } - function _calcRedemptionRate(uint /* _baseRate */) internal pure returns (uint) { - return 0; - // return LiquityMath._min( - // REDEMPTION_FEE_FLOOR + _baseRate, - // DECIMAL_PRECISION // cap at a maximum of 100% - // ); + function _calcRedemptionRate(uint _baseRate) internal pure returns (uint) { + return LiquityMath._min( + REDEMPTION_FEE_FLOOR + _baseRate, + DECIMAL_PRECISION // cap at a maximum of 100% + ); } function _getRedemptionFee(uint _ETHDrawn) internal view returns (uint) { @@ -1384,11 +1385,10 @@ contract TroveManager is ERC721, LiquityBase, Ownable, CheckContract, ITroveMana return _calcRedemptionFee(getRedemptionRateWithDecay(), _ETHDrawn); } - function _calcRedemptionFee(uint /* _redemptionRate */, uint /* _ETHDrawn */) internal pure returns (uint) { - return 0; - // uint redemptionFee = _redemptionRate * _ETHDrawn / DECIMAL_PRECISION; - // require(redemptionFee < _ETHDrawn, "TroveManager: Fee would eat up all returned collateral"); - // return redemptionFee; + function _calcRedemptionFee(uint _redemptionRate, uint _ETHDrawn) internal pure returns (uint) { + uint redemptionFee = _redemptionRate * _ETHDrawn / DECIMAL_PRECISION; + require(redemptionFee < _ETHDrawn, "TroveManager: Fee would eat up all returned collateral"); + return redemptionFee; } // --- Internal fee functions --- @@ -1471,11 +1471,6 @@ contract TroveManager is ERC721, LiquityBase, Ownable, CheckContract, ITroveMana require(_getTCR(_price) >= MCR, "TroveManager: Cannot redeem when TCR < MCR"); } - function _requireAfterBootstrapPeriod() internal view { - uint systemDeploymentTime = boldToken.deploymentStartTime(); - require(block.timestamp >= systemDeploymentTime + BOOTSTRAP_PERIOD, "TroveManager: Redemptions are not allowed during bootstrap phase"); - } - function _requireValidMaxFeePercentage(uint _maxFeePercentage) internal pure { require(_maxFeePercentage >= REDEMPTION_FEE_FLOOR && _maxFeePercentage <= DECIMAL_PRECISION, "Max fee percentage must be between 0.5% and 100%"); diff --git a/contracts/src/test/basicOps.t.sol b/contracts/src/test/basicOps.t.sol index dfdc5fd3..e622e2a4 100644 --- a/contracts/src/test/basicOps.t.sol +++ b/contracts/src/test/basicOps.t.sol @@ -46,11 +46,11 @@ contract BasicOps is DevTestSetup { uint256 trovesCount = troveManager.getTroveIdsCount(); assertEq(trovesCount, 2); - + vm.startPrank(B); borrowerOperations.closeTrove(B_Id); vm.stopPrank(); - + // Check Troves count reduced by 1 trovesCount = troveManager.getTroveIdsCount(); assertEq(trovesCount, 1); @@ -66,7 +66,7 @@ contract BasicOps is DevTestSetup { assertGt(debt_1, 0); uint256 coll_1 = troveManager.getTroveColl(A_Id); assertGt(coll_1, 0); - + // Adjust trove borrowerOperations.adjustTrove(A_Id, 1e18, 1e18, true, 500e18, true); @@ -94,8 +94,6 @@ contract BasicOps is DevTestSetup { // B is now first in line to get redeemed, as they both have the same interest rate, // but B's Trove is younger. - - vm.warp(block.timestamp + troveManager.BOOTSTRAP_PERIOD() + 1); uint256 redemptionAmount = 1000e18; // 1k BOLD @@ -106,7 +104,7 @@ contract BasicOps is DevTestSetup { 10, 1e18 ); - + // Check B's coll and debt reduced uint256 debt_2 = troveManager.getTroveDebt(B_Id); assertLt(debt_2, debt_1); diff --git a/contracts/src/test/troveManager.t.sol b/contracts/src/test/troveManager.t.sol index 035add25..65e30887 100644 --- a/contracts/src/test/troveManager.t.sol +++ b/contracts/src/test/troveManager.t.sol @@ -20,8 +20,6 @@ contract TroveManagerTest is DevTestSetup { uint256 collB1 = troveManager.getTroveColl(BTroveId); assertGt(collB1, 0); - // fast-forward until redemptions are enabled - vm.warp(block.timestamp + troveManager.BOOTSTRAP_PERIOD() + 1); // Reduce ETH price so A’s ICR goes below 100% uint256 newPrice = 1000e18; priceFeed.setPrice(newPrice); @@ -51,4 +49,29 @@ contract TroveManagerTest is DevTestSetup { uint256 collB2 = troveManager.getTroveColl(BTroveId); assertLt(collB2, collB1, "B coll mismatch"); } + + function testInitialRedemptionBaseRate() public { + assertEq(troveManager.baseRate(), 5e16); + } + + function testRedemptionBaseRateAfter2Weeks() public { + assertEq(troveManager.baseRate(), 5e16); + + // Two weeks go by + vm.warp(block.timestamp + 14 days); + + priceFeed.setPrice(2000e18); + openTroveNoHints100pctMaxFee(A, 200 ether, 200000e18, 1e17); + // A redeems 0.01 BOLD, base rate goes down to almost zero (it’s updated on redemption) + vm.startPrank(A); + troveManager.redeemCollateral( + 1e16, + 10, + 1e18 + ); + vm.stopPrank(); + + console.log(troveManager.baseRate(), "baseRate"); + assertLt(troveManager.baseRate(), 3e10); // Goes down below 3e-8, i.e., below 0.000003% + } } diff --git a/contracts/test/BorrowerOperationsTest.js b/contracts/test/BorrowerOperationsTest.js index 9949240f..97848a8f 100644 --- a/contracts/test/BorrowerOperationsTest.js +++ b/contracts/test/BorrowerOperationsTest.js @@ -3551,8 +3551,8 @@ contract("BorrowerOperations", async (accounts) => { const baseRateBefore = await troveManager.baseRate(); - // Artificially make baseRate 5% - await troveManager.setBaseRate(dec(5, 16)); + // Artificially make baseRate 6% (higher than the intital 5%) + await troveManager.setBaseRate(dec(6, 16)); await troveManager.setLastFeeOpTimeToNow(); assert.isTrue((await troveManager.baseRate()).gt(baseRateBefore));