Skip to content

Commit

Permalink
fix: manageDebt switched to cdd
Browse files Browse the repository at this point in the history
  • Loading branch information
0xmikko committed May 14, 2023
1 parent 79e9ac4 commit aae10ff
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 146 deletions.
118 changes: 32 additions & 86 deletions contracts/credit/CreditManagerV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -422,20 +422,18 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuard
creditFacadeOnly // F:[CM-2]
returns (uint256 newDebt, uint256 tokensToEnable, uint256 tokensToDisable)
{
(uint256 debt, uint256 cumulativeIndexLastUpdate, uint256 cumulativeIndexNow) =
_getCreditAccountParameters(creditAccount);
CollateralDebtData memory collateralDebtData;
_getCreditAccountParameters({collateralDebtData: collateralDebtData, creditAccount: creditAccount});

uint256 newCumulativeIndex;
if (action == ManageDebtAction.INCREASE_DEBT) {
(newDebt, newCumulativeIndex) =
CreditLogic.calcIncrease(debt, amount, cumulativeIndexNow, cumulativeIndexLastUpdate);
(newDebt, newCumulativeIndex) = collateralDebtData.calcIncrease(amount);

// Requests the pool to lend additional funds to the Credit Account
IPoolBase(pool).lendCreditAccount(amount, creditAccount); // F:[CM-20]
tokensToEnable = UNDERLYING_TOKEN_MASK;
} else {
// Decrease

CollateralDebtData memory collateralDebtData;
collateralDebtData.enabledTokensMask = enabledTokensMask;

if (supportsQuotas) {
Expand All @@ -447,10 +445,7 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuard
collateralDebtData: collateralDebtData,
creditAccount: creditAccount,
countQuotedCollateral: false,
_priceOracle: address(0), // PriceOracle not needed to compute debt only
debt: debt,
cumulativeIndexLastUpdate: cumulativeIndexLastUpdate,
cumulativeIndexNow: cumulativeIndexNow
_priceOracle: address(0) // PriceOracle not needed to compute debt only
});

if (supportsQuotas) {
Expand All @@ -463,12 +458,8 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuard
uint256 amountToRepay;
uint256 profit;

(newDebt, newCumulativeIndex, amountToRepay, profit) = collateralDebtData.calcDescrease({
amount: amount,
feeInterest: feeInterest,
cumulativeIndexNow: cumulativeIndexNow,
cumulativeIndexLastUpdate: cumulativeIndexLastUpdate
});
(newDebt, newCumulativeIndex, amountToRepay, profit) =
collateralDebtData.calcDescrease({amount: amount, feeInterest: feeInterest});

IPoolBase(pool).repayCreditAccount(amountToRepay, profit, 0); // F:[CM-21]
}
Expand All @@ -483,7 +474,7 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuard
}
//
// Sets new parameters on the Credit Account if they were changed
if (newDebt != debt || newCumulativeIndex != cumulativeIndexLastUpdate) {
if (newDebt != collateralDebtData.debt || newCumulativeIndex != collateralDebtData.cumulativeIndexLastUpdate) {
creditAccountInfo[creditAccount].debt = newDebt; // F:[CM-20. 21]
creditAccountInfo[creditAccount].cumulativeIndexLastUpdate = newCumulativeIndex; // F:[CM-20. 21]
}
Expand Down Expand Up @@ -615,21 +606,7 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuard
uint256[] memory collateralHints;

_calcFullCollateral(collateralDebtData, creditAccount, PERCENTAGE_FACTOR, collateralHints, false);

/// ADD ENABLED TOKENS MASK
if (
(
task == CollateralCalcTask.DEBT_COLLATERAL_CANCEL_WITHDRAWALS
|| task == CollateralCalcTask.DEBT_COLLATERAL_FORCE_CANCEL_WITHDRAWALS
) && _hasWithdrawals(creditAccount)
) {
_calcAndUpdateCancellableWithdrawalsValue(
collateralDebtData,
creditAccount,
task == CollateralCalcTask.DEBT_COLLATERAL_FORCE_CANCEL_WITHDRAWALS,
_priceOracle
);
}
_calcAndUpdateCancellableWithdrawalsValue(collateralDebtData, creditAccount, task, _priceOracle);

collateralDebtData.totalValue =
IPriceOracleV2(_priceOracle).convertFromUSD(collateralDebtData.totalValueUSD, underlying); // F:[FA-41]
Expand Down Expand Up @@ -699,17 +676,13 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuard
// The total weighted value of a Credit Account has to be compared
// with the entire debt sum, including interest and fees
// (collateralDebtData.debt, collateralDebtData.accruedInterest, collateralDebtData.accruedFees) =
(uint256 debt, uint256 cumulativeIndexLastUpdate, uint256 cumulativeIndexNow) =
_getCreditAccountParameters(creditAccount);
_getCreditAccountParameters({collateralDebtData: collateralDebtData, creditAccount: creditAccount});

_calcDebtAndQuotedCollateral({
collateralDebtData: collateralDebtData,
creditAccount: creditAccount,
countQuotedCollateral: countQuotedCollateral,
_priceOracle: _priceOracle,
debt: debt,
cumulativeIndexLastUpdate: cumulativeIndexLastUpdate,
cumulativeIndexNow: cumulativeIndexNow
_priceOracle: _priceOracle
});
}

Expand Down Expand Up @@ -747,35 +720,6 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuard
// QUOTAS MANAGEMENT
//

// /// @dev Returns the array of quoted tokens that are enabled on the account
// function getQuotedTokens(address creditAccount) public view returns (address[] memory tokens) {
// (tokens,) = _getQuotedTokens({enabledTokensMask: enabledTokensMaskOf(creditAccount), withLTs: false});
// }

// function _getQuotedTokens(uint256 enabledTokensMask, bool withLTs)
// internal
// view
// returns (address[] memory tokens, uint256[] memory lts)
// {
// uint256 quotedMask = enabledTokensMask & quotedTokenMask;

// if (quotedMask > 0) {
// tokens = new address[](maxAllowedEnabledTokenLength );
// lts = new uint256[](maxAllowedEnabledTokenLength );

// uint256 j;

// unchecked {
// for (uint256 tokenMask = 2; tokenMask <= quotedMask; tokenMask <<= 1) {
// if (quotedMask & tokenMask != 0) {
// (tokens[j], lts[j]) = _collateralTokensByMask({tokenMask: tokenMask, calcLT: withLTs});
// ++j;
// }
// }
// }
// }
// }

/// @dev Updates credit account's quotas for multiple tokens
/// @param creditAccount Address of credit account
function updateQuota(address creditAccount, address token, int96 quotaChange)
Expand Down Expand Up @@ -929,19 +873,13 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuard

/// @dev Returns the parameters of the Credit Account required to calculate debt
/// @param creditAccount Address of the Credit Account
/// @return debt Debt principal amount
/// @return cumulativeIndexLastUpdate The cumulative index value used to calculate
/// interest in conjunction with current pool index. Not necessarily the index
/// value at the time of account opening, since it can be updated by manageDebt.
/// @return cumulativeIndexNow Current cumulative index of the pool
function _getCreditAccountParameters(address creditAccount)
function _getCreditAccountParameters(CollateralDebtData memory collateralDebtData, address creditAccount)
internal
view
returns (uint256 debt, uint256 cumulativeIndexLastUpdate, uint256 cumulativeIndexNow)
{
debt = creditAccountInfo[creditAccount].debt; // F:[CM-49,50]
cumulativeIndexLastUpdate = creditAccountInfo[creditAccount].cumulativeIndexLastUpdate; // F:[CM-49,50]
cumulativeIndexNow = IPoolBase(pool).calcLinearCumulative_RAY(); // F:[CM-49,50]
collateralDebtData.debt = creditAccountInfo[creditAccount].debt; // F:[CM-49,50]
collateralDebtData.cumulativeIndexLastUpdate = creditAccountInfo[creditAccount].cumulativeIndexLastUpdate; // F:[CM-49,50]
collateralDebtData.cumulativeIndexNow = IPoolBase(pool).calcLinearCumulative_RAY(); // F:[CM-49,50]
}

/// @dev Returns the liquidation threshold for the provided token
Expand Down Expand Up @@ -1229,17 +1167,25 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuard
function _calcAndUpdateCancellableWithdrawalsValue(
CollateralDebtData memory collateralDebtData,
address creditAccount,
bool isForceCancel,
CollateralCalcTask task,
address _priceOracle
) internal view {
(address token1, uint256 amount1, address token2, uint256 amount2) =
IWithdrawalManager(withdrawalManager).cancellableScheduledWithdrawals(creditAccount, isForceCancel);

if (amount1 != 0) {
_addTotalValueInUSDUAndEnableInPlace(collateralDebtData, token1, amount1, _priceOracle);
}
if (amount2 != 0) {
_addTotalValueInUSDUAndEnableInPlace(collateralDebtData, token2, amount2, _priceOracle);
if (
(
task == CollateralCalcTask.DEBT_COLLATERAL_CANCEL_WITHDRAWALS
|| task == CollateralCalcTask.DEBT_COLLATERAL_FORCE_CANCEL_WITHDRAWALS
) && _hasWithdrawals(creditAccount)
) {
bool isForceCancel = task == CollateralCalcTask.DEBT_COLLATERAL_FORCE_CANCEL_WITHDRAWALS;
(address token1, uint256 amount1, address token2, uint256 amount2) =
IWithdrawalManager(withdrawalManager).cancellableScheduledWithdrawals(creditAccount, isForceCancel);

if (amount1 != 0) {
_addTotalValueInUSDUAndEnableInPlace(collateralDebtData, token1, amount1, _priceOracle);
}
if (amount2 != 0) {
_addTotalValueInUSDUAndEnableInPlace(collateralDebtData, token2, amount2, _priceOracle);
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions contracts/interfaces/ICreditManagerV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ enum CollateralCalcTask {

struct CollateralDebtData {
uint256 debt;
uint256 cumulativeIndexNow;
uint256 cumulativeIndexLastUpdate;
uint256 accruedInterest;
uint256 accruedFees;
uint256 totalValue;
Expand Down
4 changes: 4 additions & 0 deletions contracts/libraries/CreditAccountHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import {IERC20Helper} from "./IERC20Helper.sol";

import {ICreditAccount} from "../interfaces/ICreditAccount.sol";
import {AllowanceFailedException} from "../interfaces/IExceptions.sol";

import {IWETHGateway} from "../interfaces/IWETHGateway.sol";
import {IWithdrawalManager} from "../interfaces/IWithdrawalManager.sol";

/// @title CreditAccount Helper library

library CreditAccountHelper {
Expand Down
44 changes: 23 additions & 21 deletions contracts/libraries/CreditLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -158,18 +158,15 @@ library CreditLogic {
/// MANAGE DEBT

/// @dev Calculates the new cumulative index when debt is updated
/// @param debt Current debt principal
/// @param delta Absolute value of total debt amount change
/// @param cumulativeIndexNow Current cumulative index of the pool
/// @param cumulativeIndexOpen Last updated cumulative index recorded for the corresponding debt position
/// @notice Handles two potential cases:
/// * Debt principal is increased by delta - in this case, the principal is changed
/// but the interest / fees have to stay the same
/// * Interest is decreased by delta - in this case, the principal stays the same,
/// but the interest changes. The delta is assumed to have fee repayment excluded.
/// The debt decrease case where delta > interest + fees is trivial and should be handled outside
/// this function.
function calcIncrease(uint256 debt, uint256 delta, uint256 cumulativeIndexNow, uint256 cumulativeIndexOpen)
function calcIncrease(CollateralDebtData memory collateralDebtData, uint256 delta)
internal
pure
returns (uint256 newDebt, uint256 newCumulativeIndex)
Expand All @@ -179,21 +176,22 @@ library CreditLogic {
// debt * (cumulativeIndexNow / cumulativeIndexOpen - 1) ==
// == (debt + delta) * (cumulativeIndexNow / newCumulativeIndex - 1)

newDebt = debt + delta;
newDebt = collateralDebtData.debt + delta;

newCumulativeIndex = (
(cumulativeIndexNow * newDebt * INDEX_PRECISION)
/ ((INDEX_PRECISION * cumulativeIndexNow * debt) / cumulativeIndexOpen + INDEX_PRECISION * delta)
(collateralDebtData.cumulativeIndexNow * newDebt * INDEX_PRECISION)
/ (
(INDEX_PRECISION * collateralDebtData.cumulativeIndexNow * collateralDebtData.debt)
/ collateralDebtData.cumulativeIndexLastUpdate + INDEX_PRECISION * delta
)
);
}

function calcDescrease(
CollateralDebtData memory collateralDebtData,
uint256 amount,
uint16 feeInterest,
uint256 cumulativeIndexNow,
uint256 cumulativeIndexLastUpdate
) internal pure returns (uint256 newDebt, uint256 newCumulativeIndex, uint256 amountToRepay, uint256 profit) {
function calcDescrease(CollateralDebtData memory collateralDebtData, uint256 amount, uint16 feeInterest)
internal
pure
returns (uint256 newDebt, uint256 newCumulativeIndex, uint256 amountToRepay, uint256 profit)
{
amountToRepay = amount;

uint256 quotaInterestAccrued = collateralDebtData.cumulativeQuotaInterest;
Expand All @@ -214,14 +212,14 @@ library CreditLogic {
collateralDebtData.cumulativeQuotaInterest = quotaInterestAccrued - amountToPool + 1; // F: [CMQ-4]

newDebt = collateralDebtData.debt;
newCumulativeIndex = cumulativeIndexLastUpdate;
newCumulativeIndex = collateralDebtData.cumulativeIndexLastUpdate;
}
}

if (amountToRepay > 0) {
// Computes the interest accrued thus far
uint256 interestAccrued =
(collateralDebtData.debt * newCumulativeIndex) / cumulativeIndexLastUpdate - collateralDebtData.debt; // F:[CM-21]
uint256 interestAccrued = (collateralDebtData.debt * newCumulativeIndex)
/ collateralDebtData.cumulativeIndexLastUpdate - collateralDebtData.debt; // F:[CM-21]

// Computes profit, taken as a percentage of the interest rate
uint256 profitFromInterest = (interestAccrued * feeInterest) / PERCENTAGE_FACTOR; // F:[CM-21]
Expand All @@ -238,7 +236,7 @@ library CreditLogic {
// Since interest is fully repaid, the Credit Account's cumulativeIndexLastUpdate
// is set to the current cumulative index - which means interest starts accruing
// on the new principal from zero
newCumulativeIndex = cumulativeIndexNow; // F:[CM-21]
newCumulativeIndex = collateralDebtData.cumulativeIndexNow; // F:[CM-21]
} else {
// If the amount is not enough to cover interest and fees,
// then the sum is split between dao fees and pool profits pro-rata. Since the fee is the percentage
Expand All @@ -263,10 +261,14 @@ library CreditLogic {
// debt * (cumulativeIndexNow / cumulativeIndexOpen - 1) - delta ==
// == debt * (cumulativeIndexNow / newCumulativeIndex - 1)

newCumulativeIndex = (INDEX_PRECISION * cumulativeIndexNow * cumulativeIndexLastUpdate)
newCumulativeIndex = (
INDEX_PRECISION * collateralDebtData.cumulativeIndexNow
* collateralDebtData.cumulativeIndexLastUpdate
)
/ (
INDEX_PRECISION * cumulativeIndexNow
- (INDEX_PRECISION * amountToPool * cumulativeIndexLastUpdate) / collateralDebtData.debt
INDEX_PRECISION * collateralDebtData.cumulativeIndexNow
- (INDEX_PRECISION * amountToPool * collateralDebtData.cumulativeIndexLastUpdate)
/ collateralDebtData.debt
);
}
}
Expand Down
24 changes: 12 additions & 12 deletions contracts/test/integration/credit/CreditManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1778,24 +1778,24 @@ contract CreditManagerTest is Test, ICreditManagerV3Events, BalanceHelper {
//

/// @dev [CM-50]: getCreditAccountParameters return correct values
function test_CM_50_getCreditAccountParameters_return_correct_values() public {
// It enables CreditManagerTestInternal for some test cases
_connectCreditManagerSuite(Tokens.DAI, true);
// function test_CM_50_getCreditAccountParameters_return_correct_values() public {
// // It enables CreditManagerTestInternal for some test cases
// _connectCreditManagerSuite(Tokens.DAI, true);

(,,, address creditAccount) = _openCreditAccount();
// (,,, address creditAccount) = _openCreditAccount();

(uint256 expectedDebt, uint256 expectedcumulativeIndexLastUpdate,,,,) =
creditManager.creditAccountInfo(creditAccount);
// (uint256 expectedDebt, uint256 expectedcumulativeIndexLastUpdate,,,,) =
// creditManager.creditAccountInfo(creditAccount);

CreditManagerTestInternal cmi = CreditManagerTestInternal(address(creditManager));
// CreditManagerTestInternal cmi = CreditManagerTestInternal(address(creditManager));

(uint256 borrowedAmount, uint256 cumulativeIndexLastUpdate,) = cmi.getCreditAccountParameters(creditAccount);
// (uint256 borrowedAmount, uint256 cumulativeIndexLastUpdate,) = cmi.getCreditAccountParameters(creditAccount);

assertEq(borrowedAmount, expectedDebt, "Incorrect borrowed amount");
assertEq(cumulativeIndexLastUpdate, expectedcumulativeIndexLastUpdate, "Incorrect cumulativeIndexLastUpdate");
// assertEq(borrowedAmount, expectedDebt, "Incorrect borrowed amount");
// assertEq(cumulativeIndexLastUpdate, expectedcumulativeIndexLastUpdate, "Incorrect cumulativeIndexLastUpdate");

assertEq(cumulativeIndexLastUpdate, expectedcumulativeIndexLastUpdate, "cumulativeIndexLastUpdate");
}
// assertEq(cumulativeIndexLastUpdate, expectedcumulativeIndexLastUpdate, "cumulativeIndexLastUpdate");
// }

//
// SET PARAMS
Expand Down
14 changes: 7 additions & 7 deletions contracts/test/mocks/credit/CreditManagerTestInternal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,13 @@ contract CreditManagerTestInternal is CreditManagerV3 {
// _disableToken(creditAccount, token);
// }

function getCreditAccountParameters(address creditAccount)
external
view
returns (uint256 borrowedAmount, uint256 cumulativeIndexLastUpdate, uint256 cumulativeIndexNow)
{
return _getCreditAccountParameters(creditAccount);
}
// function getCreditAccountParameters(address creditAccount)
// external
// view
// returns (uint256 borrowedAmount, uint256 cumulativeIndexLastUpdate, uint256 cumulativeIndexNow)
// {
// return _getCreditAccountParameters(creditAccount);
// }

function collateralTokensInternal() external view returns (address[] memory collateralTokensAddr) {
uint256 len = collateralTokensCount;
Expand Down
Loading

0 comments on commit aae10ff

Please sign in to comment.