Skip to content

Commit

Permalink
fix: feeToken draft for credit manager
Browse files Browse the repository at this point in the history
  • Loading branch information
0xmikko committed May 4, 2023
1 parent 554da69 commit 4387826
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 177 deletions.
195 changes: 100 additions & 95 deletions contracts/credit/CreditManagerV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,12 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuard,
// If there is an underlying shortfall, attempts to transfer it from the payer
} else {
unchecked {
_transferFrom(underlying, payer, creditAccount, amountToPool + remainingFunds - underlyingBalance + 1); // F:[CM-11,13]
_transferFrom(
underlying,
payer,
creditAccount,
_amountWithFee(amountToPool + remainingFunds - underlyingBalance + 1)
); // F:[CM-11,13]
}
}

Expand Down Expand Up @@ -352,6 +357,100 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuard,
creditAccountsSet.remove(creditAccount);
}

/// @dev Computes amounts that must be sent to various addresses before closing an account
/// @param closureAction Type of account closure
/// * CLOSE_ACCOUNT: The account is healthy and is closed normally
/// * LIQUIDATE_ACCOUNT: The account is unhealthy and is being liquidated to avoid bad debt
/// * LIQUIDATE_EXPIRED_ACCOUNT: The account has expired and is being liquidated (lowered liquidation premium)
/// * LIQUIDATE_PAUSED: The account is liquidated while the system is paused due to emergency (no liquidation premium)
/// @return amountToPool Amount of underlying to be sent to the pool
/// @return remainingFunds Amount of underlying to be sent to the borrower (only applicable to liquidations)
/// @return profit Protocol's profit from fees (if any)
/// @return loss Protocol's loss from bad debt (if any)
function calcClosePayments(ClosureAction closureAction, CollateralDebtData memory collateralDebtData)
public
view
override
returns (uint256 amountToPool, uint256 remainingFunds, uint256 profit, uint256 loss)
{
uint256 debtWithInterest = collateralDebtData.debtWithInterest;
// The amount to be paid to pool is computed with fees included
// The pool will compute the amount of Diesel tokens to treasury
// based on profit
amountToPool =
debtWithInterest + ((debtWithInterest - collateralDebtData.debt) * feeInterest) / PERCENTAGE_FACTOR; // F:[CM-43]

if (
closureAction == ClosureAction.LIQUIDATE_ACCOUNT || closureAction == ClosureAction.LIQUIDATE_EXPIRED_ACCOUNT
) {
// LIQUIDATION CASE
uint256 totalValue = collateralDebtData.totalValue;
// During liquidation, totalValue of the account is discounted
// by (1 - liquidationPremium). This means that totalValue * liquidationPremium
// is removed from all calculations and can be claimed by the liquidator at the end of transaction

// The liquidation premium depends on liquidation type:
// * For normal unhealthy account or emergency liquidations, usual premium applies
// * For expiry liquidations, the premium is typically reduced,
// since the account does not risk bad debt, so the liquidation
// is not as urgent

uint256 totalFunds = (
totalValue
* (closureAction == ClosureAction.LIQUIDATE_ACCOUNT ? liquidationDiscount : liquidationDiscountExpired)
) / PERCENTAGE_FACTOR; // F:[CM-43]

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

/// Adding fee here
uint256 amountToPoolWithFee = _amountWithFee(amountToPool);

// If there are any funds left after all respective payments (this
// includes the liquidation premium, since totalFunds is already
// discounted from totalValue), they are recorded to remainingFunds
// and will later be sent to the borrower.

// If totalFunds is not sufficient to cover the entire payment to pool,
// the Credit Manager will repay what it can. When totalFunds >= debt + interest,
// this simply means that part of protocol fees will be waived (profit is reduced). Otherwise,
// there is bad debt (loss > 0).

// Since values are compared to each other before subtracting,
// this can be marked as unchecked to optimize gas

unchecked {
if (totalFunds > amountToPoolWithFee) {
remainingFunds = totalFunds - amountToPoolWithFee - 1; // F:[CM-43]
} else {
amountToPool = totalFunds; // F:[CM-43]
}

if (totalFunds >= _amountWithFee(debtWithInterest)) {
profit = amountToPool - debtWithInterest; // F:[CM-43]
} else {
loss = debtWithInterest - amountToPool; // F:[CM-43]
}
}
} else {
// CLOSURE CASE

// During closure, it is assumed that the user has enough to cover
// the principal + interest + fees. closeCreditAccount, thus, will
// attempt to charge them the entire amount.

// Since in this case amountToPool + debtWithInterest + fee,
// this block can be marked as unchecked

unchecked {
profit = amountToPool - debtWithInterest; // F:[CM-43]
}

amountToPool = _amountWithFee(amountToPool);
}
}

/// @dev Manages debt size for borrower:
///
/// - Increase debt:
Expand Down Expand Up @@ -1002,100 +1101,6 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuard,
// GETTERS
//

/// @dev Computes amounts that must be sent to various addresses before closing an account
/// @param closureAction Type of account closure
/// * CLOSE_ACCOUNT: The account is healthy and is closed normally
/// * LIQUIDATE_ACCOUNT: The account is unhealthy and is being liquidated to avoid bad debt
/// * LIQUIDATE_EXPIRED_ACCOUNT: The account has expired and is being liquidated (lowered liquidation premium)
/// * LIQUIDATE_PAUSED: The account is liquidated while the system is paused due to emergency (no liquidation premium)
/// @return amountToPool Amount of underlying to be sent to the pool
/// @return remainingFunds Amount of underlying to be sent to the borrower (only applicable to liquidations)
/// @return profit Protocol's profit from fees (if any)
/// @return loss Protocol's loss from bad debt (if any)
function calcClosePayments(ClosureAction closureAction, CollateralDebtData memory collateralDebtData)
public
view
override
returns (uint256 amountToPool, uint256 remainingFunds, uint256 profit, uint256 loss)
{
uint256 debtWithInterest = collateralDebtData.debtWithInterest;
// The amount to be paid to pool is computed with fees included
// The pool will compute the amount of Diesel tokens to treasury
// based on profit
amountToPool =
debtWithInterest + ((debtWithInterest - collateralDebtData.debt) * feeInterest) / PERCENTAGE_FACTOR; // F:[CM-43]

if (
closureAction == ClosureAction.LIQUIDATE_ACCOUNT || closureAction == ClosureAction.LIQUIDATE_EXPIRED_ACCOUNT
) {
// LIQUIDATION CASE
uint256 totalValue = collateralDebtData.totalValue;
// During liquidation, totalValue of the account is discounted
// by (1 - liquidationPremium). This means that totalValue * liquidationPremium
// is removed from all calculations and can be claimed by the liquidator at the end of transaction

// The liquidation premium depends on liquidation type:
// * For normal unhealthy account or emergency liquidations, usual premium applies
// * For expiry liquidations, the premium is typically reduced,
// since the account does not risk bad debt, so the liquidation
// is not as urgent

uint256 totalFunds = (
totalValue
* (closureAction == ClosureAction.LIQUIDATE_ACCOUNT ? liquidationDiscount : liquidationDiscountExpired)
) / PERCENTAGE_FACTOR; // F:[CM-43]

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

/// Adding fee here
uint256 amountToPoolWithFee = _amountWithFee(amountToPool);

// If there are any funds left after all respective payments (this
// includes the liquidation premium, since totalFunds is already
// discounted from totalValue), they are recorded to remainingFunds
// and will later be sent to the borrower.

// If totalFunds is not sufficient to cover the entire payment to pool,
// the Credit Manager will repay what it can. When totalFunds >= debt + interest,
// this simply means that part of protocol fees will be waived (profit is reduced). Otherwise,
// there is bad debt (loss > 0).

// Since values are compared to each other before subtracting,
// this can be marked as unchecked to optimize gas

unchecked {
if (totalFunds > amountToPoolWithFee) {
remainingFunds = totalFunds - amountToPoolWithFee - 1; // F:[CM-43]
} else {
amountToPool = totalFunds; // F:[CM-43]
}

if (totalFunds >= _amountWithFee(debtWithInterest)) {
profit = amountToPool - debtWithInterest; // F:[CM-43]
} else {
loss = debtWithInterest - amountToPool; // F:[CM-43]
}
}
} else {
// CLOSURE CASE

// During closure, it is assumed that the user has enough to cover
// the principal + interest + fees. closeCreditAccount, thus, will
// attempt to charge them the entire amount.

// Since in this case amountToPool + debtWithInterest + fee,
// this block can be marked as unchecked

unchecked {
profit = amountToPool - debtWithInterest; // F:[CM-43]
}

amountToPool = _amountWithFee(amountToPool);
}
}

/// @dev Returns the collateral token at requested index and its liquidation threshold
/// @param id The index of token to return
function collateralTokens(uint256 id) public view returns (address token, uint16 liquidationThreshold) {
Expand Down
83 changes: 1 addition & 82 deletions contracts/libraries/CreditLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,85 +6,4 @@ pragma solidity ^0.8.17;
import {CollateralDebtData} from "../interfaces/ICreditManagerV3.sol";

/// @title Quota Library
library CreditLogic {
function calcClosePayments(CollateralDebtData memory collateralDebtData, uint16 feeInterest)
internal
returns (uint256 amountToPool, uint256 profit)
{
uint256 totalValue = collateralDebtData.totalValue;
uint256 debtWithInterest = collateralDebtData.debtWithInterest;
// The amount to be paid to pool is computed with fees included
// The pool will compute the amount of Diesel tokens to treasury
// based on profit
amountToPool =
debtWithInterest + ((debtWithInterest - collateralDebtData.debt) * feeInterest) / PERCENTAGE_FACTOR; // F:[CM-43]

if (
closureAction == ClosureAction.LIQUIDATE_ACCOUNT || closureAction == ClosureAction.LIQUIDATE_EXPIRED_ACCOUNT
) {
// LIQUIDATION CASE

// During liquidation, totalValue of the account is discounted
// by (1 - liquidationPremium). This means that totalValue * liquidationPremium
// is removed from all calculations and can be claimed by the liquidator at the end of transaction

// The liquidation premium depends on liquidation type:
// * For normal unhealthy account or emergency liquidations, usual premium applies
// * For expiry liquidations, the premium is typically reduced,
// since the account does not risk bad debt, so the liquidation
// is not as urgent

uint256 totalFunds = (
totalValue
* (closureAction == ClosureAction.LIQUIDATE_ACCOUNT ? liquidationDiscount : liquidationDiscountExpired)
) / PERCENTAGE_FACTOR; // F:[CM-43]

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

/// Adding fee here
// amountToPool = _amountWithFee(amountToPool);

// If there are any funds left after all respective payments (this
// includes the liquidation premium, since totalFunds is already
// discounted from totalValue), they are recorded to remainingFunds
// and will later be sent to the borrower.

// If totalFunds is not sufficient to cover the entire payment to pool,
// the Credit Manager will repay what it can. When totalFunds >= debt + interest,
// this simply means that part of protocol fees will be waived (profit is reduced). Otherwise,
// there is bad debt (loss > 0).

// Since values are compared to each other before subtracting,
// this can be marked as unchecked to optimize gas

unchecked {
if (totalFunds > amountToPool) {
remainingFunds = totalFunds - amountToPool - 1; // F:[CM-43]
} else {
amountToPool = totalFunds; // F:[CM-43]
}

if (totalFunds >= debtWithInterest) {
profit = amountToPool - debtWithInterest; // F:[CM-43]
} else {
loss = debtWithInterest - amountToPool; // F:[CM-43]
}
}
} else {
// CLOSURE CASE

// During closure, it is assumed that the user has enough to cover
// the principal + interest + fees. closeCreditAccount, thus, will
// attempt to charge them the entire amount.

// Since in this case amountToPool + debtWithInterest + fee,
// this block can be marked as unchecked

unchecked {
profit = amountToPool - debtWithInterest; // F:[CM-43]
}
}
}
}
library CreditLogic {}

0 comments on commit 4387826

Please sign in to comment.