Skip to content

Commit

Permalink
Merge pull request #77 from Gearbox-protocol/gas-n-storage-optimisation
Browse files Browse the repository at this point in the history
perf: gas-n-storage-optimisation
  • Loading branch information
0xmikko authored Jun 6, 2023
2 parents ed8a7ea + 61e704e commit 7b2aef1
Show file tree
Hide file tree
Showing 22 changed files with 840 additions and 185 deletions.
6 changes: 5 additions & 1 deletion contracts/core/AddressProviderV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ contract AddressProviderV3 is IAddressProviderV3 {
uint256 public constant override(IVersion) version = 3_00;

modifier configuratorOnly() {
_revertIfNotConfigurator();
_;
}

function _revertIfNotConfigurator() internal view {
if (!IACL(getAddressOrRevert(AP_ACL, NO_VERSION_CONTROL)).isConfigurator(msg.sender)) {
revert CallerNotConfiguratorException();
}
_;
}

constructor(address _acl) {
Expand Down
2 changes: 1 addition & 1 deletion contracts/core/BotListV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pragma solidity ^0.8.17;
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import {IWETH} from "@gearbox-protocol/core-v2/contracts/interfaces/external/IWETH.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/core/WithdrawalManagerV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
pragma solidity ^0.8.17;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

import {IVersion} from "@gearbox-protocol/core-v2/contracts/interfaces/IVersion.sol";
Expand Down
8 changes: 6 additions & 2 deletions contracts/credit/CreditAccountV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pragma solidity ^0.8.17;
pragma abicoder v1;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

import {ICreditAccountV3} from "../interfaces/ICreditAccountV3.sol";
Expand Down Expand Up @@ -36,10 +36,14 @@ contract CreditAccountV3 is ICreditAccountV3 {

/// @dev Ensures that function caller is credit manager
modifier creditManagerOnly() {
_revertIfNotCreditManager();
_;
}

function _revertIfNotCreditManager() internal view {
if (msg.sender != creditManager) {
revert CallerNotCreditManagerException();
}
_;
}

/// @notice Constructor
Expand Down
6 changes: 5 additions & 1 deletion contracts/credit/CreditConfiguratorV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,14 @@ contract CreditConfiguratorV3 is ICreditConfiguratorV3, ACLNonReentrantTrait {

/// @notice Sanity check to verify that the token is not the underlying
modifier nonUnderlyingTokenOnly(address token) {
if (token == underlying) revert TokenNotAllowedException();
_revertIfUnderlyingToken(token);
_;
}

function _revertIfUnderlyingToken(address token) internal view {
if (token == underlying) revert TokenNotAllowedException();
}

/// @notice Constructor has a special role in Credit Manager deployment
/// For newly deployed CMs, this is where the initial configuration is performed.
/// The correct deployment flow is as follows:
Expand Down
183 changes: 106 additions & 77 deletions contracts/credit/CreditFacadeV3.sol

Large diffs are not rendered by default.

19 changes: 9 additions & 10 deletions contracts/credit/CreditManagerV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pragma solidity ^0.8.17;
// LIBRARIES
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";

// LIBS & TRAITS
import {UNDERLYING_TOKEN_MASK, BitMask} from "../libraries/BitMask.sol";
Expand Down Expand Up @@ -58,7 +58,6 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuardT
using CreditLogic for CollateralDebtData;
using CollateralLogic for CollateralDebtData;
using SafeERC20 for IERC20;
using IERC20Helper for IERC20;
using CreditAccountHelper for ICreditAccountBase;

// IMMUTABLE PARAMS
Expand Down Expand Up @@ -237,7 +236,7 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuardT
function openCreditAccount(uint256 debt, address onBehalfOf)
external
override
nonZeroAddress(onBehalfOf) // todo: add check
nonZeroAddress(onBehalfOf)
nonReentrant // U:[CM-5]
creditFacadeOnly // // U:[CM-2]
returns (address creditAccount)
Expand Down Expand Up @@ -359,15 +358,15 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuardT
}); // U:[CM-8]
}
{
uint256 underlyingBalance = IERC20Helper.balanceOf({token: underlying, holder: creditAccount}); // U:[CM-8]
uint256 underlyingBalance = IERC20(underlying).safeBalanceOf({account: creditAccount}); // U:[CM-8]

// If there is an underlying shortfall, attempts to transfer it from the payer
if (underlyingBalance < amountToPool + remainingFunds + 1) {
unchecked {
IERC20(underlying).safeTransferFrom({
from: payer,
to: creditAccount,
value: _amountWithFee(amountToPool + remainingFunds + 1 - underlyingBalance)
amount: _amountWithFee(amountToPool + remainingFunds + 1 - underlyingBalance)
}); // U:[CM-8]
}
}
Expand Down Expand Up @@ -521,7 +520,7 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuardT
}

/// If the entire underlying balance was spent on repayment, it is disabled
if (IERC20Helper.balanceOf({token: underlying, holder: creditAccount}) <= 1) {
if (IERC20(underlying).safeBalanceOf({account: creditAccount}) <= 1) {
tokensToDisable = UNDERLYING_TOKEN_MASK; // U:[CM-11]
}
}
Expand All @@ -542,7 +541,7 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuardT
returns (uint256 tokenMask)
{
tokenMask = getTokenMaskOrRevert({token: token}); // U:[CM-13]
IERC20(token).safeTransferFrom({from: payer, to: creditAccount, value: amount}); // U:[CM-13]
IERC20(token).safeTransferFrom({from: payer, to: creditAccount, amount: amount}); // U:[CM-13]
}

///
Expand Down Expand Up @@ -1059,7 +1058,7 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuardT
_enableFlag({creditAccount: creditAccount, flag: WITHDRAWAL_FLAG});
}

if (IERC20Helper.balanceOf({token: token, holder: creditAccount}) <= 1) {
if (IERC20(token).safeBalanceOf({account: creditAccount}) <= 1) {
tokensToDisable = tokenMask; // U:[CM-27]
}
}
Expand Down Expand Up @@ -1135,7 +1134,7 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuardT
// enabledTokensMask & tokenMask == tokenMask when the token is enabled, and 0 otherwise
if (tokensToTransferMask & tokenMask != 0) {
address token = getTokenByMask(tokenMask); // U:[CM-31]
uint256 amount = IERC20Helper.balanceOf({token: token, holder: creditAccount}); // U:[CM-31]
uint256 amount = IERC20(token).safeBalanceOf({account: creditAccount}); // U:[CM-31]
if (amount > 1) {
// 1 is subtracted from amount to leave a non-zero value in the balance mapping, optimizing future writes
// Since the amount is checked to be more than 1, the block can be marked as unchecked
Expand Down Expand Up @@ -1476,7 +1475,7 @@ contract CreditManagerV3 is ICreditManagerV3, SanityCheckTrait, ReentrancyGuardT
/// which gives users/bots time to react and adjust their position for the new LT
/// @dev A static LT can be forced by setting ltInitial to desired LT and setting timestampRampStart to unit40.max
/// @param token The collateral token to set the LT for
/// todo: add ltInitial
/// @param ltInitial The initial LT before ramping
/// @param ltFinal The final LT after ramping
/// @param timestampRampStart Timestamp when the LT starts ramping
/// @param rampDuration Duration of ramping
Expand Down
8 changes: 7 additions & 1 deletion contracts/governance/ControllerTimelockV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,18 @@ contract ControllerTimelockV3 is PolicyManagerV3, IControllerTimelockV3 {
vetoAdmin = _vetoAdmin;
}


/// @dev Allows access to function only to veto admin
modifier vetoAdminOnly() {
_revertIfCallerIsNotVetoAdmin();
_;
}


function _revertIfCallerIsNotVetoAdmin() internal view {
if (msg.sender != vetoAdmin) {
revert CallerNotVetoAdminException();
}
_;
}

/// @notice Queues a transaction to set a new expiration date in the Credit Facade
Expand Down
2 changes: 1 addition & 1 deletion contracts/governance/GearStakingV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// (c) Gearbox Holdings, 2022
pragma solidity ^0.8.17;

import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";

Expand Down
27 changes: 16 additions & 11 deletions contracts/interfaces/ICreditFacadeV3Multicall.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import {Balance} from "@gearbox-protocol/core-v2/contracts/libraries/Balances.so
import {RevocationPair} from "./ICreditManagerV3.sol";

uint192 constant ADD_COLLATERAL_PERMISSION = 1;
uint192 constant INCREASE_DEBT_PERMISSION = 2 ** 1;
uint192 constant DECREASE_DEBT_PERMISSION = 2 ** 2;
uint192 constant ENABLE_TOKEN_PERMISSION = 2 ** 3;
uint192 constant DISABLE_TOKEN_PERMISSION = 2 ** 4;
uint192 constant WITHDRAW_PERMISSION = 2 ** 5;
uint192 constant UPDATE_QUOTA_PERMISSION = 2 ** 6;
uint192 constant REVOKE_ALLOWANCES_PERMISSION = 2 ** 7;
uint192 constant INCREASE_DEBT_PERMISSION = 1 << 1;
uint192 constant DECREASE_DEBT_PERMISSION = 1 << 2;
uint192 constant ENABLE_TOKEN_PERMISSION = 1 << 3;
uint192 constant DISABLE_TOKEN_PERMISSION = 1 << 4;
uint192 constant WITHDRAW_PERMISSION = 1 << 5;
uint192 constant UPDATE_QUOTA_PERMISSION = 1 << 6;
uint192 constant REVOKE_ALLOWANCES_PERMISSION = 1 << 7;

uint192 constant EXTERNAL_CALLS_PERMISSION = 2 ** 16;
uint192 constant EXTERNAL_CALLS_PERMISSION = 1 << 16;

uint256 constant ALL_CREDIT_FACADE_CALLS_PERMISSION = ADD_COLLATERAL_PERMISSION | INCREASE_DEBT_PERMISSION
| DECREASE_DEBT_PERMISSION | ENABLE_TOKEN_PERMISSION | DISABLE_TOKEN_PERMISSION | WITHDRAW_PERMISSION
Expand All @@ -24,11 +24,16 @@ uint256 constant ALL_CREDIT_FACADE_CALLS_PERMISSION = ADD_COLLATERAL_PERMISSION
uint256 constant ALL_PERMISSIONS = ALL_CREDIT_FACADE_CALLS_PERMISSION | EXTERNAL_CALLS_PERMISSION;

// All flags start from 193rd bit, because bot permissions is uint192
uint256 constant INCREASE_DEBT_WAS_CALLED = 2 ** 193;
uint256 constant EXTERNAL_CONTRACT_WAS_CALLED = 2 ** 194;
uint256 constant INCREASE_DEBT_WAS_CALLED = 1 << 193;
uint256 constant EXTERNAL_CONTRACT_WAS_CALLED = 1 << 194;
uint256 constant PRICE_UPDATES_ALREADY_APPLIED = 1 << 195;

// pay bot is a flag which is enabled in botMulticall function only to allow one payment operation
uint256 constant PAY_BOT_CAN_BE_CALLED = 2 ** 195;
uint256 constant PAY_BOT_CAN_BE_CALLED = 1 << 196;

interface IUpdatablePriceFeed {
function updatePrice(bytes calldata data) external;
}

interface ICreditFacadeV3Multicall {
/// @dev Instructs CreditFacadeV3 to check token balances at the end
Expand Down
22 changes: 0 additions & 22 deletions contracts/interfaces/IPriceFeedOnDemand.sol

This file was deleted.

13 changes: 8 additions & 5 deletions contracts/libraries/BalancesLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
// (c) Gearbox Holdings, 2023
pragma solidity ^0.8.17;

import {IERC20Helper} from "./IERC20Helper.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";

import {BitMask} from "./BitMask.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {RAY} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol";
Expand All @@ -19,6 +21,7 @@ struct BalanceWithMask {
/// @notice Implements functions that used for before-and-after balance comparisons
library BalancesLogic {
using BitMask for uint256;
using SafeERC20 for IERC20;

/// @dev Returns an array of balances that are expected after operations
/// @param creditAccount Credit Account to compute new balances for
Expand All @@ -31,7 +34,7 @@ library BalancesLogic {
expected = deltas; // U:[BLL-1]
uint256 len = deltas.length;
for (uint256 i = 0; i < len;) {
expected[i].balance += IERC20Helper.balanceOf(expected[i].token, creditAccount); // U:[BLL-1]
expected[i].balance += IERC20(expected[i].token).safeBalanceOf({account: creditAccount}); // U:[BLL-1]
unchecked {
++i;
}
Expand All @@ -46,7 +49,7 @@ library BalancesLogic {
uint256 len = expected.length;
unchecked {
for (uint256 i = 0; i < len; ++i) {
if (IERC20Helper.balanceOf(expected[i].token, creditAccount) < expected[i].balance) {
if (IERC20(expected[i].token).safeBalanceOf({account: creditAccount}) < expected[i].balance) {
return false; // U:[BLL-2]
}
}
Expand Down Expand Up @@ -76,7 +79,7 @@ library BalancesLogic {
address token = getTokenByMaskFn(tokenMask);
forbiddenBalances[i].token = token; // U:[BLL-3]
forbiddenBalances[i].tokenMask = tokenMask; // U:[BLL-3]
forbiddenBalances[i].balance = IERC20Helper.balanceOf(token, creditAccount); // U:[BLL-3]
forbiddenBalances[i].balance = IERC20(token).safeBalanceOf({account: creditAccount}); // U:[BLL-3]
++i;
}
}
Expand Down Expand Up @@ -111,7 +114,7 @@ library BalancesLogic {
uint256 len = forbiddenBalances.length;
for (uint256 i = 0; i < len; ++i) {
if (forbiddenTokensOnAccount & forbiddenBalances[i].tokenMask != 0) {
uint256 currentBalance = IERC20Helper.balanceOf(forbiddenBalances[i].token, creditAccount);
uint256 currentBalance = IERC20(forbiddenBalances[i].token).safeBalanceOf({account: creditAccount});
if (currentBalance > forbiddenBalances[i].balance) {
return false; // U:[BLL-4]
}
Expand Down
7 changes: 5 additions & 2 deletions contracts/libraries/CollateralLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
// (c) Gearbox Holdings, 2022
pragma solidity ^0.8.17;

import {IERC20Helper} from "./IERC20Helper.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";

import {CollateralDebtData} from "../interfaces/ICreditManagerV3.sol";
import {PERCENTAGE_FACTOR, RAY} from "@gearbox-protocol/core-v2/contracts/libraries/Constants.sol";

Expand All @@ -15,6 +17,7 @@ import "forge-std/console.sol";
/// @dev Implements functions that compute value of collateral on a Credit Account
library CollateralLogic {
using BitMask for uint256;
using SafeERC20 for IERC20;

/// @dev Computes USD-denominated total value and TWV of a Credit Account
/// @param collateralDebtData A struct containing data on the Credit Account's debt and quoted tokens
Expand Down Expand Up @@ -283,7 +286,7 @@ library CollateralLogic {
uint16 liquidationThreshold,
uint256 quotaUSD
) internal view returns (uint256 valueUSD, uint256 weightedValueUSD, bool nonZeroBalance) {
uint256 balance = IERC20Helper.balanceOf(token, creditAccount); // U:[CLL-1]
uint256 balance = IERC20(token).safeBalanceOf({account: creditAccount}); // U:[CLL-1]

/// Collateral computations are skipped if the balance is 0
/// and nonZeroBalance will be equal to false
Expand Down
8 changes: 4 additions & 4 deletions contracts/libraries/CreditAccountHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
pragma solidity ^0.8.17;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Helper} from "./IERC20Helper.sol";
import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";

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

/// @title CreditAccount Helper library
/// @dev Implements functions that help manage assets on a Credit Account
library CreditAccountHelper {
using IERC20Helper for IERC20;
using SafeERC20 for IERC20;

/// @dev Requests a Credit Account to do an approval with support for various kinds of tokens
/// @dev Supports up-to-spec ERC20 tokens, ERC20 tokens that revert on transfer failure,
Expand Down Expand Up @@ -88,8 +88,8 @@ library CreditAccountHelper {
address to,
uint256 amount
) internal returns (uint256 delivered) {
uint256 balanceBefore = IERC20Helper.balanceOf(token, to);
uint256 balanceBefore = IERC20(token).safeBalanceOf({account: to});
transfer(creditAccount, token, to, amount);
delivered = IERC20Helper.balanceOf(token, to) - balanceBefore;
delivered = IERC20(token).safeBalanceOf({account: to}) - balanceBefore;
}
}
8 changes: 1 addition & 7 deletions contracts/libraries/IERC20Helper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,10 @@
pragma solidity ^0.8.17;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
// import {SafeTransferFailedException, SafeTransferFromFailedException} from "../interfaces/IExceptions.sol";

/// @title ERC20 helper library
library IERC20Helper {
/// @dev Returns `holder`'s balance of `token`
/// Can be used to reduce the size of a contract that makes multiple external
/// `balanceOf` calls by making them internal (yes, it really works)
function balanceOf(address token, address holder) internal view returns (uint256) {
return IERC20(token).balanceOf(holder);
}

/// @dev Same as OpenZeppelin's `safeTransfer`, but, instead of reverting, returns `false` when transfer fails
function unsafeTransfer(IERC20 token, address to, uint256 amount) internal returns (bool success) {
return _unsafeCall(address(token), abi.encodeCall(IERC20.transfer, (to, amount))); // U:[EH-1]
Expand Down
Loading

0 comments on commit 7b2aef1

Please sign in to comment.