Skip to content

Commit

Permalink
fix: calc withdrawal value
Browse files Browse the repository at this point in the history
  • Loading branch information
0xmikko committed Apr 28, 2023
1 parent 225c9b9 commit 3786f69
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 76 deletions.
1 change: 1 addition & 0 deletions contracts/credit/CreditFacadeV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ contract CreditFacadeV3 is ICreditFacade, ACLNonReentrantTrait, BalanceHelperTra
uint256 enabledTokensMask,
uint256 flags
) internal returns (FullCheckParams memory fullCheckParams) {
uint256 limitedTokenMask;
// Emits event for multicall start - used in analytics to track actions within multicalls
emit StartMultiCall(borrower); // F:[FA-26]

Expand Down
29 changes: 20 additions & 9 deletions contracts/credit/CreditManagerV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,13 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuard,
_calcAllCollateral(_priceOracle, creditAccount, enabledTokenMask, PERCENTAGE_FACTOR, collateralHints, false);

// add withdrawal balances to TotalValue
if (hasWithdrawalValue(creditAccount)) {
(uint256 withdrawValueUSD, uint256 tokensToEnable) =
_calcDelayedWithdrawalValue(_priceOracle, creditAccount);

totalUSD += withdrawValueUSD;
enabledTokenMask |= tokensToEnable;
}

total = _convertFromUSD(_priceOracle, totalUSD, underlying); // F:[FA-41]
hf = twvUSD * PERCENTAGE_FACTOR / borrowAmountPlusInterestRateAndFeesUSD;
Expand Down Expand Up @@ -899,29 +906,29 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuard,
function _calcDelayedWithdrawalValue(IPriceOracleV2 _priceOracle, address creditAccount)
internal
view
returns (uint256 amount, uint256 enabledTokenMask)
returns (uint256 withdrawValueUSD, uint256 tokensToEnable)
{
(uint256 tokenMask1, uint256 balance1, uint256 tokenMask2, uint256 balance2) =
withdrawManager.getWithdrawals(address(this), creditAccount);

(amount, enabledTokenMask) = _calcWithdrawalValueUSD(0, 0, _priceOracle, tokenMask1, balance1);
(amount, enabledTokenMask) =
_calcWithdrawalValueUSD(amount, enabledTokenMask, _priceOracle, tokenMask2, balance2);
(withdrawValueUSD, tokensToEnable) = _calcWithdrawalValueUSD(0, 0, _priceOracle, tokenMask1, balance1);
(withdrawValueUSD, tokensToEnable) =
_calcWithdrawalValueUSD(withdrawValueUSD, tokensToEnable, _priceOracle, tokenMask2, balance2);
}

function _calcWithdrawalValueUSD(
uint256 _amount,
uint256 _withdrawValueUSD,
uint256 _tokensToEnbable,
IPriceOracleV2 _priceOracle,
uint256 tokenMask,
uint256 balance
) internal view returns (uint256 amount, uint256 tokensToEnable) {
amount = _amount;
) internal view returns (uint256 withdrawValueUSD, uint256 tokensToEnable) {
withdrawValueUSD = _withdrawValueUSD;
tokensToEnable = _tokensToEnbable;

if (balance > 1) {
address token = getTokenByMask(tokenMask);
amount += _convertToUSD(_priceOracle, balance, token);
withdrawValueUSD += _convertToUSD(_priceOracle, balance, token);
tokensToEnable |= tokenMask;
}
}
Expand Down Expand Up @@ -1603,7 +1610,7 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuard,
creditFacadeOnly
returns (uint256 tokensToEnable)
{
if (creditAccountInfo[creditAccount].flags & WITHDRAWAL_FLAG != 0) {
if (hasWithdrawalValue(creditAccount)) {
return withdrawManager.cancelWithdrawals(creditAccount, ctype);
}
}
Expand Down Expand Up @@ -1653,6 +1660,10 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuard,
creditAccountInfo[creditAccount].enabledTokensMask = uint248(enabledTokenMask);
}

function hasWithdrawalValue(address creditAccount) internal view returns (bool) {
return creditAccountInfo[creditAccount].flags & WITHDRAWAL_FLAG != 0;
}

function _enableWithdrawalFlag(address creditAccount) internal {
creditAccountInfo[creditAccount].flags |= WITHDRAWAL_FLAG;
}
Expand Down
74 changes: 7 additions & 67 deletions contracts/test/unit/credit/CreditManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ERC20Mock} from "@gearbox-protocol/core-v2/contracts/test/mocks/token/ERC20Mock.sol";
import {PERCENTAGE_FACTOR} from "@gearbox-protocol/core-v2/contracts/libraries/PercentageMath.sol";

// LIBS & TRAITS
import {BitMask} from "../../../libraries/BitMask.sol";
// TESTS

import "../../lib/constants.sol";

import {BalanceHelper} from "../../helpers/BalanceHelper.sol";

// EXCEPTIONS
Expand Down Expand Up @@ -63,6 +64,8 @@ import "forge-std/console.sol";
/// @title AddressRepository
/// @notice Stores addresses of deployed contracts
contract CreditManagerTest is DSTest, ICreditManagerV3Events, BalanceHelper {
using BitMask for uint256;

CheatCodes evm = CheatCodes(HEVM_ADDRESS);

CreditManagerTestSuite cms;
Expand Down Expand Up @@ -232,70 +235,6 @@ contract CreditManagerTest is DSTest, ICreditManagerV3Events, BalanceHelper {
_addAndEnableTokens(creditAccount, maxAllowedEnabledTokenLength, 2);
}

// function prepareForEnabledTokenOptimization(
// address creditAccount,
// bool[] memory tokenTypes,
// uint256 enabledTokensNum,
// uint256 zeroTokensNum,
// uint256 breakPoint
// ) internal returns (uint256) {
// if (enabledTokensNum == 0) {
// return 1;
// }

// bool setBreakpoint;

// if (enabledTokensNum != zeroTokensNum) {
// // When there are more enabled tokens than zero tokens, we have a breakpoint other than underlying

// uint256 daiBalance = tokenTestSuite.balanceOf(Tokens.DAI, creditAccount);
// tokenTestSuite.burn(Tokens.DAI, creditAccount, daiBalance);
// setBreakpoint = true;
// } else {
// // When there is the same number of enabled and zero tokens, only the underlying will be checked in fullCheck,
// // hence all tokens + underlying will remain enabled before optimizer is run

// enabledTokensNum += 1;
// }

// for (uint256 i = 0; i < tokenTypes.length; i++) {
// if ((i == breakPoint) && setBreakpoint) {
// _addAndEnableTokens(creditAccount, 1, RAY);
// } else if (tokenTypes[i]) {
// _addAndEnableTokens(creditAccount, 1, 2);
// } else {
// _addAndEnableTokens(creditAccount, 1, 1);
// if ((i > breakPoint) && setBreakpoint) {
// enabledTokensNum--;
// }
// }
// }

// return enabledTokensNum;
// }

function calcEnabledTokens(address creditAccount) internal view returns (uint256) {
uint256 enabledMask = creditManager.enabledTokensMap(creditAccount);

uint256 tokensEnabled;

uint256 tokenMask;
unchecked {
for (uint256 i; i < 256; ++i) {
tokenMask = 1 << i;
if (enabledMask & tokenMask != 0) {
++tokensEnabled;
}

if (tokenMask >= enabledMask) {
break;
}
}
}

return tokensEnabled;
}

function _openAccountAndTransferToCF() internal returns (address creditAccount) {
(,,, creditAccount) = _openCreditAccount();
creditManager.transferAccountOwnership(USER, address(this));
Expand Down Expand Up @@ -1514,11 +1453,12 @@ contract CreditManagerTest is DSTest, ICreditManagerV3Events, BalanceHelper {
hints[i] = 2 ** (totalTokens - i - 1);
}
}
// _baseFullCollateralCheck(creditAccount);

creditManager.fullCollateralCheck(creditAccount, 2 ** (totalTokens) - 1, hints, 10000);

assertEq(calcEnabledTokens(creditAccount), 1, "Incorrect number of tokens enabled");
assertEq(
creditManager.enabledTokensMap(creditAccount).calcEnabledTokens(), 1, "Incorrect number of tokens enabled"
);
}

/// @dev [CM-42]: fullCollateralCheck fuzzing test
Expand Down

0 comments on commit 3786f69

Please sign in to comment.