Skip to content

Commit

Permalink
Merge pull request #259 from liquity/redemptions_when_zero_unbacked
Browse files Browse the repository at this point in the history
fix: Take care of redemptions when all redeemable branches have zero …
  • Loading branch information
bingen authored Jul 21, 2024
2 parents 4aaffe7 + 5221302 commit 4c3767f
Show file tree
Hide file tree
Showing 5 changed files with 282 additions and 18 deletions.
17 changes: 16 additions & 1 deletion contracts/src/CollateralRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,25 @@ contract CollateralRegistry is LiquityBase, ICollateralRegistry {
ITroveManager troveManager = getTroveManager(index);
(uint256 unbackedPortion, uint256 price, bool redeemable) =
troveManager.getUnbackedPortionPriceAndRedeemability();
prices[index] = price;
if (redeemable) {
totals.unbacked += unbackedPortion;
unbackedPortions[index] = unbackedPortion;
prices[index] = price;
}
}

// There’s an unlikely scenario where all the normally redeemable branches (i.e. having TCR > SCR) have 0 unbacked
// In that case, we redeem proportinally to branch size
if (totals.unbacked == 0) {
unbackedPortions = new uint256[](totals.numCollaterals);
for (uint256 index = 0; index < totals.numCollaterals; index++) {
ITroveManager troveManager = getTroveManager(index);
(,, bool redeemable) = troveManager.getUnbackedPortionPriceAndRedeemability();
if (redeemable) {
uint256 unbackedPortion = troveManager.getEntireSystemDebt();
totals.unbacked += unbackedPortion;
unbackedPortions[index] = unbackedPortion;
}
}
}

Expand Down
19 changes: 14 additions & 5 deletions contracts/src/test/TestContracts/InvariantsTestHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1508,18 +1508,27 @@ contract InvariantsTestHandler is BaseHandler, BaseMultiCollateralTest {
uint256 feePct,
RedemptionTotals[] memory t
) internal returns (uint256 totalRedeemed) {
uint256 totalUnbacked = 0;
uint256[] memory unbacked = new uint256[](branches.length);
uint256 totalProportions = 0;
uint256[] memory proportions = new uint256[](branches.length);

// Try in proportion to unbacked
for (uint256 j = 0; j < branches.length; ++j) {
if (isShutdown[j] || _TCR(j) < SCR[j]) continue;
totalUnbacked += unbacked[j] = _getUnbacked(j);
totalProportions += proportions[j] = _getUnbacked(j);
}

if (totalUnbacked == 0) return 0;
// Fallback: in proportion to branch debt
if (totalProportions == 0) {
for (uint256 j = 0; j < branches.length; ++j) {
if (isShutdown[j] || _TCR(j) < SCR[j]) continue;
totalProportions += proportions[j] = _getTotalDebt(j);
}
}

if (totalProportions == 0) return 0;

for (uint256 j = 0; j < branches.length; ++j) {
t[j].attemptedAmount = amount * unbacked[j] / totalUnbacked;
t[j].attemptedAmount = amount * proportions[j] / totalProportions;
if (t[j].attemptedAmount == 0) continue;

LiquityContractsDev memory c = branches[j];
Expand Down
28 changes: 20 additions & 8 deletions contracts/src/test/liquidations.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@ contract LiquidationsTest is DevTestSetup {

priceFeed.setPrice(2000e18);
vm.startPrank(A);
uint256 ATroveId = borrowerOperations.openTrove(A, 0, collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
uint256 ATroveId =
borrowerOperations.openTrove(A, 0, collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
vm.stopPrank();

vm.startPrank(B);
borrowerOperations.openTrove(B, 0, 2 * collAmount, liquidationAmount + 100e18, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
borrowerOperations.openTrove(
B, 0, 2 * collAmount, liquidationAmount + 100e18, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18
);
vm.stopPrank();
// B deposits to SP
makeSPDepositAndClaim(B, liquidationAmount + 100e18);
Expand Down Expand Up @@ -95,11 +98,14 @@ contract LiquidationsTest is DevTestSetup {

priceFeed.setPrice(2000e18);
vm.startPrank(A);
uint256 ATroveId = borrowerOperations.openTrove(A, 0, collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
uint256 ATroveId =
borrowerOperations.openTrove(A, 0, collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
vm.stopPrank();

vm.startPrank(B);
borrowerOperations.openTrove(B, 0, 3 * collAmount, liquidationAmount + 100e18, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
borrowerOperations.openTrove(
B, 0, 3 * collAmount, liquidationAmount + 100e18, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18
);
vm.stopPrank();
// B deposits to SP
makeSPDepositAndClaim(B, liquidationAmount + 100e18);
Expand Down Expand Up @@ -153,11 +159,14 @@ contract LiquidationsTest is DevTestSetup {

priceFeed.setPrice(2000e18);
vm.startPrank(A);
uint256 ATroveId = borrowerOperations.openTrove(A, 0, collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
uint256 ATroveId =
borrowerOperations.openTrove(A, 0, collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
vm.stopPrank();

vm.startPrank(B);
uint256 BTroveId = borrowerOperations.openTrove(B, 0, 2 * collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
uint256 BTroveId = borrowerOperations.openTrove(
B, 0, 2 * collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18
);

// Price drops
priceFeed.setPrice(1100e18 - 1);
Expand Down Expand Up @@ -215,11 +224,14 @@ contract LiquidationsTest is DevTestSetup {

priceFeed.setPrice(2000e18);
vm.startPrank(A);
uint256 ATroveId = borrowerOperations.openTrove(A, 0, collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
uint256 ATroveId =
borrowerOperations.openTrove(A, 0, collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
vm.stopPrank();

vm.startPrank(B);
uint256 BTroveId = borrowerOperations.openTrove(B, 0, 2 * collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
uint256 BTroveId = borrowerOperations.openTrove(
B, 0, 2 * collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18
);
vm.stopPrank();
// B deposits to SP
makeSPDepositAndClaim(B, liquidationAmount / 2);
Expand Down
14 changes: 10 additions & 4 deletions contracts/src/test/liquidationsLST.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,14 @@ contract LiquidationsLSTTest is DevTestSetup {

priceFeed.setPrice(2000e18);
vm.startPrank(A);
uint256 ATroveId = borrowerOperations.openTrove(A, 0, collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
uint256 ATroveId =
borrowerOperations.openTrove(A, 0, collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
vm.stopPrank();

vm.startPrank(B);
uint256 BTroveId = borrowerOperations.openTrove(B, 0, 2 * collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
uint256 BTroveId = borrowerOperations.openTrove(
B, 0, 2 * collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18
);

// Price drops
priceFeed.setPrice(1200e18 - 1);
Expand Down Expand Up @@ -152,11 +155,14 @@ contract LiquidationsLSTTest is DevTestSetup {

priceFeed.setPrice(initialPrice);
vm.startPrank(A);
uint256 ATroveId = borrowerOperations.openTrove(A, 0, collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
uint256 ATroveId =
borrowerOperations.openTrove(A, 0, collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
vm.stopPrank();

vm.startPrank(B);
uint256 BTroveId = borrowerOperations.openTrove(B, 0, 3 * collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18);
uint256 BTroveId = borrowerOperations.openTrove(
B, 0, 3 * collAmount, liquidationAmount, 0, 0, MIN_ANNUAL_INTEREST_RATE, 1000e18
);
vm.stopPrank();
// B deposits to SP
if (_spAmount > 0) {
Expand Down
Loading

0 comments on commit 4c3767f

Please sign in to comment.