Skip to content

Commit

Permalink
Merge pull request #14 from Gearbox-protocol/poolQuotaKeeper-improvem…
Browse files Browse the repository at this point in the history
…ents

fix: exceptions optimitsation
  • Loading branch information
0xmikko authored Apr 2, 2023
2 parents 27fdfec + b1ce73f commit b1aeef7
Show file tree
Hide file tree
Showing 20 changed files with 158 additions and 659 deletions.
4 changes: 2 additions & 2 deletions contracts/credit/CreditConfigurator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ contract CreditConfigurator is ICreditConfigurator, ACLNonReentrantTrait {
if (
targetContract == address(creditManager) || targetContract == address(creditFacade())
|| adapter == address(creditManager) || adapter == address(creditFacade())
) revert CreditManagerOrFacadeUsedAsTargetContractsException(); // F:[CC-13]
) revert TargetContractNotAllowedException(); // F:[CC-13]

// Checks that adapter is not used for another target
if (creditManager.adapterToContract(adapter) != address(0)) {
Expand Down Expand Up @@ -480,7 +480,7 @@ contract CreditConfigurator is ICreditConfigurator, ACLNonReentrantTrait {
if (
_feeInterest >= PERCENTAGE_FACTOR || (_liquidationPremium + _feeLiquidation) >= PERCENTAGE_FACTOR
|| (_liquidationPremiumExpired + _feeLiquidationExpired) >= PERCENTAGE_FACTOR
) revert IncorrectFeesException(); // FT:[CC-23]
) revert IncorrectParameterException(); // FT:[CC-23]

_setParams(
_feeInterest,
Expand Down
178 changes: 76 additions & 102 deletions contracts/credit/CreditFacade.sol
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ contract CreditFacade is ICreditFacade, ACLNonReentrantTrait {
/// @dev Keeps parameters that are used to pause the system after too much bad debt over a short period
CumulativeLossParams public override lossParams;

/// @dev Address of the pool
address public immutable pool;

/// @dev Address of the underlying token
address public immutable underlying;

Expand Down Expand Up @@ -138,6 +141,7 @@ contract CreditFacade is ICreditFacade, ACLNonReentrantTrait {
nonZeroAddress(_creditManager)
{
creditManager = ICreditManagerV2(_creditManager); // F:[FA-1A]
pool = creditManager.pool();
underlying = ICreditManagerV2(_creditManager).underlying(); // F:[FA-1A]
wethAddress = ICreditManagerV2(_creditManager).wethAddress(); // F:[FA-1A]
wethGateway = IWETHGateway(ICreditManagerV2(_creditManager).wethGateway());
Expand Down Expand Up @@ -215,7 +219,7 @@ contract CreditFacade is ICreditFacade, ACLNonReentrantTrait {
emit OpenCreditAccount(onBehalfOf, creditAccount, borrowedAmount, referralCode); // F:[FA-5]

// Transfers collateral from the user to the new Credit Account
addCollateral(onBehalfOf, creditAccount, underlying, amount); // F:[FA-5]
_addCollateral(onBehalfOf, creditAccount, underlying, amount); // F:[FA-5]
}

/// @dev Opens a Credit Account and runs a batch of operations in a multicall
Expand Down Expand Up @@ -609,22 +613,22 @@ contract CreditFacade is ICreditFacade, ACLNonReentrantTrait {
// Checks that onBehalfOf has an account
address creditAccount = _getCreditAccountOrRevert(onBehalfOf); // F:[FA-2]

addCollateral(onBehalfOf, creditAccount, token, amount);

// Since this action can enable new tokens, Credit Manager
// needs to check that the max enabled token limit is not
// breached
creditManager.checkEnabledTokensLength(creditAccount); // F: [FA-21C]
}

function addCollateral(address onBehalfOf, address creditAccount, address token, uint256 amount) internal {
// Checks that msg.sender can transfer funds to onBehalfOf's account
// This is done to prevent malicious actors sending bad collateral
// to users
// mgs.sender can only add collateral if transfer are approved
// from itself to onBehalfOf
_revertIfActionOnAccountNotAllowed(onBehalfOf); // F: [FA-21A]

_addCollateral(onBehalfOf, creditAccount, token, amount);

// Since this action can enable new tokens, Credit Manager
// needs to check that the max enabled token limit is not
// breached
creditManager.checkEnabledTokensLength(creditAccount); // F: [FA-21C]
}

function _addCollateral(address onBehalfOf, address creditAccount, address token, uint256 amount) internal {
// Requests Credit Manager to transfer collateral to the Credit Account
creditManager.addCollateral(msg.sender, creditAccount, token, amount); // F:[FA-21]

Expand Down Expand Up @@ -722,50 +726,54 @@ contract CreditFacade is ICreditFacade, ACLNonReentrantTrait {
fullCheckParams.minHealthFactor = PERCENTAGE_FACTOR;

uint256 len = calls.length; // F:[FA-26]
for (uint256 i = 0; i < len;) {
MultiCall calldata mcall = calls[i]; // F:[FA-26]

// Reverts of calldata has less than 4 bytes
if (mcall.callData.length < 4) revert IncorrectCallDataException(); // F:[FA-22]

if (mcall.target == address(this)) {
// No internal calls on closure except slippage control, to avoid loss manipulation
if (isClosure) {
bytes4 method = bytes4(mcall.callData);
if (method != ICreditFacadeExtended.revertIfReceivedLessThan.selector) {
revert ForbiddenDuringClosureException();
} // F:[FA-13]
}

//
// CREDIT FACADE
//

// increaseDebtWasCalled and expectedBalances are parameters that persist throughout multicall,
// therefore they are passed to the internal function processor, which returns updated values
(increaseDebtWasCalled, expectedBalances, fullCheckParams) = _processCreditFacadeMulticall(
borrower, creditAccount, mcall.callData, increaseDebtWasCalled, expectedBalances, fullCheckParams
);
} else {
//
// ADAPTERS
//

// Checks that the target is an allowed adapter and not CreditManager
// As CreditFacade has powerful permissions in CreditManagers,
// functionCall to it is strictly forbidden, even if
// the Configurator adds it as an adapter
if (
creditManager.adapterToContract(mcall.target) == address(0)
|| mcall.target == address(creditManager)
) revert TargetContractNotAllowedException(); // F:[FA-24]

// Makes a call
mcall.target.functionCall(mcall.callData); // F:[FA-29]
}
unchecked {
for (uint256 i = 0; i < len; ++i) {
MultiCall calldata mcall = calls[i]; // F:[FA-26]

// Reverts of calldata has less than 4 bytes
if (mcall.callData.length < 4) revert IncorrectCallDataException(); // F:[FA-22]

if (mcall.target == address(this)) {
// No internal calls on closure except slippage control, to avoid loss manipulation
if (isClosure) {
bytes4 method = bytes4(mcall.callData);
if (method != ICreditFacadeExtended.revertIfReceivedLessThan.selector) {
revert ForbiddenDuringClosureException();
} // F:[FA-13]
}

unchecked {
++i;
//
// CREDIT FACADE
//

// increaseDebtWasCalled and expectedBalances are parameters that persist throughout multicall,
// therefore they are passed to the internal function processor, which returns updated values
(increaseDebtWasCalled, expectedBalances, fullCheckParams) = _processCreditFacadeMulticall(
borrower,
creditAccount,
mcall.callData,
increaseDebtWasCalled,
expectedBalances,
fullCheckParams
);
} else {
//
// ADAPTERS
//

// Checks that the target is an allowed adapter and not CreditManager
// As CreditFacade has powerful permissions in CreditManagers,
// functionCall to it is strictly forbidden, even if
// the Configurator adds it as an adapter
if (
creditManager.adapterToContract(mcall.target) == address(0)
|| mcall.target == address(creditManager)
) revert TargetContractNotAllowedException(); // F:[FA-24]

// Makes a call
mcall.target.functionCall(mcall.callData); // F:[FA-29]
}
}
}

Expand Down Expand Up @@ -825,26 +833,16 @@ contract CreditFacade is ICreditFacade, ACLNonReentrantTrait {
// SET FULL CHECK PARAMS
//
} else if (method == ICreditFacadeExtended.setFullCheckParams.selector) {
(uint256[] memory collateralHints, uint16 minHealthFactor) = abi.decode(callData[4:], (uint256[], uint16));

fullCheckParams.collateralHints = collateralHints;
fullCheckParams.minHealthFactor = minHealthFactor;
(fullCheckParams.collateralHints, fullCheckParams.minHealthFactor) =
abi.decode(callData[4:], (uint256[], uint16));
}
//
// ADD COLLATERAL
//
else if (method == ICreditFacade.addCollateral.selector) {
else if (method == ICreditFacadeExtended.addCollateral.selector) {
// Parses parameters from calldata
(address onBehalfOf, address token, uint256 amount) = abi.decode(callData[4:], (address, address, uint256)); // F:[FA-26, 27]

// In case onBehalfOf isn't the owner of the currently processed account,
// retrieves onBehalfOf's account
addCollateral(
onBehalfOf,
onBehalfOf == borrower ? creditAccount : _getCreditAccountOrRevert(onBehalfOf),
token,
amount
); // F:[FA-26, 27]
(address token, uint256 amount) = abi.decode(callData[4:], (address, uint256)); // F:[FA-26, 27]
_addCollateral(borrower, creditAccount, token, amount); // F:[FA-26, 27]
}
//
// INCREASE DEBT
Expand Down Expand Up @@ -880,7 +878,7 @@ contract CreditFacade is ICreditFacade, ACLNonReentrantTrait {
address token = abi.decode(callData[4:], (address)); // F: [FA-53]

// Executes enableToken for creditAccount
_enableToken(borrower, token); // F: [FA-53]
creditManager.checkAndEnableToken(token); // F: [FA-53]
}
//
// DISABLE TOKEN
Expand All @@ -892,7 +890,7 @@ contract CreditFacade is ICreditFacade, ACLNonReentrantTrait {
address token = abi.decode(callData[4:], (address)); // F: [FA-54]

// Executes disableToken for creditAccount
_disableToken(borrower, token); // F: [FA-54]
creditManager.disableToken(token); // F: [FA-54]
}
//
// UPDATE QUOTAS
Expand All @@ -918,6 +916,7 @@ contract CreditFacade is ICreditFacade, ACLNonReentrantTrait {
returns (Balance[] memory)
{
uint256 len = expected.length; // F:[FA-45]

for (uint256 i = 0; i < len;) {
expected[i].balance += IERC20(expected[i].token).balanceOf(creditAccount); // F:[FA-45]
unchecked {
Expand All @@ -934,12 +933,11 @@ contract CreditFacade is ICreditFacade, ACLNonReentrantTrait {
/// @param creditAccount Credit Account to check
function _compareBalances(Balance[] memory expected, address creditAccount) internal view {
uint256 len = expected.length; // F:[FA-45]
for (uint256 i = 0; i < len;) {
if (IERC20(expected[i].token).balanceOf(creditAccount) < expected[i].balance) {
revert BalanceLessThanMinimumDesiredException(expected[i].token);
} // F:[FA-45]
unchecked {
++i;
unchecked {
for (uint256 i = 0; i < len; ++i) {
if (IERC20(expected[i].token).balanceOf(creditAccount) < expected[i].balance) {
revert BalanceLessThanMinimumDesiredException(expected[i].token);
} // F:[FA-45]
}
}
}
Expand All @@ -952,7 +950,7 @@ contract CreditFacade is ICreditFacade, ACLNonReentrantTrait {
function transferAccountOwnership(address to) external override nonReentrant {
// In whitelisted mode only select addresses can have Credit Accounts
// So this action is prohibited
if (whitelisted) revert NotAllowedInWhitelistedMode(); // F:[FA-32]
if (whitelisted) revert AccountTransferNotAllowedException(); // F:[FA-32]

address creditAccount = _getCreditAccountOrRevert(msg.sender); // F:[FA-2]

Expand Down Expand Up @@ -1004,7 +1002,7 @@ contract CreditFacade is ICreditFacade, ACLNonReentrantTrait {
// In whitelisted mode, users can only open an account by burning a DegenNFT
// And opening an account for another address is forbidden
if (whitelisted && msg.sender != onBehalfOf) {
revert NotAllowedInWhitelistedMode();
revert AccountTransferNotAllowedException();
} // F:[FA-4B]

IDegenNFT(degenNFT).burn(onBehalfOf, 1); // F:[FA-4B]
Expand Down Expand Up @@ -1085,30 +1083,6 @@ contract CreditFacade is ICreditFacade, ACLNonReentrantTrait {
emit TransferAccountAllowed(from, msg.sender, state); // F:[FA-38]
}

/// @dev Enables token in enabledTokenMask for a Credit Account
/// @param borrower Owner of the account
/// @param token Collateral token to enable
function _enableToken(address borrower, address token) internal {
// Will revert if the token is not known or forbidden,
// If the token is disabled, adds the respective bit to the mask, otherwise does nothing
creditManager.checkAndEnableToken(token); // F:[FA-39]

// Emits event
emit TokenEnabled(borrower, token);
}

/// @dev Disable a token for a Credit Account
/// @param borrower Owner of the account
/// @param token Token to disable
function _disableToken(address borrower, address token) internal {
// If the token is enabled, removes a respective bit from the mask,
// otherwise does nothing
if (creditManager.disableToken(token)) {
// Emits event
emit TokenDisabled(borrower, token);
} // F: [FA-54]
}

//
// HELPERS
//
Expand All @@ -1135,7 +1109,7 @@ contract CreditFacade is ICreditFacade, ACLNonReentrantTrait {

/// @dev Returns the current available liquidity of the pool
function _getAvailableLiquidity() internal view returns (uint256) {
return IPool4626(creditManager.pool()).availableLiquidity();
return IERC20(underlying).balanceOf(pool);
}

/// @dev Pauses the Credit Manager
Expand Down
10 changes: 5 additions & 5 deletions contracts/credit/CreditManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ contract CreditManager is ICreditManagerV2, ACLNonReentrantTrait {
/// @dev Restricts calls to Credit Facade or allowed adapters
modifier adaptersOrCreditFacadeOnly() {
if (adapterToContract[msg.sender] == address(0) && msg.sender != creditFacade) {
revert AdaptersOrCreditFacadeOnlyException();
revert CallerNotAdaptersOrCreditFacadeException();
} //
_;
}
Expand Down Expand Up @@ -640,7 +640,7 @@ contract CreditManager is ICreditManagerV2, ACLNonReentrantTrait {
&& msg.sender != universalAdapter
) || targetContract == address(0)
) {
revert AdaptersOrCreditFacadeOnlyException(); // F:[CM-3,25]
revert CallerNotAdaptersOrCreditFacadeException(); // F:[CM-3,25]
}

// Checks that the token is a collateral token
Expand Down Expand Up @@ -1483,9 +1483,9 @@ contract CreditManager is ICreditManagerV2, ACLNonReentrantTrait {
} // F:[CM-52]

// Checks that there aren't too many tokens
// Since token masks are 256 bit numbers with each bit corresponding to 1 token,
// only at most 256 are supported
if (collateralTokensCount >= 256) revert TooManyTokensException(); // F:[CM-52]
// Since token masks are 255 bit numbers with each bit corresponding to 1 token,
// only at most 255 are supported
if (collateralTokensCount >= 255) revert TooManyTokensException(); // F:[CM-52]

// The tokenMask of a token is a bit mask with 1 at position corresponding to its index
// (i.e. 2 ** index or 1 << index)
Expand Down
10 changes: 1 addition & 9 deletions contracts/interfaces/IBotList.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,6 @@ struct BotFunding {
uint40 allowanceLU;
}

interface IBotListExceptions {
/// @dev Thrown when attempting to pass a zero amount to a funding-related operation
error AmountCantBeZeroException();

/// @dev Thrown when attempting to fund a bot that is forbidden or not directly allowed by the user
error InvalidBotException();
}

interface IBotListEvents {
/// @dev Emits when a borrower enables or disables a bot for their account
event BotApprovalChanged(address indexed borrower, address indexed bot, bool status);
Expand All @@ -41,7 +33,7 @@ interface IBotListEvents {
}

/// @title IBotList
interface IBotList is IBotListEvents, IBotListExceptions, IVersion {
interface IBotList is IBotListEvents, IVersion {
/// @dev Sets approval from msg.sender to bot
function setBotStatus(address bot, bool status) external;

Expand Down
9 changes: 1 addition & 8 deletions contracts/interfaces/ICreditFacade.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@ interface ICreditFacadeExtended {
function disableToken(address token) external;

/// @dev Adds collateral to borrower's credit account
/// @param onBehalfOf Address of the borrower whose account is funded
/// @param token Address of a collateral token
/// @param amount Amount to add
function addCollateral(address onBehalfOf, address token, uint256 amount) external payable;
function addCollateral(address token, uint256 amount) external payable;

/// @dev Increases debt for msg.sender's Credit Account
/// - Borrows the requested amount from the pool
Expand Down Expand Up @@ -114,12 +113,6 @@ interface ICreditFacadeEvents {

/// @dev Emits when the user changes approval for account transfers to itself from another address
event TransferAccountAllowed(address indexed from, address indexed to, bool state);

/// @dev Emits when the account owner enables a token on their CA
event TokenEnabled(address indexed borrower, address indexed token);

/// @dev Emits when the account owner disables a token on their CA
event TokenDisabled(address indexed borrower, address indexed token);
}

interface ICreditFacade is ICreditFacadeEvents, IVersion {
Expand Down
Loading

0 comments on commit b1aeef7

Please sign in to comment.