Skip to content

Commit 57f89c7

Browse files
committed
fix: Prevent the ration between batch shares and debt to be too low
1 parent 53c3d2d commit 57f89c7

File tree

3 files changed

+52
-2
lines changed

3 files changed

+52
-2
lines changed

contracts/src/Dependencies/Constants.sol

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ uint128 constant MIN_INTEREST_RATE_CHANGE_PERIOD = 1 seconds; // prevents more t
2828

2929
uint256 constant REDEMPTION_FEE_FLOOR = _1pct / 2; // 0.5%
3030

31+
// For the shares ratio to decrease 1e9 (1e18/MIN_BATCH_SHARES_RATIO),
32+
// at an average annual rate of 10%, it would take more than 217 years (log(1e9)/log(1.1))
33+
// at an average annual rate of 50%, it would take more than 51 years (log(1e9)/log(1.5))
34+
uint256 constant MIN_BATCH_SHARES_RATIO = 1e9;
35+
3136
// Half-life of 12h. 12h = 720 min
3237
// (1/2) = d^720 => d = (1/2)^(1/720)
3338
uint256 constant REDEMPTION_MINUTE_DECAY_FACTOR = 999037758833783000;

contracts/src/TroveManager.sol

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ contract TroveManager is LiquityBase, ITroveManager, ITroveEvents {
166166
error NotShutDown();
167167
error NotEnoughBoldBalance();
168168
error MinCollNotReached(uint256 _coll);
169+
error BatchSharesRatioTooLow();
169170

170171
// --- Events ---
171172

@@ -1784,6 +1785,12 @@ contract TroveManager is LiquityBase, ITroveManager, ITroveEvents {
17841785
if (_batchDebt == 0) {
17851786
batchDebtSharesDelta = debtIncrease;
17861787
} else {
1788+
// For the shares ratio to decrease 1e9 (1e18/MIN_BATCH_SHARES_RATIO),
1789+
// at an average annual rate of 10%, it would take more than 217 years (log(1e9)/log(1.1))
1790+
// at an average annual rate of 50%, it would take more than 51 years (log(1e9)/log(1.5))
1791+
// When that happens, no more debt can be manually added to the batch, so batch should be migrated to a new one
1792+
_requireAtLeastMinSharesRatio(currentBatchDebtShares, _batchDebt);
1793+
17871794
batchDebtSharesDelta = currentBatchDebtShares * debtIncrease / _batchDebt;
17881795
}
17891796

@@ -1825,6 +1832,12 @@ contract TroveManager is LiquityBase, ITroveManager, ITroveEvents {
18251832
}
18261833
}
18271834

1835+
function _requireAtLeastMinSharesRatio(uint256 _currentBatchDebtShares, uint256 _batchDebt) internal pure {
1836+
if (_currentBatchDebtShares * DECIMAL_PRECISION / _batchDebt < MIN_BATCH_SHARES_RATIO) {
1837+
revert BatchSharesRatioTooLow();
1838+
}
1839+
}
1840+
18281841
function onRemoveFromBatch(
18291842
uint256 _troveId,
18301843
uint256 _newTroveColl, // entire, with redistribution

contracts/src/test/rebasingBatchShares.t.sol

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,11 @@ contract RebasingBatchShares is DevTestSetup {
9898

9999
// === 4: Free Loans === //
100100
uint256 debtB4 = borrowerOperations.getEntireSystemDebt();
101-
// We can now open a new Trove
102-
uint256 anotherATroveId = openTroveAndJoinBatchManager(A, 100 ether, MIN_DEBT, B, MIN_ANNUAL_INTEREST_RATE);
101+
// We shouldn’t be able to open a new Trove now
102+
uint256 anotherATroveId = openTroveExpectRevert(A, 100 ether, MIN_DEBT, B);
103+
assertEq(anotherATroveId, 0);
104+
105+
/*
103106
LatestTroveData memory anotherATrove = troveManager.getLatestTroveData(anotherATroveId);
104107
uint256 aDebt = anotherATrove.entireDebt;
105108
@@ -115,6 +118,7 @@ contract RebasingBatchShares is DevTestSetup {
115118
116119
assertGt(debtAfter, debtB4, "Debt should have increased");
117120
assertLt(balB4, balAfter, "Something should have benn paid");
121+
*/
118122
}
119123

120124
uint128 subTractor = 1;
@@ -140,6 +144,7 @@ contract RebasingBatchShares is DevTestSetup {
140144
// Log ratio
141145
uint256 batchSharesRatio = batchShares * DECIMAL_PRECISION / batchDebt;
142146
console2.log("shares / batch ratio: ", batchSharesRatio);
147+
console2.log("Ratio too low? ", batchSharesRatio < MIN_BATCH_SHARES_RATIO);
143148

144149
// Trove
145150
/*
@@ -149,6 +154,7 @@ contract RebasingBatchShares is DevTestSetup {
149154
console2.log("Trove Shares: ", troveBatchShares);
150155
uint256 troveSharesRatio = troveBatchShares * DECIMAL_PRECISION / troveData.entireDebt;
151156
console2.log("Trove ratio: ", troveSharesRatio);
157+
console2.log("Ratio too low? ", troveSharesRatio < MIN_BATCH_SHARES_RATIO);
152158
*/
153159
}
154160

@@ -198,4 +204,30 @@ contract RebasingBatchShares is DevTestSetup {
198204

199205
return allBatchDebtShares;
200206
}
207+
208+
function openTroveExpectRevert(address _troveOwner, uint256 _coll, uint256 _debt, address _batchAddress)
209+
internal
210+
returns (uint256)
211+
{
212+
IBorrowerOperations.OpenTroveAndJoinInterestBatchManagerParams memory params = IBorrowerOperations
213+
.OpenTroveAndJoinInterestBatchManagerParams({
214+
owner: _troveOwner,
215+
ownerIndex: 0,
216+
collAmount: _coll,
217+
boldAmount: _debt,
218+
upperHint: 0,
219+
lowerHint: 0,
220+
interestBatchManager: _batchAddress,
221+
maxUpfrontFee: 1e24,
222+
addManager: address(0),
223+
removeManager: address(0),
224+
receiver: address(0)
225+
});
226+
vm.startPrank(_troveOwner);
227+
vm.expectRevert(TroveManager.BatchSharesRatioTooLow.selector);
228+
uint256 troveId = borrowerOperations.openTroveAndJoinInterestBatchManager(params);
229+
vm.stopPrank();
230+
231+
return troveId;
232+
}
201233
}

0 commit comments

Comments
 (0)