Skip to content

Commit

Permalink
Merge pull request #110 from liquity/initial_redemption_rate
Browse files Browse the repository at this point in the history
feat: Add initial redemption base rate
  • Loading branch information
bingen authored Apr 11, 2024
2 parents 7edba5d + ac8dc73 commit 4e391cb
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 36 deletions.
4 changes: 2 additions & 2 deletions contracts/src/Interfaces/ITroveManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
43 changes: 19 additions & 24 deletions contracts/src/TroveManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 ---

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand All @@ -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 ---
Expand Down Expand Up @@ -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%");
Expand Down
10 changes: 4 additions & 6 deletions contracts/src/test/basicOps.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);

Expand Down Expand Up @@ -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

Expand All @@ -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);
Expand Down
27 changes: 25 additions & 2 deletions contracts/src/test/troveManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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%
}
}
4 changes: 2 additions & 2 deletions contracts/test/BorrowerOperationsTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down

0 comments on commit 4e391cb

Please sign in to comment.