Skip to content

Commit

Permalink
fix: premiums for emergency liquidators
Browse files Browse the repository at this point in the history
  • Loading branch information
0xmikko committed Mar 18, 2023
1 parent 58dcc7e commit a01083f
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 53 deletions.
35 changes: 16 additions & 19 deletions contracts/credit/CreditManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ import {
UNIVERSAL_CONTRACT
} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol";

import "forge-std/console.sol";

uint256 constant ADDR_BIT_SIZE = 160;
uint256 constant INDEX_PRECISION = 10 ** 9;

Expand Down Expand Up @@ -296,19 +298,9 @@ contract CreditManager is ICreditManagerV2, ACLNonReentrantTrait {
// If the contract is paused and the payer is the emergency liquidator,
// changes closure action to LIQUIDATE_PAUSED, so that the premium is nullified
// If the payer is not an emergency liquidator, reverts
if (paused()) {
if (
canLiquidateWhilePaused[payer]
&& (
closureActionType == ClosureAction.LIQUIDATE_ACCOUNT
|| closureActionType == ClosureAction.LIQUIDATE_EXPIRED_ACCOUNT
)
) {
closureActionType = ClosureAction.LIQUIDATE_PAUSED; // F: [CM-12, 13]
} else {
revert("Pausable: paused");
} // F:[CM-5]
}
if (paused() && (closureActionType == ClosureAction.CLOSE_ACCOUNT || !canLiquidateWhilePaused[payer])) {
revert("Pausable: paused");
} // F:[CM-5]

// Checks that the Credit Account exists for the borrower
address creditAccount = getCreditAccountOrRevert(borrower); // F:[CM-6, 9, 10]
Expand Down Expand Up @@ -1198,7 +1190,6 @@ contract CreditManager is ICreditManagerV2, ACLNonReentrantTrait {
if (
closureActionType == ClosureAction.LIQUIDATE_ACCOUNT
|| closureActionType == ClosureAction.LIQUIDATE_EXPIRED_ACCOUNT
|| closureActionType == ClosureAction.LIQUIDATE_PAUSED
) {
// LIQUIDATION CASE

Expand All @@ -1212,17 +1203,23 @@ contract CreditManager is ICreditManagerV2, ACLNonReentrantTrait {
// since the account does not risk bad debt, so the liquidation
// is not as urgent

// UNHEALTHY ACCOUNT CASE
uint256 totalFunds = (
totalValue
* (
closureActionType == ClosureAction.LIQUIDATE_EXPIRED_ACCOUNT
? slot1.liquidationDiscountExpired
: slot1.liquidationDiscount
closureActionType == ClosureAction.LIQUIDATE_ACCOUNT
? slot1.liquidationDiscount
: slot1.liquidationDiscountExpired
)
) / PERCENTAGE_FACTOR; // F:[CM-43]

amountToPool += (totalValue * slot1.feeLiquidation) / PERCENTAGE_FACTOR; // F:[CM-43]
amountToPool += (
totalValue
* (
closureActionType == ClosureAction.LIQUIDATE_ACCOUNT
? slot1.feeLiquidation
: slot1.feeLiquidationExpired
)
) / PERCENTAGE_FACTOR; // F:[CM-43]

// If there are any funds left after all respective payments (this
// includes the liquidation premium, since totalFunds is already
Expand Down
3 changes: 1 addition & 2 deletions contracts/interfaces/ICreditManagerV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import {IVersion} from "@gearbox-protocol/core-v2/contracts/interfaces/IVersion.
enum ClosureAction {
CLOSE_ACCOUNT,
LIQUIDATE_ACCOUNT,
LIQUIDATE_EXPIRED_ACCOUNT,
LIQUIDATE_PAUSED
LIQUIDATE_EXPIRED_ACCOUNT
}

struct CollateralTokenData {
Expand Down
2 changes: 0 additions & 2 deletions contracts/pool/Pool4626.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ import {Errors} from "@gearbox-protocol/core-v2/contracts/libraries/Errors.sol";
// EXCEPTIONS
import {ZeroAddressException} from "../interfaces/IErrors.sol";

import "forge-std/console.sol";

struct CreditManagerDebt {
uint128 totalBorrowed;
uint128 limit;
Expand Down
58 changes: 28 additions & 30 deletions contracts/test/credit/CreditManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,7 @@ contract CreditManagerTest is DSTest, ICreditManagerV2Events, ICreditManagerV2Ex
for (uint256 i = 0; i < 3; i++) {
uint256 friendBalanceBefore = tokenTestSuite.balanceOf(Tokens.DAI, FRIEND);

ClosureAction action = i == 0 ? ClosureAction.LIQUIDATE_ACCOUNT : ClosureAction.LIQUIDATE_EXPIRED_ACCOUNT;
ClosureAction action = i == 1 ? ClosureAction.LIQUIDATE_EXPIRED_ACCOUNT : ClosureAction.LIQUIDATE_ACCOUNT;

(
uint256 borrowedAmount,
Expand All @@ -745,9 +745,8 @@ contract CreditManagerTest is DSTest, ICreditManagerV2Events, ICreditManagerV2Ex

uint256 interestAccrued = (borrowedAmount * cumulativeIndexAtClose) / cumulativeIndexAtOpen - borrowedAmount;

uint256 discount = i == 2
? PERCENTAGE_FACTOR
: action == ClosureAction.LIQUIDATE_ACCOUNT ? liquidationDiscount : liquidationDiscountExpired;
uint256 discount =
action == ClosureAction.LIQUIDATE_ACCOUNT ? liquidationDiscount : liquidationDiscountExpired;

uint256 amountToPool = (totalValue * discount) / PERCENTAGE_FACTOR;

Expand Down Expand Up @@ -833,8 +832,7 @@ contract CreditManagerTest is DSTest, ICreditManagerV2Events, ICreditManagerV2Ex

(feeInterest,, liquidationDiscountNormal,, liquidationDiscountExpired) = creditManager.fees();

liquidationDiscount =
i == 0 ? liquidationDiscountNormal : i == 1 ? liquidationDiscountExpired : PERCENTAGE_FACTOR;
liquidationDiscount = i == 1 ? liquidationDiscountExpired : liquidationDiscountNormal;
}

uint256 profitInterest = (interestAccrued * feeInterest) / PERCENTAGE_FACTOR;
Expand Down Expand Up @@ -874,7 +872,7 @@ contract CreditManagerTest is DSTest, ICreditManagerV2Events, ICreditManagerV2Ex

uint256 remainingFunds = creditManager.closeCreditAccount(
USER,
i == 0 ? ClosureAction.LIQUIDATE_ACCOUNT : ClosureAction.LIQUIDATE_EXPIRED_ACCOUNT,
i == 1 ? ClosureAction.LIQUIDATE_EXPIRED_ACCOUNT : ClosureAction.LIQUIDATE_ACCOUNT,
totalValue,
LIQUIDATOR,
FRIEND,
Expand Down Expand Up @@ -1712,7 +1710,7 @@ contract CreditManagerTest is DSTest, ICreditManagerV2Events, ICreditManagerV2Ex
9800 // liquidationPremiumExpired: 2%
);

CalcClosePaymentsPureTestCase[9] memory cases = [
CalcClosePaymentsPureTestCase[7] memory cases = [
CalcClosePaymentsPureTestCase({
name: "CLOSURE",
totalValue: 0,
Expand Down Expand Up @@ -1789,29 +1787,29 @@ contract CreditManagerTest is DSTest, ICreditManagerV2Events, ICreditManagerV2Ex
remainingFunds: 0, // 0, cause it's loss
profit: 0,
loss: 920
}),
CalcClosePaymentsPureTestCase({
name: "LIQUIDATION WHILE PAUSED WITH REMAINING FUNDS",
totalValue: 2000,
closureActionType: ClosureAction.LIQUIDATE_PAUSED,
borrowedAmount: 1000,
borrowedAmountWithInterest: 1100,
amountToPool: 1150, // amountToPool = 1100 + 100 * 10% + 2000 * 2% = 1150
remainingFunds: 849, //remainingFunds: 2000 - 1150 - 1 = 869
profit: 50,
loss: 0
}),
CalcClosePaymentsPureTestCase({
name: "LIQUIDATION OF EXPIRED WITH LOSS",
totalValue: 1000,
closureActionType: ClosureAction.LIQUIDATE_PAUSED,
borrowedAmount: 900,
borrowedAmountWithInterest: 1900,
amountToPool: 1000, // amountToPool = 1900 + 1000 * 10% + 1000 * 2% = 2020, totalFunds = 1000 * 98% = 980, So, amount to pool would be 980
remainingFunds: 0, // 0, cause it's loss
profit: 0,
loss: 900
})
// CalcClosePaymentsPureTestCase({
// name: "LIQUIDATION WHILE PAUSED WITH REMAINING FUNDS",
// totalValue: 2000,
// closureActionType: ClosureAction.LIQUIDATE_PAUSED,
// borrowedAmount: 1000,
// borrowedAmountWithInterest: 1100,
// amountToPool: 1150, // amountToPool = 1100 + 100 * 10% + 2000 * 2% = 1150
// remainingFunds: 849, //remainingFunds: 2000 - 1150 - 1 = 869
// profit: 50,
// loss: 0
// }),
// CalcClosePaymentsPureTestCase({
// name: "LIQUIDATION OF EXPIRED WITH LOSS",
// totalValue: 1000,
// closureActionType: ClosureAction.LIQUIDATE_PAUSED,
// borrowedAmount: 900,
// borrowedAmountWithInterest: 1900,
// amountToPool: 1000, // amountToPool = 1900 + 1000 * 10% + 1000 * 2% = 2020, totalFunds = 1000 * 98% = 980, So, amount to pool would be 980
// remainingFunds: 0, // 0, cause it's loss
// profit: 0,
// loss: 900
// })
];

for (uint256 i = 0; i < cases.length; i++) {
Expand Down

0 comments on commit a01083f

Please sign in to comment.