Badger eBTC Audit + Certora Formal Verification Competition - codeslide's results

Use stETH to borrow Bitcoin with 0% fees | The only smart contract based #BTC.

General Information

Platform: Code4rena

Start Date: 24/10/2023

Pot Size: $149,725 USDC

Total HM: 7

Participants: 52

Period: 21 days

Judge: ronnyx2017

Total Solo HM: 2

Id: 300

League: ETH

eBTC Protocol

Findings Distribution

Researcher Performance

Rank: 19/52

Findings: 1

Award: $162.76

Gas:
grade-a

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

162.763 USDC - $162.76

Labels

bug
G (Gas Optimization)
grade-a
sufficient quality report
G-19

External Links

<a id="summary-gas-optimizations"></a> Gas Optimizations

There are 759 instances over 27 issues.

IDDescriptionCountGas Per InstanceGas Savings
G-01++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, as is the case when used in for- and while-loops1060600
G-02>= costs less gas than >773231
G-03Constructors can be marked payable1921399
G-04Don't compare boolean expressions to boolean literals199
G-05Events should be emitted outside of loops1375375
G-06Functions guaranteed to revert when called by normal users can be marked payable2421504
G-07Gas use can be reduced by using Solidity 0.8.19 or later39--
G-08internal functions not called by the contract should be removed to save deployment gas15--
G-09internal/private functions only called once can be inlined to save gas77201,540
G-10keccak256() should only need to be called on a specific string literal once42184
G-11Multiplication by powers of two should use bit shifting1112112
G-12Nesting if-statements is cheaper than using &&14684
G-13Optimize names to save gas2622572
G-14Remove unused local variable4--
G-15require()/revert() strings longer than 32 bytes cost extra gas1153345
G-16Splitting require() statements that use && saves gas8324
G-17State variable read in a loop311003,100
G-18The result of function calls should be cached rather than re-calling the function12020
G-19unchecked {} can be used on the division of two uints in order to save gas3120620
G-20Usage of uints/ints smaller than 32 bytes (256 bits) incurs overhead922198
G-21Use assembly for small keccak256 hashes, in order to save gas18080
G-22Use assembly to emit events, in order to save gas55382,090
G-23Use custom errors rather than revert()/require() strings to save gas162--
G-24Use predefined address instead of address(this)27501,350
G-25Use uint256(1)/uint256(2) instead of true/false to save gas for changes38,55025,650
G-26Using constants directly, rather than caching the value, saves gas1--
G-27Using storage instead of memory for structs/arrays saves gas34,20012,600
Total Gas Savings50,587

Gas totals use lower bounds of ranges and count two iterations of each for loop. Gas savings values are runtime values except for cases where only deployment values are applicable, like for constant declarations.

<a id="details-gas-optimizations"></a> Gas Optimizations

<a id="g-01"></a> [G-01] ++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, as is the case when used in for- and while-loops
Description:

++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, as is the case when used in for and while loops. This saves 30-40 gas per loop iteration.

Instances:

There are 10 instances of this issue.

<details><summary>View 10 Instances</summary>
File: packages/contracts/contracts/Governor.sol

46:         for (uint256 i = 0; i < users.length(); i++) {

57:             for (uint256 i = 0; i < _usrs.length; i++) {

76:         for (uint8 i = 0; i < type(uint8).max; i++) {

84:             for (uint8 i = 0; i < type(uint8).max; i++) {

98:         for (uint8 i = 0; i < type(uint8).max; i++) {

107:             for (uint8 i = 0; i < type(uint8).max; i++) {

122:         for (uint8 i = 0; i < roleIds.length; i++) {

137:             for (uint256 i = 0; i < _sigs.length; ++i) {
File LinkInstance CountInstance Links
Governor.sol846,57,76,84,98,107,122,137

File: packages/contracts/contracts/SortedCdps.sol

432:         for (uint256 i = 0; i < _len; ++i) {

449:         for (uint i = 0; i < _len; ++i) {
File LinkInstance CountInstance Links
SortedCdps.sol2432,449

</details>
<a id="g-02"></a> [G-02] >= costs less gas than >
Description:

The compiler uses opcodes GT and ISZERO for Solidity code that uses >, but only requires LT for >=, which saves 3 gas. If < is being used, the condition can be inverted.

Instances:

There are 77 instances of this issue.

<details><summary>View 77 Instances</summary>
File: packages/contracts/contracts/BorrowerOperations.sol

393:         if (!_isDebtIncrease && _debtChange > 0) {

495:             if (newTCR < CCR) {

495:             if (newTCR < CCR) {

891:             if (_vars.newTCR < CCR) {

891:             if (_vars.newTCR < CCR) {
File LinkInstance CountInstance Links
BorrowerOperations.sol5393,495,495,891,891

File: packages/contracts/contracts/CdpManager.sol

203:                 collateral.getPooledEthByShares(newColl) < MIN_NET_STETH_BALANCE

203:                 collateral.getPooledEthByShares(newColl) < MIN_NET_STETH_BALANCE

279:             getSyncedICR(_firstRedemptionHint, _price) < MCR

369:             while (currentBorrower != address(0) && getSyncedICR(_cId, totals.price) < MCR) {

436:         } else if (_numCdpsFullyRedeemed > 1) {

436:         } else if (_numCdpsFullyRedeemed > 1) {
File LinkInstance CountInstance Links
CdpManager.sol6203,203,279,369,436,436

File: packages/contracts/contracts/CdpManagerStorage.sol

99:         if (newTCR < CCR) {

315:         if (_debtIndexDiff > 0) {

362:         if (_feeSplitDistributed > 0 || _debtIndexDelta > 0) {

362:         if (_feeSplitDistributed > 0 || _debtIndexDelta > 0) {

369:             if (_feeSplitDistributed > 0) {

369:             if (_feeSplitDistributed > 0) {

380:             if (_debtIndexDelta > 0) {

380:             if (_debtIndexDelta > 0) {

453:             require(totalStakesSnapshot > 0, "CdpManagerStorage: zero totalStakesSnapshot!");

512:         if (_newIndex > _oldIndex && totalStakes > 0) {

512:         if (_newIndex > _oldIndex && totalStakes > 0) {

636:         if (_scaledCdpColl > _feeSplitDistributed) {

765:         if (_newIndex > _oldIndex && totalStakes > 0) {

765:         if (_newIndex > _oldIndex && totalStakes > 0) {

796:         if (_cdpPerUnitIdx != _systemStEthFeePerUnitIndex && _cdpPerUnitIdx > 0) {

829:         if (pendingDebtRedistributed > 0) {

879:         if (_feeTaken > 0) {
File LinkInstance CountInstance Links
CdpManagerStorage.sol1799,315,362,362,369,369,380,380,453,512,512,636,765,765,796,829,879

File: packages/contracts/contracts/Dependencies/EbtcMath.sol

60:         if (_minutes > 525600000) {

93:         if (_debt > 0) {

109:         if (_debt > 0) {
File LinkInstance CountInstance Links
EbtcMath.sol360,93,109

File: packages/contracts/contracts/Governor.sol

53:         if (count > 0) {

57:             for (uint256 i = 0; i < _usrs.length; i++) {

81:         if (count > 0) {

84:             for (uint8 i = 0; i < type(uint8).max; i++) {

104:         if (count > 0) {

107:             for (uint8 i = 0; i < type(uint8).max; i++) {

135:         if (_sigs.length > 0) {

137:             for (uint256 i = 0; i < _sigs.length; ++i) {
File LinkInstance CountInstance Links
Governor.sol853,57,81,84,104,107,135,137

File: packages/contracts/contracts/HintHelpers.sol

93:                 if (currentCdpDebt > vars.remainingEbtcToRedeem) {

102:                         collateral.getPooledEthByShares(partialRedemptionNewColl) <
103:                         MIN_NET_STETH_BALANCE

102:                         collateral.getPooledEthByShares(partialRedemptionNewColl) <
103:                         MIN_NET_STETH_BALANCE

191:             if (currentDiff < diff) {
File LinkInstance CountInstance Links
HintHelpers.sol493,102,102,191

File: packages/contracts/contracts/LeverageMacroBase.sol

128:         if (operation.amountToTransferIn > 0) {

223:         if (ebtcBal > 0) {

227:         if (collateralBal > 0) {

293:         if (beforeSwapsLength > 0) {

307:         if (afterSwapsLength > 0) {
File LinkInstance CountInstance Links
LeverageMacroBase.sol5128,223,227,293,307

File: packages/contracts/contracts/LiquidationLibrary.sol

94:                 block.timestamp >
95:                     cachedLastGracePeriodStartTimestamp + recoveryModeGracePeriodDuration,

195:             if (_outputState.totalSurplusCollShares > 0) {

195:             if (_outputState.totalSurplusCollShares > 0) {

261:             if (_collSurplus > 0) {

266:             if (_debtToRedistribute > 0) {

336:             if (_collSurplus > 0) {

342:             if (_debtToRedistribute > 0) {

476:         if (_partialState.ICR > LICR) {

525:         if (totalDebtToRedistribute > 0) {

553:         if (_ICR > LICR) {

555:             _incentiveColl = (_totalDebtToBurn * (_ICR > MCR ? MCR : _ICR)) / _price;

578:         if (_ICR > LICR) {

579:             _incentiveColl = (_totalDebtToBurn * (_ICR > MCR ? MCR : _ICR)) / _price;

594:             debtToRedistribute = _debtToRepay < _totalDebtToBurn

713:         if (totals.totalCollSurplus > 0) {

788:                     vars.backToNormalMode = _TCR < CCR ? false : true;

788:                     vars.backToNormalMode = _TCR < CCR ? false : true;
File LinkInstance CountInstance Links
LiquidationLibrary.sol1794,195,195,261,266,336,342,476,525,553,555,578,579,594,713,788,788

File: packages/contracts/contracts/PriceFeed.sol

421:             _response.timestampEthBtc > block.timestamp ||

423:             _response.timestampStEthEth > block.timestamp

471:         if (_response.timestamp == 0 || _response.timestamp > block.timestamp) {
File LinkInstance CountInstance Links
PriceFeed.sol3421,423,471

File: packages/contracts/contracts/SortedCdps.sol

202:             if (maxNodes > 0 && i >= maxNodes) {

259:             if (maxNodes > 0 && i >= maxNodes) {

274:         if (_ownedCount > 0) {

330:             if (maxNodes > 0 && i >= maxNodes) {

460:         if (data.size > 1) {

683:             if (!contains(prevId) || _NICR > cdpManager.getCachedNominalICR(prevId)) {

683:             if (!contains(prevId) || _NICR > cdpManager.getCachedNominalICR(prevId)) {

690:             if (!contains(nextId) || _NICR < cdpManager.getCachedNominalICR(nextId)) {

690:             if (!contains(nextId) || _NICR < cdpManager.getCachedNominalICR(nextId)) {
File LinkInstance CountInstance Links
SortedCdps.sol9202,259,274,330,460,683,683,690,690

</details>
<a id="g-03"></a> [G-03] Constructors can be marked payable
Description:

payable functions cost less gas to execute since the compiler does not have to add extra checks to ensure that a payment wasn't provided. A constructor can safely be marked as payable since only the deployer can pass funds.

Instances:

There are 19 instances of this issue.

<details><summary>View 19 Instances</summary>
File: packages/contracts/contracts/ActivePool.sol

46:     constructor(
47:         address _borrowerOperationsAddress,
48:         address _cdpManagerAddress,
49:         address _collTokenAddress,
50:         address _collSurplusAddress,
51:         address _feeRecipientAddress
52:     ) {
File LinkInstance CountInstance Link
ActivePool.sol146

File: packages/contracts/contracts/BorrowerOperations.sol

107:     constructor(
108:         address _cdpManagerAddress,
109:         address _activePoolAddress,
110:         address _collSurplusPoolAddress,
111:         address _priceFeedAddress,
112:         address _sortedCdpsAddress,
113:         address _ebtcTokenAddress,
114:         address _feeRecipientAddress,
115:         address _collTokenAddress
116:     ) EbtcBase(_activePoolAddress, _priceFeedAddress, _collTokenAddress) {
File LinkInstance CountInstance Link
BorrowerOperations.sol1107

File: packages/contracts/contracts/CdpManager.sol

30:     constructor(
31:         address _liquidationLibraryAddress,
32:         address _authorityAddress,
33:         address _borrowerOperationsAddress,
34:         address _collSurplusPoolAddress,
35:         address _ebtcTokenAddress,
36:         address _sortedCdpsAddress,
37:         address _activePoolAddress,
38:         address _priceFeedAddress,
39:         address _collTokenAddress
40:     )
41:         CdpManagerStorage(
42:             _liquidationLibraryAddress,
43:             _authorityAddress,
44:             _borrowerOperationsAddress,
45:             _collSurplusPoolAddress,
46:             _ebtcTokenAddress,
47:             _sortedCdpsAddress,
48:             _activePoolAddress,
49:             _priceFeedAddress,
50:             _collTokenAddress
51:         )
52:     {
File LinkInstance CountInstance Link
CdpManager.sol130

File: packages/contracts/contracts/CdpManagerStorage.sol

217:     constructor(
218:         address _liquidationLibraryAddress,
219:         address _authorityAddress,
220:         address _borrowerOperationsAddress,
221:         address _collSurplusPool,
222:         address _ebtcToken,
223:         address _sortedCdps,
224:         address _activePool,
225:         address _priceFeed,
226:         address _collateral
227:     ) EbtcBase(_activePool, _priceFeed, _collateral) {
File LinkInstance CountInstance Link
CdpManagerStorage.sol1217

File: packages/contracts/contracts/CollSurplusPool.sol

42:     constructor(
43:         address _borrowerOperationsAddress,
44:         address _cdpManagerAddress,
45:         address _activePoolAddress,
46:         address _collTokenAddress
47:     ) {
File LinkInstance CountInstance Link
CollSurplusPool.sol142

File: packages/contracts/contracts/Dependencies/Auth.sol

18:     constructor(address _owner, Authority _authority) {
File LinkInstance CountInstance Link
Auth.sol118

File: packages/contracts/contracts/Dependencies/EbtcBase.sol

52:     constructor(address _activePoolAddress, address _priceFeedAddress, address _collateralAddress) {
File LinkInstance CountInstance Link
EbtcBase.sol152

File: packages/contracts/contracts/Dependencies/RolesAuthority.sol

20:     constructor(address _owner, Authority _authority) Auth(_owner, _authority) {}
File LinkInstance CountInstance Link
RolesAuthority.sol120

File: packages/contracts/contracts/EBTCToken.sol

61:     constructor(
62:         address _cdpManagerAddress,
63:         address _borrowerOperationsAddress,
64:         address _authorityAddress
65:     ) {
File LinkInstance CountInstance Link
EBTCToken.sol161

File: packages/contracts/contracts/Governor.sol

36:     constructor(address _owner) RolesAuthority(_owner, Authority(address(this))) {}
File LinkInstance CountInstance Link
Governor.sol136

File: packages/contracts/contracts/HintHelpers.sol

27:     constructor(
28:         address _sortedCdpsAddress,
29:         address _cdpManagerAddress,
30:         address _collateralAddress,
31:         address _activePoolAddress,
32:         address _priceFeedAddress
33:     ) EbtcBase(_activePoolAddress, _priceFeedAddress, _collateralAddress) {
File LinkInstance CountInstance Link
HintHelpers.sol127

File: packages/contracts/contracts/LeverageMacroBase.sol

51:     constructor(
52:         address _borrowerOperationsAddress,
53:         address _activePool,
54:         address _cdpManager,
55:         address _ebtc,
56:         address _coll,
57:         address _sortedCdps,
58:         bool _sweepToCaller
59:     ) {
File LinkInstance CountInstance Link
LeverageMacroBase.sol151

File: packages/contracts/contracts/LeverageMacroDelegateTarget.sol

41:     constructor(
42:         address _borrowerOperationsAddress,
43:         address _activePool,
44:         address _cdpManager,
45:         address _ebtc,
46:         address _coll,
47:         address _sortedCdps
48:     )
49:         LeverageMacroBase(
50:             _borrowerOperationsAddress,
51:             _activePool,
52:             _cdpManager,
53:             _ebtc,
54:             _coll,
55:             _sortedCdps,
56:             false // Do not sweep to caller
57:         )
58:     {
File LinkInstance CountInstance Link
LeverageMacroDelegateTarget.sol141

File: packages/contracts/contracts/LeverageMacroFactory.sol

21:     constructor(
22:         address _borrowerOperationsAddress,
23:         address _activePool,
24:         address _cdpManager,
25:         address _ebtc,
26:         address _coll,
27:         address _sortedCdps
28:     ) {
File LinkInstance CountInstance Link
LeverageMacroFactory.sol121

File: packages/contracts/contracts/LeverageMacroReference.sol

17:     constructor(
18:         address _borrowerOperationsAddress,
19:         address _activePool,
20:         address _cdpManager,
21:         address _ebtc,
22:         address _coll,
23:         address _sortedCdps,
24:         address _owner
25:     )
26:         LeverageMacroBase(
27:             _borrowerOperationsAddress,
28:             _activePool,
29:             _cdpManager,
30:             _ebtc,
31:             _coll,
32:             _sortedCdps,
33:             true // Sweep to caller since this is not supposed to hold funds
34:         )
35:     {
File LinkInstance CountInstance Link
LeverageMacroReference.sol117

File: packages/contracts/contracts/LiquidationLibrary.sol

14:     constructor(
15:         address _borrowerOperationsAddress,
16:         address _collSurplusPool,
17:         address _ebtcToken,
18:         address _sortedCdps,
19:         address _activePool,
20:         address _priceFeed,
21:         address _collateral
22:     )
23:         CdpManagerStorage(
24:             address(0),
25:             address(0),
26:             _borrowerOperationsAddress,
27:             _collSurplusPool,
28:             _ebtcToken,
29:             _sortedCdps,
30:             _activePool,
31:             _priceFeed,
32:             _collateral
33:         )
34:     {}
File LinkInstance CountInstance Link
LiquidationLibrary.sol114

File: packages/contracts/contracts/PriceFeed.sol

57:     constructor(
58:         address _fallbackCallerAddress,
59:         address _authorityAddress,
60:         address _collEthCLFeed,
61:         address _ethBtcCLFeed
62:     ) {
File LinkInstance CountInstance Link
PriceFeed.sol157

File: packages/contracts/contracts/SimplifiedDiamondLike.sol

44:     constructor(address _owner) {
File LinkInstance CountInstance Link
SimplifiedDiamondLike.sol144

File: packages/contracts/contracts/SortedCdps.sol

88:     constructor(uint256 _size, address _cdpManagerAddress, address _borrowerOperationsAddress) {
File LinkInstance CountInstance Link
SortedCdps.sol188

</details>
<a id="g-04"></a> [G-04] Don't compare boolean expressions to boolean literals
Description:

Do not compare boolean expressions to the boolean literals true and false.

  • No: if (foo == true)
  • Yes: if (foo)
  • No: if (bar == false)
  • Yes: if (!bar)
Instances:

There is 1 instance of this issue.

File: packages/contracts/contracts/CdpManager.sol

332:         require(redemptionsPaused == false, "CdpManager: Redemptions Paused");
File LinkInstance CountInstance Link
CdpManager.sol1332

<a id="g-05"></a> [G-05] Events should be emitted outside of loops
Description:

Emitting an event has an overhead of 375 gas, which will be incurred on every iteration of the loop. It is cheaper to emit as a "batch" once after the loop has finished.

Instances:

There is 1 instance of this issue.

File: packages/contracts/contracts/SortedCdps.sol

451:             emit NodeRemoved(_ids[i]);
File LinkInstance CountInstance Link
SortedCdps.sol1451

<a id="g-06"></a> [G-06] Functions guaranteed to revert when called by normal users can be marked payable
Description:

If a function modifier such as onlyOwner is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided. The extra opcodes avoided are CALLVALUE(2), DUP1(3), ISZERO(3), PUSH2(3), JUMPI(10), PUSH1(3), DUP1(3), REVERT(0), JUMPDEST(1), and POP(2). In addition to the extra deployment cost, on average, approximately 21 gas can be saved per call to the function.

Instances:

There are 24 instances of this issue.

<details><summary>View 24 Instances</summary>
File: packages/contracts/contracts/ActivePool.sol

346:     function claimFeeRecipientCollShares(uint256 _shares) external override requiresAuth {

371:     function sweepToken(address token, uint256 amount) public nonReentrant requiresAuth {

390:     function setFeeRecipientAddress(address _feeRecipientAddress) external requiresAuth {

404:     function setFeeBps(uint256 _newFee) external requiresAuth {

417:     function setFlashLoansPaused(bool _paused) external requiresAuth {
File LinkInstance CountInstance Links
ActivePool.sol5346,371,390,404,417

File: packages/contracts/contracts/BorrowerOperations.sol

1140:     function setFeeRecipientAddress(address _feeRecipientAddress) external requiresAuth {

1154:     function setFeeBps(uint256 _newFee) external requiresAuth {

1167:     function setFlashLoansPaused(bool _paused) external requiresAuth {
File LinkInstance CountInstance Links
BorrowerOperations.sol31140,1154,1167

File: packages/contracts/contracts/CdpManager.sol

773:     function setStakingRewardSplit(uint256 _stakingRewardSplit) external requiresAuth {

788:     function setRedemptionFeeFloor(uint256 _redemptionFeeFloor) external requiresAuth {

807:     function setMinuteDecayFactor(uint256 _minuteDecayFactor) external requiresAuth {

830:     function setBeta(uint256 _beta) external requiresAuth {

843:     function setRedemptionsPaused(bool _paused) external requiresAuth {
File LinkInstance CountInstance Links
CdpManager.sol5773,788,807,830,843

File: packages/contracts/contracts/CdpManagerStorage.sol

111:     function setGracePeriod(uint128 _gracePeriod) external requiresAuth {
File LinkInstance CountInstance Link
CdpManagerStorage.sol1111

File: packages/contracts/contracts/CollSurplusPool.sol

142:     function sweepToken(address token, uint256 amount) public nonReentrant requiresAuth {
File LinkInstance CountInstance Link
CollSurplusPool.sol1142

File: packages/contracts/contracts/Dependencies/Auth.sol

52:     function transferOwnership(address newOwner) public virtual requiresAuth {
File LinkInstance CountInstance Link
Auth.sol152

File: packages/contracts/contracts/Dependencies/RolesAuthority.sol

20:     constructor(address _owner, Authority _authority) Auth(_owner, _authority) {}

85:     function setPublicCapability(
86:         address target,
87:         bytes4 functionSig,
88:         bool enabled
89:     ) public virtual requiresAuth {

106:     function setRoleCapability(
107:         uint8 role,
108:         address target,
109:         bytes4 functionSig,
110:         bool enabled
111:     ) public virtual requiresAuth {

133:     function burnCapability(address target, bytes4 functionSig) public virtual requiresAuth {

147:     function setUserRole(address user, uint8 role, bool enabled) public virtual requiresAuth {
File LinkInstance CountInstance Links
RolesAuthority.sol520,85,106,133,147

File: packages/contracts/contracts/Governor.sol

36:     constructor(address _owner) RolesAuthority(_owner, Authority(address(this))) {}

154:     function setRoleName(uint8 role, string memory roleName) external requiresAuth {
File LinkInstance CountInstance Links
Governor.sol236,154

File: packages/contracts/contracts/PriceFeed.sol

358:     function setFallbackCaller(address _fallbackCaller) external requiresAuth {
File LinkInstance CountInstance Link
PriceFeed.sol1358

</details>
<a id="g-07"></a> [G-07] Gas use can be reduced by using Solidity 0.8.19 or later
Description:

See Preventing Dead Code in Runtime Bytecode for the full details.

Instances:

There are 39 instances of this issue.

<details><summary>View 39 Instances</summary>
File: packages/contracts/contracts/ActivePool.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
ActivePool.sol13

File: packages/contracts/contracts/BorrowerOperations.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
BorrowerOperations.sol13

File: packages/contracts/contracts/CdpManager.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
CdpManager.sol13

File: packages/contracts/contracts/CdpManagerStorage.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
CdpManagerStorage.sol13

File: packages/contracts/contracts/CollSurplusPool.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
CollSurplusPool.sol13

File: packages/contracts/contracts/Dependencies/Auth.sol

2: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
Auth.sol12

File: packages/contracts/contracts/Dependencies/AuthNoOwner.sol

2: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
AuthNoOwner.sol12

File: packages/contracts/contracts/Dependencies/ERC3156FlashLender.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
ERC3156FlashLender.sol13

File: packages/contracts/contracts/Dependencies/EbtcBase.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
EbtcBase.sol13

File: packages/contracts/contracts/Dependencies/EbtcMath.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
EbtcMath.sol13

File: packages/contracts/contracts/Dependencies/ReentrancyGuard.sol

2: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
ReentrancyGuard.sol12

File: packages/contracts/contracts/Dependencies/RolesAuthority.sol

2: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
RolesAuthority.sol12

File: packages/contracts/contracts/EBTCToken.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
EBTCToken.sol13

File: packages/contracts/contracts/Governor.sol

2: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
Governor.sol12

File: packages/contracts/contracts/HintHelpers.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
HintHelpers.sol13

File: packages/contracts/contracts/Interfaces/IActivePool.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
IActivePool.sol13

File: packages/contracts/contracts/Interfaces/IBorrowerOperations.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
IBorrowerOperations.sol13

File: packages/contracts/contracts/Interfaces/ICdpManager.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
ICdpManager.sol13

File: packages/contracts/contracts/Interfaces/ICdpManagerData.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
ICdpManagerData.sol13

File: packages/contracts/contracts/Interfaces/ICollSurplusPool.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
ICollSurplusPool.sol13

File: packages/contracts/contracts/Interfaces/IEBTCToken.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
IEBTCToken.sol13

File: packages/contracts/contracts/Interfaces/IERC3156FlashBorrower.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
IERC3156FlashBorrower.sol13

File: packages/contracts/contracts/Interfaces/IERC3156FlashLender.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
IERC3156FlashLender.sol13

File: packages/contracts/contracts/Interfaces/IEbtcBase.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
IEbtcBase.sol13

File: packages/contracts/contracts/Interfaces/IFallbackCaller.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
IFallbackCaller.sol13

File: packages/contracts/contracts/Interfaces/IPermitNonce.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
IPermitNonce.sol13

File: packages/contracts/contracts/Interfaces/IPool.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
IPool.sol13

File: packages/contracts/contracts/Interfaces/IPositionManagers.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
IPositionManagers.sol13

File: packages/contracts/contracts/Interfaces/IPriceFeed.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
IPriceFeed.sol13

File: packages/contracts/contracts/Interfaces/IRecoveryModeGracePeriod.sol

2: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
IRecoveryModeGracePeriod.sol12

File: packages/contracts/contracts/Interfaces/ISortedCdps.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
ISortedCdps.sol13

File: packages/contracts/contracts/LeverageMacroBase.sol

2: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
LeverageMacroBase.sol12

File: packages/contracts/contracts/LeverageMacroDelegateTarget.sol

2: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
LeverageMacroDelegateTarget.sol12

File: packages/contracts/contracts/LeverageMacroFactory.sol

2: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
LeverageMacroFactory.sol12

File: packages/contracts/contracts/LeverageMacroReference.sol

2: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
LeverageMacroReference.sol12

File: packages/contracts/contracts/LiquidationLibrary.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
LiquidationLibrary.sol13

File: packages/contracts/contracts/PriceFeed.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
PriceFeed.sol13

File: packages/contracts/contracts/SimplifiedDiamondLike.sol

2: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
SimplifiedDiamondLike.sol12

File: packages/contracts/contracts/SortedCdps.sol

3: pragma solidity 0.8.17;
File LinkInstance CountInstance Link
SortedCdps.sol13

</details>
<a id="g-08"></a> [G-08] internal functions not called by the contract should be removed to save deployment gas
Description:

If the functions are required by an interface, the contract should inherit from that interface and use the override keyword.

Instances:

There are 15 instances of this issue.

<details><summary>View 15 Instances</summary>
File: packages/contracts/contracts/CdpManagerStorage.sol

87:     function _syncGracePeriodForGivenValues(
88:         uint256 systemCollShares,
89:         uint256 systemDebt,
90:         uint256 price
91:     ) internal {

255:     function _closeCdp(bytes32 _cdpId, Status closedStatus) internal {

344:     function _syncAccounting(bytes32 _cdpId) internal {

419:     function _updateStakeAndTotalStakes(bytes32 _cdpId) internal returns (uint256) {

489:     function _computeTCRWithGivenSystemValues(
490:         uint256 _systemCollShares,
491:         uint256 _systemDebt,
492:         uint256 _price
493:     ) internal view returns (uint256) {

648:     function _requireCdpIsActive(bytes32 _cdpId) internal view {

733:     function _getSyncedDebtAndCollShares(
734:         bytes32 _cdpId
735:     ) internal view returns (CdpDebtAndCollShares memory) {
File LinkInstance CountInstance Links
CdpManagerStorage.sol787,255,344,419,489,648,733

File: packages/contracts/contracts/Dependencies/AuthNoOwner.sol

55:     function _initializeAuthority(address newAuthority) internal {
File LinkInstance CountInstance Link
AuthNoOwner.sol155

File: packages/contracts/contracts/Dependencies/EbtcBase.sol

60:     function _calcNetStEthBalance(uint256 _stEthBalance) internal pure returns (uint256) {

95:     function _checkRecoveryMode(uint256 _price) internal view returns (bool) {

103:     function _requireUserAcceptsFee(
104:         uint256 _fee,
105:         uint256 _amount,
106:         uint256 _maxFeePercentage
107:     ) internal pure {

115:     function _convertDebtDenominationToBtc(
116:         uint256 _debt,
117:         uint256 _price
118:     ) internal pure returns (uint256) {

124:     function _checkICRAgainstLiqThreshold(uint256 _icr, uint _tcr) internal view returns (bool) {
File LinkInstance CountInstance Links
EbtcBase.sol560,95,103,115,124

File: packages/contracts/contracts/EBTCToken.sol

306:     function _requireCallerIsBorrowerOperations() internal view {

323:     function _requireCallerIsCdpM() internal view {
File LinkInstance CountInstance Links
EBTCToken.sol2306,323

</details>
<a id="g-09"></a> [G-09] internal/private functions only called once can be inlined to save gas
Description:

The two extra JUMP instructions and additional stack operations needed for function calls costs 20 to 40 gas.

Recommendation:

For internal or private functions used just once, move the function logic to the calling function.

Instances:

There are 77 instances of this issue.

<details><summary>View 77 Instances</summary>
File: packages/contracts/contracts/ActivePool.sol

219:     function _requireCallerIsBorrowerOperations() internal view {

235:     function _requireCallerIsCdpManager() internal view {
File LinkInstance CountInstance Links
ActivePool.sol2219,235

File: packages/contracts/contracts/BorrowerOperations.sol

744:     function _getCollSharesChangeFromStEthChange(
745:         uint256 _collReceived,
746:         uint256 _requestedCollWithdrawal
747:     ) internal view returns (uint256 collSharesChange, bool isCollIncrease) {

760:     function _processTokenMovesFromAdjustment(MoveTokensParams memory _varMvTokens) internal {

803:     function _requireSingularCollChange(
804:         uint256 _stEthBalanceIncrease,
805:         uint256 _stEthBalanceDecrease
806:     ) internal pure {

813:     function _requireNonZeroAdjustment(
814:         uint256 _stEthBalanceIncrease,
815:         uint256 _debtChange,
816:         uint256 _stEthBalanceDecrease
817:     ) internal pure {

829:     function _requireCdpIsNonExistent(bytes32 _cdpId) internal view {

834:     function _requireNonZeroDebtChange(uint _debtChange) internal pure {

838:     function _requireNotInRecoveryMode(uint256 _tcr) internal view {

845:     function _requireNoStEthBalanceDecrease(uint256 _stEthBalanceDecrease) internal pure {

852:     function _requireValidAdjustmentInCurrentMode(
853:         bool _isRecoveryMode,
854:         uint256 _stEthBalanceDecrease,
855:         bool _isDebtIncrease,
856:         AdjustCdpLocals memory _vars
857:     ) internal {

921:     function _requireNoDecreaseOfICR(uint256 _newICR, uint256 _oldICR) internal pure {

946:     function _requireValidDebtRepayment(uint256 _currentDebt, uint256 _debtRepayment) internal pure {

986:     function _getNewNominalICRFromCdpChange(
987:         AdjustCdpLocals memory vars,
988:         bool _isDebtIncrease
989:     ) internal pure returns (uint256) {

1004:     function _getNewICRFromCdpChange(
1005:         uint256 _collShares,
1006:         uint256 _debt,
1007:         uint256 _collSharesChange,
1008:         bool _isCollIncrease,
1009:         uint256 _debtChange,
1010:         bool _isDebtIncrease,
1011:         uint256 _price
1012:     ) internal view returns (uint256) {
File LinkInstance CountInstance Links
BorrowerOperations.sol13744,760,803,813,829,834,838,845,852,921,946,986,1004

File: packages/contracts/contracts/CdpManager.sol

135:     function _redeemCollateralFromCdp(
136:         SingleRedemptionInputs memory _redeemColFromCdp
137:     ) internal returns (SingleRedemptionValues memory singleRedemption) {

244:     function _closeCdpByRedemption(
245:         bytes32 _cdpId,
246:         uint256 _EBTC,
247:         uint256 _collSurplus,
248:         uint256 _liquidatorRewardShares,
249:         address _borrower
250:     ) internal {

272:     function _isValidFirstRedemptionHint(
273:         bytes32 _firstRedemptionHint,
274:         uint256 _price
275:     ) internal view returns (bool) {

489:     function _getCdpIdsToRemove(
490:         bytes32 _start,
491:         uint256 _total,
492:         bytes32 _end
493:     ) internal view returns (bytes32[] memory) {

550:     function _addCdpIdToArray(bytes32 _cdpId) internal returns (uint128 index) {

595:     function _checkPotentialRecoveryMode(
596:         uint256 _systemCollShares,
597:         uint256 _systemDebt,
598:         uint256 _price
599:     ) internal view returns (bool) {

612:     function _updateBaseRateFromRedemption(
613:         uint256 _ETHDrawn,
614:         uint256 _price,
615:         uint256 _totalEBTCSupply
616:     ) internal returns (uint256) {

655:     function _getRedemptionFee(uint256 _ETHDrawn) internal view returns (uint256) {

737:     function _requireEbtcBalanceCoversRedemptionAndWithinSupply(
738:         address _redeemer,
739:         uint256 _amount,
740:         uint256 _totalSupply
741:     ) internal view {

753:     function _requireAmountGreaterThanZero(uint256 _amount) internal pure {

757:     function _requireTCRisNotBelowMCR(uint256 _price, uint256 _TCR) internal view {

761:     function _requireValidMaxFeePercentage(uint256 _maxFeePercentage) internal view {

977:     function _setCdpCollShares(bytes32 _cdpId, uint256 _newColl) internal {

984:     function _setCdpDebt(bytes32 _cdpId, uint256 _newDebt) internal {
File LinkInstance CountInstance Links
CdpManager.sol14135,244,272,489,550,595,612,655,737,753,757,761,977,984

File: packages/contracts/contracts/CdpManagerStorage.sol

73:     function _syncGracePeriod() internal {

260:     function _closeCdpWithoutRemovingSortedCdps(bytes32 _cdpId, Status closedStatus) internal {

293:     function _updateSystemSnapshotsExcludeCollRemainder(uint256 _collRemainder) internal {

327:     function _hasRedistributedDebt(bytes32 _cdpId) internal view returns (bool) {

336:     function _updateRedistributedDebtIndex(bytes32 _cdpId) internal {

410:     function _removeStake(bytes32 _cdpId) internal {

431:     function _updateStakeForCdp(bytes32 _cdpId) internal returns (uint256, uint256) {

441:     function _computeNewStake(uint256 _coll) internal view returns (uint256) {

463:     function _removeCdp(bytes32 _cdpId, uint256 cdpIdsArrayLength) internal {

539:     function _syncStEthIndex(uint256 _oldIndex, uint256 _newIndex) internal {

574:     function _takeSplitAndUpdateFeePerUnit(
575:         uint256 _feeTaken,
576:         uint256 _newPerUnit,
577:         uint256 _newErrorPerUnit
578:     ) internal {

592:     function _applyAccumulatedFeeSplit(
593:         bytes32 _cdpId,
594:         uint256 _newColl,
595:         uint256 _feeSplitDistributed,
596:         uint256 _oldPerUnitCdp,
597:         uint256 _systemStEthFeePerUnitIndex
598:     ) internal {

652:     function _requireMoreThanOneCdpInSystem(uint256 CdpOwnersArrayLength) internal view {

895:     function _recoveryModeGracePeriodPassed() internal view returns (bool) {
File LinkInstance CountInstance Links
CdpManagerStorage.sol1473,260,293,327,336,410,431,441,463,539,574,592,652,895

File: packages/contracts/contracts/CollSurplusPool.sol

112:     function _requireCallerIsBorrowerOperations() internal view {

119:     function _requireCallerIsCdpManager() internal view {

123:     function _requireCallerIsActivePool() internal view {
File LinkInstance CountInstance Links
CollSurplusPool.sol3112,119,123

File: packages/contracts/contracts/Dependencies/Auth.sol

32:     function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) {
File LinkInstance CountInstance Link
Auth.sol132

File: packages/contracts/contracts/Dependencies/AuthNoOwner.sol

30:     function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) {
File LinkInstance CountInstance Link
AuthNoOwner.sol130

File: packages/contracts/contracts/Dependencies/EbtcBase.sol

75:     function _getSystemDebt() internal view returns (uint256 entireSystemDebt) {

79:     function _getCachedTCR(uint256 _price) internal view returns (uint256 TCR) {

83:     function _getTCRWithSystemDebtAndCollShares(
84:         uint256 _price
85:     ) internal view returns (uint256 TCR, uint256 _coll, uint256 _debt) {

134:     function _checkICRAgainstMCR(uint256 _icr) internal view returns (bool) {

140:     function _checkICRAgainstTCR(uint256 _icr, uint _tcr) internal view returns (bool) {
File LinkInstance CountInstance Links
EbtcBase.sol575,79,83,134,140

File: packages/contracts/contracts/EBTCToken.sol

262:     function _mint(address account, uint256 amount) internal {
File LinkInstance CountInstance Link
EBTCToken.sol1262

File: packages/contracts/contracts/HintHelpers.sol

133:     function _calculateCdpStateAfterPartialRedemption(
134:         LocalVariables_getRedemptionHints memory vars,
135:         uint256 currentCdpDebt,
136:         uint256 _price
137:     ) internal view returns (uint256, uint256) {
File LinkInstance CountInstance Link
HintHelpers.sol1133

File: packages/contracts/contracts/LeverageMacroBase.sol

398:     function _doSwap(SwapOperation memory swapData) internal {

435:     function _doSwapChecks(SwapCheck[] memory swapChecks) internal {

450:     function _ensureNotSystem(address addy) internal {

460:     function _openCdpCallback(bytes memory data) internal {

474:     function _closeCdpCallback(bytes memory data) internal {

482:     function _adjustCdpCallback(bytes memory data) internal {

498:     function excessivelySafeCall(
499:         address _target,
500:         uint256 _gas,
501:         uint256 _value,
502:         uint16 _maxCopy,
503:         bytes memory _calldata
504:     ) internal returns (bool, bytes memory) {
File LinkInstance CountInstance Links
LeverageMacroBase.sol7398,435,450,460,474,482,498

File: packages/contracts/contracts/LiquidationLibrary.sol

135:     function _liquidateIndividualCdpSetupCDP(
136:         LiquidationLocals memory _liqState,
137:         LiquidationRecoveryModeLocals memory _recoveryState
138:     ) internal {

397:     function _liquidateCDPPartially(
398:         LiquidationLocals memory _partialState
399:     ) private returns (uint256, uint256) {

450:     function _partiallyReduceCdpDebt(
451:         bytes32 _cdpId,
452:         uint256 _partialDebt,
453:         uint256 _partialColl
454:     ) internal {

466:     function _reInsertPartialLiquidation(
467:         LiquidationLocals memory _partialState,
468:         uint256 _newNICR,
469:         uint256 _oldDebt,
470:         uint256 _oldColl
471:     ) internal {

544:     function _calculatePartialLiquidationSurplusAndCap(
545:         uint256 _ICR,
546:         uint256 _price,
547:         uint256 _totalDebtToBurn,
548:         uint256 _totalColToSend
549:     ) private view returns (uint256 toLiquidator, uint256 collSurplus, uint256 debtToRedistribute) {

642:     function _getLiquidationValuesRecoveryMode(
643:         uint256 _price,
644:         uint256 _systemDebt,
645:         uint256 _systemCollShares,
646:         LocalVariables_LiquidationSequence memory vars,
647:         LiquidationValues memory singleLiquidation
648:     ) internal {

733:     function _getTotalFromBatchLiquidate_RecoveryMode(
734:         uint256 _price,
735:         uint256 _systemCollShares,
736:         uint256 _systemDebt,
737:         bytes32[] memory _cdpArray
738:     ) internal returns (LiquidationTotals memory totals) {

807:     function _getTotalsFromBatchLiquidate_NormalMode(
808:         uint256 _price,
809:         uint256 _TCR,
810:         bytes32[] memory _cdpArray
811:     ) internal returns (LiquidationTotals memory totals) {

862:     function _redistributeDebt(uint256 _debt) internal {

896:     function _requirePartialLiqDebtSize(
897:         uint256 _partialDebt,
898:         uint256 _entireDebt,
899:         uint256 _price
900:     ) internal view {

908:     function _requirePartialLiqCollSize(uint256 _entireColl) internal pure {
File LinkInstance CountInstance Links
LiquidationLibrary.sol11135,397,450,466,544,642,733,807,862,896,908

File: packages/contracts/contracts/PriceFeed.sol

582:     function _getCurrentFallbackResponse()
583:         internal
584:         view
585:         returns (FallbackResponse memory fallbackResponse)
586:     {
File LinkInstance CountInstance Link
PriceFeed.sol1582

File: packages/contracts/contracts/SimplifiedDiamondLike.sol

134:     function _executeOne(Operation calldata op) internal {

174:     function _fallback() internal {
File LinkInstance CountInstance Links
SimplifiedDiamondLike.sol2134,174

File: packages/contracts/contracts/SortedCdps.sol

642:     function _ascendList(uint256 _NICR, bytes32 _startId) internal view returns (bytes32, bytes32) {
File LinkInstance CountInstance Link
SortedCdps.sol1642

</details>
<a id="g-10"></a> [G-10] keccak256() should only need to be called on a specific string literal once
Description:

The result of the call to keccak256() should be saved to an immutable variable, and that variable used instead. If the hash is being used as a part of a function selector, the cast to bytes4 should also only be done once.

Recommendation:

To reduce gas cost and redundancy, keccak256() should only be called on a specific string literal once.

Instances:

There are 4 instances of this issue.

File: packages/contracts/contracts/BorrowerOperations.sol

/// @audit also at packages/contracts/contracts/EBTCToken.sol:72
129:         bytes32 hashedVersion = keccak256(bytes(_VERSION));
File LinkInstance CountInstance Link
BorrowerOperations.sol1129

File: packages/contracts/contracts/Dependencies/ERC3156FlashLender.sol

/// @audit also at packages/contracts/contracts/LeverageMacroBase.sol:37
11:     bytes32 public constant FLASH_SUCCESS_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan");
File LinkInstance CountInstance Link
ERC3156FlashLender.sol111

File: packages/contracts/contracts/EBTCToken.sol

/// @audit also at packages/contracts/contracts/BorrowerOperations.sol:129
72:         bytes32 hashedVersion = keccak256(bytes(_VERSION));
File LinkInstance CountInstance Link
EBTCToken.sol172

File: packages/contracts/contracts/LeverageMacroBase.sol

/// @audit also at packages/contracts/contracts/Dependencies/ERC3156FlashLender.sol:11
37:     bytes32 constant FLASH_LOAN_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");
File LinkInstance CountInstance Link
LeverageMacroBase.sol137

<a id="g-11"></a> [G-11] Multiplication by powers of two should use bit shifting

Note: This issue was listed in the automated findings output; however, additional instances of the issue are listed here.

Description:

When multiplying a number by two and powers of two, use shift left instead of multiplication. Shifting left by N is the same as multiplying by 2^N. Examples:<br/>uint256 b = a * 2; --> uint256 b = a << 1;<br/>uint256 c = a * 4; --> uint256 c = a << 2;<br/>Using shift left instead of multiplication will save 112 gas.

Instances:

There is 1 instance of this issue.

File: packages/contracts/contracts/PriceFeed.sol

804:                 EbtcMath.DECIMAL_PRECISION) / 10 ** (_decimalDenominator * 2);
File LinkInstance CountInstance Link
PriceFeed.sol1804

<a id="g-12"></a> [G-12] Nesting if-statements is cheaper than using &&
Description:

Nesting if-statements avoids the stack operations of setting up and using an extra jumpdest, and saves 6 gas.

Instances:

There are 14 instances of this issue.

<details><summary>View 14 Instances</summary>
File: packages/contracts/contracts/BorrowerOperations.sol

393:         if (!_isDebtIncrease && _debtChange > 0) {
394:             _requireValidDebtRepayment(vars.debt, vars.netDebtChange);
395:             _requireSufficientEbtcTokenBalance(msg.sender, vars.netDebtChange);
396:             _requireNonZeroDebt(vars.debt - vars.netDebtChange);
397:         }
File LinkInstance CountInstance Link
BorrowerOperations.sol1393

File: packages/contracts/contracts/CdpManagerStorage.sol

512:         if (_newIndex > _oldIndex && totalStakes > 0) {
513:             (
514:                 uint256 _feeTaken,
515:                 uint256 _newFeePerUnit,
516:                 uint256 _perUnitError
517:             ) = _calcSyncedGlobalAccounting(_newIndex, _oldIndex);
518:             _takeSplitAndUpdateFeePerUnit(_feeTaken, _newFeePerUnit, _perUnitError);
519:             _updateSystemSnapshotsExcludeCollRemainder(0);
520:         }

796:         if (_cdpPerUnitIdx != _systemStEthFeePerUnitIndex && _cdpPerUnitIdx > 0) {
797:             (
798:                 uint256 _feeSplitDistributed,
799:                 uint256 _newCollShareAfter
800:             ) = getAccumulatedFeeSplitApplied(_cdpId, _systemStEthFeePerUnitIndex);
801:             _feeSplitApplied = _feeSplitDistributed;
802:             _newCollShare = _newCollShareAfter;
803:         }
File LinkInstance CountInstance Links
CdpManagerStorage.sol2512,796

File: packages/contracts/contracts/LiquidationLibrary.sol

157:             if (
158:                 liquidationValues.totalCollToSendToLiquidator == 0 &&
159:                 liquidationValues.debtToBurn == 0
160:             ) {
161:                 // retry with fully liquidation
162:                 (
163:                     liquidationValues.debtToBurn,
164:                     liquidationValues.totalCollToSendToLiquidator,
165:                     liquidationValues.debtToRedistribute,
166:                     liquidationValues.liquidatorCollSharesReward,
167:                     liquidationValues.collSurplus
168:                 ) = _liquidateCdpInGivenMode(_liqState, _recoveryState);
169:             }

756:             if (vars.cdpId != bytes32(0) && Cdps[vars.cdpId].status == Status.active) {
757:                 vars.ICR = getSyncedICR(vars.cdpId, _price);
758:
759:                 if (
760:                     !vars.backToNormalMode &&
761:                     (_checkICRAgainstMCR(vars.ICR) || canLiquidateRecoveryMode(vars.ICR, _TCR))
762:                 ) {
763:                     vars.price = _price;
764:                     _syncAccounting(vars.cdpId);
765:                     _getLiquidationValuesRecoveryMode(
766:                         _price,
767:                         vars.entireSystemDebt,
768:                         vars.entireSystemColl,
769:                         vars,
770:                         singleLiquidation
771:                     );
772:
773:                     // Update aggregate trackers
774:                     vars.entireSystemDebt = vars.entireSystemDebt - singleLiquidation.debtToBurn;
775:                     vars.entireSystemColl =
776:                         vars.entireSystemColl -
777:                         singleLiquidation.totalCollToSendToLiquidator -
778:                         singleLiquidation.collSurplus;
779:
780:                     // Add liquidation values to their respective running totals
781:                     totals = _addLiquidationValuesToTotals(totals, singleLiquidation);
782:
783:                     _TCR = _computeTCRWithGivenSystemValues(
784:                         vars.entireSystemColl,
785:                         vars.entireSystemDebt,
786:                         _price
787:                     );
788:                     vars.backToNormalMode = _TCR < CCR ? false : true;
789:                     _liqFlags[vars.i] = true;
790:                 } else if (vars.backToNormalMode && _checkICRAgainstMCR(vars.ICR)) {
791:                     _syncAccounting(vars.cdpId);
792:                     _getLiquidationValuesNormalMode(_price, _TCR, vars, singleLiquidation);
793:
794:                     // Add liquidation values to their respective running totals
795:                     totals = _addLiquidationValuesToTotals(totals, singleLiquidation);
796:                     _liqFlags[vars.i] = true;
797:                 }
798:                 // In Normal Mode skip cdps with ICR >= MCR
799:             }

790:                 } else if (vars.backToNormalMode && _checkICRAgainstMCR(vars.ICR)) {
791:                     _syncAccounting(vars.cdpId);
792:                     _getLiquidationValuesNormalMode(_price, _TCR, vars, singleLiquidation);
793:
794:                     // Add liquidation values to their respective running totals
795:                     totals = _addLiquidationValuesToTotals(totals, singleLiquidation);
796:                     _liqFlags[vars.i] = true;
797:                 }

819:             if (vars.cdpId != bytes32(0) && Cdps[vars.cdpId].status == Status.active) {
820:                 vars.ICR = getSyncedICR(vars.cdpId, _price);
821:
822:                 if (_checkICRAgainstMCR(vars.ICR)) {
823:                     _syncAccounting(vars.cdpId);
824:                     _getLiquidationValuesNormalMode(_price, _TCR, vars, singleLiquidation);
825:
826:                     // Add liquidation values to their respective running totals
827:                     totals = _addLiquidationValuesToTotals(totals, singleLiquidation);
828:                 }
829:             }
File LinkInstance CountInstance Links
LiquidationLibrary.sol4157,756,790,819

File: packages/contracts/contracts/PriceFeed.sol

226:                 if (
227:                     !_chainlinkIsBroken(chainlinkResponse, prevChainlinkResponse) &&
228:                     !_chainlinkIsFrozen(chainlinkResponse)
229:                 ) {
230:                     _changeStatus(Status.usingChainlinkFallbackUntrusted);
231:                     return _storeChainlinkPrice(chainlinkResponse.answer);
232:                 }

372:                 if (
373:                     !_fallbackIsBroken(fallbackResponse) &&
374:                     !_responseTimeout(fallbackResponse.timestamp, newFallbackCaler.fallbackTimeout())
375:                 ) {
376:                     address oldFallbackCaller = address(fallbackCaller);
377:                     fallbackCaller = newFallbackCaler;
378:                     emit FallbackCallerChanged(oldFallbackCaller, _fallbackCaller);
379:                 }
File LinkInstance CountInstance Links
PriceFeed.sol2226,372

File: packages/contracts/contracts/SortedCdps.sol

202:             if (maxNodes > 0 && i >= maxNodes) {
203:                 break;
204:             }

259:             if (maxNodes > 0 && i >= maxNodes) {
260:                 break;
261:             }

330:             if (maxNodes > 0 && i >= maxNodes) {
331:                 break;
332:             }

621:         if (data.head == _startId && _NICR >= cdpManager.getCachedNominalICR(_startId)) {
622:             return (dummyId, _startId);
623:         }

644:         if (data.tail == _startId && _NICR <= cdpManager.getCachedNominalICR(_startId)) {
645:             return (_startId, dummyId);
646:         }
File LinkInstance CountInstance Links
SortedCdps.sol5202,259,330,621,644

</details>
<a id="g-13"></a> [G-13] Optimize names to save gas
Description:

public and external function names and public member variable names can be optimized to save gas. The contracts listed below can be optimized so that the most frequently called functions use the least amount of gas possible during the Method ID lookup. Method IDs that have two leading zero bytes can save 128 gas each during deployment. Renaming functions to have lower Method IDs will save 22 gas per call, per sorted position shifted.

Recommendation:

Use a tool like Solidity Optimize Name to find names that will generate Method IDs that will prioritize the most used functions.

Instances:

There are 26 instances of this issue.

<details><summary>View 26 Instances</summary>
File: packages/contracts/contracts/ActivePool.sol

/// @audit sweepToken(), setFeeRecipientAddress(), setFeeBps(), setFlashLoansPaused()
22: contract ActivePool is IActivePool, ERC3156FlashLender, ReentrancyGuard, BaseMath, AuthNoOwner {
File LinkInstance CountInstance Link
ActivePool.sol122

File: packages/contracts/contracts/BorrowerOperations.sol

/// @audit DOMAIN_SEPARATOR(), setFeeRecipientAddress(), setFeeBps(), setFlashLoansPaused()
21: contract BorrowerOperations is
22:     EbtcBase,
23:     ReentrancyGuard,
24:     IBorrowerOperations,
25:     ERC3156FlashLender,
26:     AuthNoOwner,
27:     PermitNonce
28: {
File LinkInstance CountInstance Link
BorrowerOperations.sol121

File: packages/contracts/contracts/CdpManager.sol

/// @audit getSystemDebt(), getDeploymentStartTime(), checkPotentialRecoveryMode(), setStakingRewardSplit(), setRedemptionFeeFloor(), setMinuteDecayFactor(), setBeta(), setRedemptionsPaused(), initializeCdp(), updateCdp()
16: contract CdpManager is CdpManagerStorage, ICdpManager, Proxy {
File LinkInstance CountInstance Link
CdpManager.sol116

File: packages/contracts/contracts/CdpManagerStorage.sol

/// @audit notifyStartGracePeriod(), notifyEndGracePeriod(), setGracePeriod(), syncGlobalAccounting(), syncGlobalAccountingAndGracePeriod(), calcFeeUponStakingReward(), getAccumulatedFeeSplitApplied(), getCachedNominalICR(), getSyncedNominalICR(), getCachedICR(), getPendingRedistributedDebt(), hasPendingRedistributedDebt(), getSyncedDebtAndCollShares(), getSyncedCdpDebt(), getSyncedCdpCollShares(), getSyncedICR(), getSyncedTCR(), canLiquidateRecoveryMode()
19: contract CdpManagerStorage is EbtcBase, ReentrancyGuard, ICdpManagerData, AuthNoOwner {
File LinkInstance CountInstance Link
CdpManagerStorage.sol119

File: packages/contracts/contracts/Dependencies/AuthNoOwner.sol

/// @audit authority(), authorityInitialized(), setAuthority()
10: contract AuthNoOwner {
File LinkInstance CountInstance Link
AuthNoOwner.sol110

File: packages/contracts/contracts/Dependencies/RolesAuthority.sol

/// @audit doesUserHaveRole(), doesRoleHaveCapability(), isPublicCapability(), setPublicCapability(), setRoleCapability(), burnCapability(), setUserRole()
12: contract RolesAuthority is IRolesAuthority, Auth, Authority {
File LinkInstance CountInstance Link
RolesAuthority.sol112

File: packages/contracts/contracts/EBTCToken.sol

/// @audit burn(), DOMAIN_SEPARATOR()
26: contract EBTCToken is IEBTCToken, AuthNoOwner, PermitNonce {
File LinkInstance CountInstance Link
EBTCToken.sol126

File: packages/contracts/contracts/Governor.sol

/// @audit getUsersByRole(), getRolesForUser(), getRolesFromByteMap(), getByteMapFromRoles(), getEnabledFunctionsInTarget(), getRoleName(), setRoleName()
13: contract Governor is RolesAuthority {
File LinkInstance CountInstance Link
Governor.sol113

File: packages/contracts/contracts/HintHelpers.sol

/// @audit getRedemptionHints(), getApproxHint(), computeNominalCR(), computeCR()
11: contract HintHelpers is EbtcBase {
File LinkInstance CountInstance Link
HintHelpers.sol111

File: packages/contracts/contracts/Interfaces/IActivePool.sol

/// @audit transferSystemCollShares(), increaseSystemCollShares(), transferSystemCollSharesAndLiquidatorReward(), allocateSystemCollSharesToFeeRecipient(), claimFeeRecipientCollShares(), feeRecipientAddress(), getFeeRecipientClaimableCollShares(), setFeeRecipientAddress()
7: interface IActivePool is IPool {
File LinkInstance CountInstance Link
IActivePool.sol17

File: packages/contracts/contracts/Interfaces/IBorrowerOperations.sol

/// @audit openCdp(), openCdpFor(), addColl(), withdrawColl(), withdrawDebt(), repayDebt(), closeCdp(), adjustCdp(), adjustCdpWithColl(), claimSurplusCollShares(), feeRecipientAddress()
7: interface IBorrowerOperations is IPositionManagers {
File LinkInstance CountInstance Link
IBorrowerOperations.sol17

File: packages/contracts/contracts/Interfaces/ICdpManager.sol

/// @audit getActiveCdpsCount(), getIdFromCdpIdsArray(), liquidate(), partiallyLiquidate(), batchLiquidateCdps(), redeemCollateral(), updateStakeAndTotalStakes(), syncAccounting(), closeCdp(), getRedemptionRate(), getRedemptionRateWithDecay(), getRedemptionFeeWithDecay(), getCdpStatus(), getCdpStake(), getCdpDebt(), getCdpCollShares(), getCdpLiquidatorRewardShares(), initializeCdp(), updateCdp(), getCachedTCR(), checkRecoveryMode()
9: interface ICdpManager is IEbtcBase, ICdpManagerData {
File LinkInstance CountInstance Link
ICdpManager.sol19

File: packages/contracts/contracts/Interfaces/ICdpManagerData.sol

/// @audit totalStakes(), ebtcToken(), systemStEthFeePerUnitIndex(), systemStEthFeePerUnitIndexError(), stEthIndex(), calcFeeUponStakingReward(), syncGlobalAccounting(), syncGlobalAccountingAndGracePeriod(), getAccumulatedFeeSplitApplied(), getCachedNominalICR(), getCachedICR(), getSyncedCdpDebt(), getSyncedCdpCollShares(), getSyncedICR(), getSyncedTCR(), getSyncedNominalICR(), getPendingRedistributedDebt(), hasPendingRedistributedDebt(), getSyncedDebtAndCollShares(), canLiquidateRecoveryMode()
13: interface ICdpManagerData is IRecoveryModeGracePeriod {
File LinkInstance CountInstance Link
ICdpManagerData.sol113

File: packages/contracts/contracts/Interfaces/ICollSurplusPool.sol

/// @audit getTotalSurplusCollShares(), getSurplusCollShares(), increaseSurplusCollShares(), claimSurplusCollShares(), increaseTotalSurplusCollShares()
5: interface ICollSurplusPool {
File LinkInstance CountInstance Link
ICollSurplusPool.sol15

File: packages/contracts/contracts/Interfaces/IEBTCToken.sol

/// @audit mint(), burn()
8: interface IEBTCToken is IERC20, IERC2612 {
File LinkInstance CountInstance Link
IEBTCToken.sol18

File: packages/contracts/contracts/Interfaces/IERC3156FlashLender.sol

/// @audit maxFlashLoan(), flashFee(), flashLoan()
7: interface IERC3156FlashLender {
File LinkInstance CountInstance Link
IERC3156FlashLender.sol17

File: packages/contracts/contracts/Interfaces/IFallbackCaller.sol

/// @audit getFallbackResponse(), fallbackTimeout(), setFallbackTimeout()
5: interface IFallbackCaller {
File LinkInstance CountInstance Link
IFallbackCaller.sol15

File: packages/contracts/contracts/Interfaces/IPermitNonce.sol

/// @audit increasePermitNonce(), nonces()
5: interface IPermitNonce {
File LinkInstance CountInstance Link
IPermitNonce.sol15

File: packages/contracts/contracts/Interfaces/IPool.sol

/// @audit getSystemCollShares(), getSystemDebt(), increaseSystemDebt(), decreaseSystemDebt()
6: interface IPool {
File LinkInstance CountInstance Link
IPool.sol16

File: packages/contracts/contracts/Interfaces/IPositionManagers.sol

/// @audit getPositionManagerApproval(), setPositionManagerApproval(), revokePositionManagerApproval(), renouncePositionManagerApproval(), permitPositionManagerApproval(), version(), permitTypeHash(), domainSeparator()
5: interface IPositionManagers {
File LinkInstance CountInstance Link
IPositionManagers.sol15

File: packages/contracts/contracts/Interfaces/IRecoveryModeGracePeriod.sol

/// @audit notifyStartGracePeriod(), notifyEndGracePeriod()
5: interface IRecoveryModeGracePeriod {
File LinkInstance CountInstance Link
IRecoveryModeGracePeriod.sol15

File: packages/contracts/contracts/Interfaces/ISortedCdps.sol

/// @audit remove(), batchRemove(), reInsert(), contains(), isFull(), isEmpty(), getSize(), getMaxSize(), getFirst(), getLast(), getNext(), getPrev(), validInsertPosition(), findInsertPosition(), insert(), getOwnerAddress(), nonExistId(), cdpCountOf(), getCdpCountOf(), getCdpsOf(), getAllCdpsOf(), cdpOfOwnerByIndex(), cdpOfOwnerByIdx()
6: interface ISortedCdps {
File LinkInstance CountInstance Link
ISortedCdps.sol16

File: packages/contracts/contracts/LeverageMacroBase.sol

/// @audit owner(), doOperation(), sweepToCaller(), sweepToken(), decodeFLData(), onFlashLoan()
26: contract LeverageMacroBase {
File LinkInstance CountInstance Link
LeverageMacroBase.sol126

File: packages/contracts/contracts/LeverageMacroFactory.sol

/// @audit deployNewMacro(), deployNewMacro()
11: contract LeverageMacroFactory {
File LinkInstance CountInstance Link
LeverageMacroFactory.sol111

File: packages/contracts/contracts/LiquidationLibrary.sol

/// @audit liquidate(), partiallyLiquidate(), batchLiquidateCdps()
13: contract LiquidationLibrary is CdpManagerStorage {
File LinkInstance CountInstance Link
LiquidationLibrary.sol113

File: packages/contracts/contracts/SimplifiedDiamondLike.sol

/// @audit setFallbackHandler(), setAllowAnyCall(), enableCallbackForCall(), execute()
25: contract SimplifiedDiamondLike {
File LinkInstance CountInstance Link
SimplifiedDiamondLike.sol125

</details>
<a id="g-14"></a> [G-14] Remove unused local variable
Instances:

There are 4 instances of this issue.

File: packages/contracts/contracts/CdpManager.sol

922:         uint256 index = _addCdpIdToArray(_cdpId);
File LinkInstance CountInstance Link
CdpManager.sol1922

File: packages/contracts/contracts/CdpManagerStorage.sol

357:             uint _pendingDebt,

687:         (uint256 _newColl, uint256 _newDebt, , uint256 _pendingDebt, ) = _calcSyncedAccounting(
File LinkInstance CountInstance Links
CdpManagerStorage.sol2357,687

File: packages/contracts/contracts/LeverageMacroBase.sol

465:         bytes32 _cdpId = borrowerOperations.openCdp(
File LinkInstance CountInstance Link
LeverageMacroBase.sol1465

<a id="g-15"></a> [G-15] require()/revert() strings longer than 32 bytes cost extra gas

Note: This issue was listed in the automated findings output; however, additional instances of the issue are listed here.

Description:

Shortening revert strings to fit in 32 bytes will decrease deploy-time gas and will decrease runtime gas when the revert condition has been met. Revert strings that are longer than 32 bytes require at least one additional mstore (3 gas), along with additional overhead for computing memory offset, etc. (When using Solidity 0.8.4 or later, it is recommended to use custom errors instead.)

Instances:

There are 115 instances of this issue.

<details><summary>View 115 Instances</summary>
File: packages/contracts/contracts/ActivePool.sol

137:         require(cachedSystemCollShares >= _shares, "ActivePool: Insufficient collateral shares");

162:         require(cachedSystemCollShares >= _shares, "ActivePool: Insufficient collateral shares");

220:         require(
221:             msg.sender == borrowerOperationsAddress,
222:             "ActivePool: Caller is not BorrowerOperations"
223:         );

228:         require(
229:             msg.sender == borrowerOperationsAddress || msg.sender == cdpManagerAddress,
230:             "ActivePool: Caller is neither BorrowerOperations nor CdpManager"
231:         );

236:         require(msg.sender == cdpManagerAddress, "ActivePool: Caller is not CdpManager");

277:         require(
278:             receiver.onFlashLoan(msg.sender, token, amount, fee, data) == FLASH_SUCCESS_VALUE,
279:             "ActivePool: IERC3156: Callback failed"
280:         );

302:         require(
303:             collateral.getPooledEthByShares(DECIMAL_PRECISION) == oldRate,
304:             "ActivePool: Should keep same collateral share rate"
305:         );

350:         require(
351:             cachedFeeRecipientCollShares >= _shares,
352:             "ActivePool: Insufficient fee recipient coll"
353:         );

374:         require(token != address(collateral), "ActivePool: Cannot Sweep Collateral");

377:         require(amount <= balance, "ActivePool: Attempt to sweep more than balance");

393:         require(
394:             _feeRecipientAddress != address(0),
395:             "ActivePool: Cannot set fee recipient to zero address"
396:         );

407:         require(_newFee <= MAX_FEE_BPS, "ERC3156FlashLender: _newFee should <= MAX_FEE_BPS");
File LinkInstance CountInstance Links
ActivePool.sol12137,162,220,228,236,277,302,350,374,377,393,407

File: packages/contracts/contracts/BorrowerOperations.sol

145:         require(locked == OPEN, "BorrowerOperations: Reentrancy in nonReentrant call");

146:         require(
147:             ReentrancyGuard(address(cdpManager)).locked() == OPEN,
148:             "CdpManager: Reentrancy in nonReentrant call"
149:         );

368:         require(
369:             _stEthBalanceDecrease <= _cdpStEthBalance,
370:             "BorrowerOperations: Cannot withdraw greater stEthBalance than the value in Cdp"
371:         );

463:         require(vars.netStEthBalance > 0, "BorrowerOperations: zero collateral for openCdp()!");

541:         require(
542:             vars.netStEthBalance + LIQUIDATOR_REWARD == _stEthBalance,
543:             "BorrowerOperations: deposited collateral mismatch!"
544:         );

715:         require(_deadline >= block.timestamp, "BorrowerOperations: Position manager permit expired");

734:         require(
735:             recoveredAddress != address(0) && recoveredAddress == _borrower,
736:             "BorrowerOperations: Invalid signature"
737:         );

807:         require(
808:             _stEthBalanceIncrease == 0 || _stEthBalanceDecrease == 0,
809:             "BorrowerOperations: Cannot add and withdraw collateral in same operation"
810:         );

818:         require(
819:             _stEthBalanceIncrease != 0 || _stEthBalanceDecrease != 0 || _debtChange != 0,
820:             "BorrowerOperations: There must be either a collateral change or a debt change"
821:         );

826:         require(status == 1, "BorrowerOperations: Cdp does not exist or is closed");

831:         require(status == 0, "BorrowerOperations: Cdp is active or has been previously closed");

835:         require(_debtChange > 0, "BorrowerOperations: Debt increase requires non-zero debtChange");

839:         require(
840:             !_checkRecoveryModeForTCR(_tcr),
841:             "BorrowerOperations: Operation not permitted during Recovery Mode"
842:         );

846:         require(
847:             _stEthBalanceDecrease == 0,
848:             "BorrowerOperations: Collateral withdrawal not permitted during Recovery Mode"
849:         );

911:         require(
912:             _newICR >= MCR,
913:             "BorrowerOperations: An operation that would result in ICR < MCR is not permitted"
914:         );

918:         require(_newICR >= CCR, "BorrowerOperations: Operation must leave cdp with ICR >= CCR");

922:         require(
923:             _newICR >= _oldICR,
924:             "BorrowerOperations: Cannot decrease your Cdp's ICR in Recovery Mode"
925:         );

929:         require(
930:             _newTCR >= CCR,
931:             "BorrowerOperations: An operation that would result in TCR < CCR is not permitted"
932:         );

936:         require(_debt > 0, "BorrowerOperations: Debt must be non-zero");

940:         require(
941:             _stEthBalance >= MIN_NET_STETH_BALANCE,
942:             "BorrowerOperations: Cdp's net stEth balance must not fall below minimum"
943:         );

947:         require(
948:             _debtRepayment <= _currentDebt,
949:             "BorrowerOperations: Amount repaid must not be larger than the Cdp's debt"
950:         );

957:         require(
958:             ebtcToken.balanceOf(_account) >= _debtRepayment,
959:             "BorrowerOperations: Caller doesnt have enough eBTC to make repayment"
960:         );

970:         require(
971:             _approval != PositionManagerApproval.None,
972:             "BorrowerOperations: Only borrower account or approved position manager can OpenCdp on borrower's behalf"
973:         );

1116:         require(!flashLoansPaused, "BorrowerOperations: Flash Loans Paused");

1141:         require(
1142:             _feeRecipientAddress != address(0),
1143:             "BorrowerOperations: Cannot set feeRecipient to zero address"
1144:         );

1155:         require(_newFee <= MAX_FEE_BPS, "ERC3156FlashLender: _newFee should <= MAX_FEE_BPS");

File: packages/contracts/contracts/CdpManager.sol

431:         require(totals.collSharesDrawn > 0, "CdpManager: Unable to redeem any amount");

502:         require(_toRemoveIds[0] == _start, "CdpManager: batchRemoveSortedCdpIds check start error");

503:         require(
504:             _toRemoveIds[_total - 1] == _end,
505:             "CdpManager: batchRemoveSortedCdpIds check end error"
506:         );

626:         require(newBaseRate > 0, "CdpManager: new baseRate is zero!"); // Base rate is always non-zero after redemption

672:         require(redemptionFee < _ETHDrawn, "CdpManager: Fee would eat up all returned collateral");

743:         require(
744:             callerBalance >= _amount,
745:             "CdpManager: Requested redemption amount must be <= user's EBTC token balance"
746:         );

747:         require(
748:             callerBalance <= _totalSupply,
749:             "CdpManager: redeemer's EBTC balance exceeds total supply!"
750:         );

754:         require(_amount > 0, "CdpManager: Amount must be greater than zero");

758:         require(_TCR >= MCR, "CdpManager: Cannot redeem when TCR < MCR");

762:         require(
763:             _maxFeePercentage >= redemptionFeeFloor && _maxFeePercentage <= DECIMAL_PRECISION,
764:             "Max fee percentage must be between redemption fee floor and 100%"
765:         );

774:         require(
775:             _stakingRewardSplit <= MAX_REWARD_SPLIT,
776:             "CDPManager: new staking reward split exceeds max"
777:         );

789:         require(
790:             _redemptionFeeFloor >= MIN_REDEMPTION_FEE_FLOOR,
791:             "CDPManager: new redemption fee floor is lower than minimum"
792:         );

793:         require(
794:             _redemptionFeeFloor <= DECIMAL_PRECISION,
795:             "CDPManager: new redemption fee floor is higher than maximum"
796:         );

808:         require(
809:             _minuteDecayFactor >= MIN_MINUTE_DECAY_FACTOR,
810:             "CDPManager: new minute decay factor out of range"
811:         );

812:         require(
813:             _minuteDecayFactor <= MAX_MINUTE_DECAY_FACTOR,
814:             "CDPManager: new minute decay factor out of range"
815:         );
File LinkInstance CountInstance Links
CdpManager.sol15431,502,503,626,672,743,747,754,758,762,774,789,793,808,812

File: packages/contracts/contracts/CdpManagerStorage.sol

112:         require(
113:             _gracePeriod >= MINIMUM_GRACE_PERIOD,
114:             "CdpManager: Grace period below minimum duration"
115:         );

242:         require(locked == OPEN, "CdpManager: Reentrancy in nonReentrant call");

243:         require(
244:             ReentrancyGuard(borrowerOperationsAddress).locked() == OPEN,
245:             "BorrowerOperations: Reentrancy in nonReentrant call"
246:         );

261:         require(
262:             closedStatus != Status.nonExistent && closedStatus != Status.active,
263:             "CdpManagerStorage: close non-exist or non-active CDP!"
264:         );

453:             require(totalStakesSnapshot > 0, "CdpManagerStorage: zero totalStakesSnapshot!");

466:         require(
467:             cdpStatus != Status.nonExistent && cdpStatus != Status.active,
468:             "CdpManagerStorage: remove non-exist or non-active CDP!"
469:         );

475:         require(index <= idxLast, "CdpManagerStorage: CDP indexing overflow!");

556:         require(_newIndex > _prevIndex, "CDPManager: only take fee with bigger new index");

649:         require(Cdps[_cdpId].status == Status.active, "CdpManager: Cdp does not exist or is closed");

653:         require(
654:             CdpOwnersArrayLength > 1 && sortedCdps.getSize() > 1,
655:             "CdpManager: Only one cdp in the system"
656:         );

660:         require(
661:             msg.sender == borrowerOperationsAddress,
662:             "CdpManager: Caller is not the BorrowerOperations contract"
663:         );
File LinkInstance CountInstance Links
CdpManagerStorage.sol11112,242,243,261,453,466,475,556,649,653,660

File: packages/contracts/contracts/CollSurplusPool.sol

92:         require(claimableColl > 0, "CollSurplusPool: No collateral available to claim");

113:         require(
114:             msg.sender == borrowerOperationsAddress,
115:             "CollSurplusPool: Caller is not Borrower Operations"
116:         );

120:         require(msg.sender == cdpManagerAddress, "CollSurplusPool: Caller is not CdpManager");

124:         require(msg.sender == activePoolAddress, "CollSurplusPool: Caller is not Active Pool");

143:         require(token != address(collateral), "CollSurplusPool: Cannot Sweep Collateral");

146:         require(amount <= balance, "CollSurplusPool: Attempt to sweep more than balance");
File LinkInstance CountInstance Links
CollSurplusPool.sol692,113,120,124,143,146

File: packages/contracts/contracts/Dependencies/AuthNoOwner.sol

57:         require(!_authorityInitialized, "Auth: authority already initialized");
File LinkInstance CountInstance Link
AuthNoOwner.sol157

File: packages/contracts/contracts/Dependencies/ReentrancyGuard.sol

14:         require(locked == OPEN, "ReentrancyGuard: Reentrancy in nonReentrant call");
File LinkInstance CountInstance Link
ReentrancyGuard.sol114

File: packages/contracts/contracts/Dependencies/RolesAuthority.sol

90:         require(
91:             capabilityFlag[target][functionSig] != CapabilityFlag.Burned,
92:             "RolesAuthority: Capability Burned"
93:         );

134:         require(
135:             capabilityFlag[target][functionSig] != CapabilityFlag.Burned,
136:             "RolesAuthority: Capability Burned"
137:         );
File LinkInstance CountInstance Links
RolesAuthority.sol290,134

File: packages/contracts/contracts/EBTCToken.sol

144:             require(cachedAllowance >= amount, "ERC20: transfer amount exceeds allowance");

165:         require(cachedAllowances >= subtractedValue, "ERC20: decreased allowance below zero");

251:         require(cachedSenderBalances >= amount, "ERC20: transfer amount exceeds balance");

263:         require(account != address(0), "EBTCToken: mint to zero recipient!");

271:         require(account != address(0), "EBTCToken: burn from zero account!");

274:         require(cachedBalance >= amount, "ERC20: burn amount exceeds balance");

296:         require(
297:             _recipient != address(0) && _recipient != address(this),
298:             "EBTC: Cannot transfer tokens directly to the EBTC token contract or the zero address"
299:         );

300:         require(
301:             _recipient != cdpManagerAddress && _recipient != borrowerOperationsAddress,
302:             "EBTC: Cannot transfer tokens directly to the CdpManager or BorrowerOps"
303:         );

307:         require(
308:             msg.sender == borrowerOperationsAddress,
309:             "EBTCToken: Caller is not BorrowerOperations"
310:         );

315:         require(
316:             msg.sender == borrowerOperationsAddress ||
317:                 msg.sender == cdpManagerAddress ||
318:                 isAuthorized(msg.sender, msg.sig),
319:             "EBTC: Caller is neither BorrowerOperations nor CdpManager nor authorized"
320:         );
File LinkInstance CountInstance Links
EBTCToken.sol10144,165,251,263,271,274,296,300,307,315

File: packages/contracts/contracts/LeverageMacroBase.sol

179:             require(
180:                 cdpInfo.status == checkParams.expectedStatus,
181:                 "!LeverageMacroReference: openCDP status check"
182:             );

191:             require(
192:                 cdpInfo.status == checkParams.expectedStatus,
193:                 "!LeverageMacroReference: adjustCDP status check"
194:             );

201:             require(
202:                 cdpInfo.status == checkParams.expectedStatus,
203:                 "!LeverageMacroReference: closeCDP status check"
204:             );

249:             require(check.value >= valueToCheck, "!LeverageMacroReference: gte post check");

251:             require(check.value <= valueToCheck, "!LeverageMacroReference: let post check");

253:             require(check.value == valueToCheck, "!LeverageMacroReference: equal post check");

352:         require(initiator == address(this), "LeverageMacroReference: wrong initiator for flashloan");

356:             require(
357:                 msg.sender == address(borrowerOperations),
358:                 "LeverageMacroReference: wrong lender for eBTC flashloan"
359:             );

362:             require(
363:                 msg.sender == address(activePool),
364:                 "LeverageMacroReference: wrong lender for stETH flashloan"
365:             );

440:                 require(
441:                     IERC20(swapChecks[i].tokenToCheck).balanceOf(address(this)) >
442:                         swapChecks[i].expectedMinOut,
443:                     "LeverageMacroReference: swap check failure!"
444:                 );
File LinkInstance CountInstance Links
LeverageMacroBase.sol10179,191,201,249,251,253,352,356,362,440

File: packages/contracts/contracts/LiquidationLibrary.sol

56:         require(_partialAmount != 0, "LiquidationLibrary: use `liquidate` for 100%");

82:             require(
83:                 _checkICRAgainstLiqThreshold(_ICR, _TCR),
84:                 "LiquidationLibrary: ICR is not below liquidation threshold in current mode"
85:             );

89:             require(
90:                 cachedLastGracePeriodStartTimestamp != UNSET_TIMESTAMP,
91:                 "LiquidationLibrary: Recovery Mode grace period not started"
92:             );

93:             require(
94:                 block.timestamp >
95:                     cachedLastGracePeriodStartTimestamp + recoveryModeGracePeriodDuration,
96:                 "LiquidationLibrary: Recovery mode grace period still in effect"
97:             );

477:             require(
478:                 getCachedICR(_cdpId, _partialState.price) >= _partialState.ICR,
479:                 "LiquidationLibrary: !_newICR>=_ICR"
480:             );

680:         require(
681:             _cdpArray.length != 0,
682:             "LiquidationLibrary: Calldata address array must not be empty"
683:         );

710:         require(totals.totalDebtInSequence > 0, "LiquidationLibrary: nothing to liquidate");

901:         require(
902:             (_partialDebt + _convertDebtDenominationToBtc(MIN_NET_STETH_BALANCE, _price)) <=
903:                 _entireDebt,
904:             "LiquidationLibrary: Partial debt liquidated must be less than total debt"
905:         );

909:         require(
910:             _entireColl >= MIN_NET_STETH_BALANCE,
911:             "LiquidationLibrary: Coll remaining in partially liquidated CDP must be >= minimum"
912:         );
File LinkInstance CountInstance Links
LiquidationLibrary.sol956,82,89,93,477,680,710,901,909

File: packages/contracts/contracts/PriceFeed.sol

79:         require(
80:             !_chainlinkIsBroken(chainlinkResponse, prevChainlinkResponse) &&
81:                 !_chainlinkIsFrozen(chainlinkResponse),
82:             "PriceFeed: Chainlink must be working and current"
83:         );
File LinkInstance CountInstance Link
PriceFeed.sol179

File: packages/contracts/contracts/SortedCdps.sol

352:         require(cdpManager.getCdpStatus(_id) == 0, "SortedCdps: new id is NOT nonExistent!");

367:         require(!contains(_id), "SortedCdps: List already contains the node");

371:         require(_NICR > 0, "SortedCdps: NICR must be positive");

422:         require(_len > 1, "SortedCdps: batchRemove() only apply to multiple cdpIds!");

427:         require(
428:             _firstPrev != dummyId || _lastNext != dummyId,
429:             "SortedCdps: batchRemove() leave ZERO node left!"
430:         );

433:             require(contains(_ids[i]), "SortedCdps: List does not contain the id");

458:         require(contains(_id), "SortedCdps: List does not contain the id");

506:         require(contains(_id), "SortedCdps: List does not contain the id");

508:         require(_newNICR > 0, "SortedCdps: NICR must be positive");

715:         require(msg.sender == address(cdpManager), "SortedCdps: Caller is not the CdpManager");

720:         require(
721:             msg.sender == borrowerOperationsAddress || msg.sender == address(cdpManager),
722:             "SortedCdps: Caller is neither BO nor CdpM"
723:         );
File LinkInstance CountInstance Links
SortedCdps.sol11352,367,371,422,427,433,458,506,508,715,720

</details>
<a id="g-16"></a> [G-16] Splitting require() statements that use && saves gas
Description:

Instead of using the && operator in a single require statement to check multiple conditions, using multiple require statements with 1 condition per require statement will save 3 GAS per &&.

Instances:

There are 8 instances of this issue.

<details><summary>View 8 Instances</summary>
File: packages/contracts/contracts/BorrowerOperations.sol

734:         require(
735:             recoveredAddress != address(0) && recoveredAddress == _borrower,
736:             "BorrowerOperations: Invalid signature"
737:         );
File LinkInstance CountInstance Link
BorrowerOperations.sol1734

File: packages/contracts/contracts/CdpManager.sol

762:         require(
763:             _maxFeePercentage >= redemptionFeeFloor && _maxFeePercentage <= DECIMAL_PRECISION,
764:             "Max fee percentage must be between redemption fee floor and 100%"
765:         );
File LinkInstance CountInstance Link
CdpManager.sol1762

File: packages/contracts/contracts/CdpManagerStorage.sol

261:         require(
262:             closedStatus != Status.nonExistent && closedStatus != Status.active,
263:             "CdpManagerStorage: close non-exist or non-active CDP!"
264:         );

466:         require(
467:             cdpStatus != Status.nonExistent && cdpStatus != Status.active,
468:             "CdpManagerStorage: remove non-exist or non-active CDP!"
469:         );

653:         require(
654:             CdpOwnersArrayLength > 1 && sortedCdps.getSize() > 1,
655:             "CdpManager: Only one cdp in the system"
656:         );
File LinkInstance CountInstance Links
CdpManagerStorage.sol3261,466,653

File: packages/contracts/contracts/EBTCToken.sol

296:         require(
297:             _recipient != address(0) && _recipient != address(this),
298:             "EBTC: Cannot transfer tokens directly to the EBTC token contract or the zero address"
299:         );

300:         require(
301:             _recipient != cdpManagerAddress && _recipient != borrowerOperationsAddress,
302:             "EBTC: Cannot transfer tokens directly to the CdpManager or BorrowerOps"
303:         );
File LinkInstance CountInstance Links
EBTCToken.sol2296,300

File: packages/contracts/contracts/PriceFeed.sol

79:         require(
80:             !_chainlinkIsBroken(chainlinkResponse, prevChainlinkResponse) &&
81:                 !_chainlinkIsFrozen(chainlinkResponse),
82:             "PriceFeed: Chainlink must be working and current"
83:         );
File LinkInstance CountInstance Link
PriceFeed.sol179

</details>
<a id="g-17"></a> [G-17] State variable read in a loop
Description:

State variables should be cached in a local variable rather than reading it them every iteration of the for-loop, which will replace each Gwarmaccess (100 gas) with a much cheaper stack read.

Instances:

There are 31 instances of this issue.

<details><summary>View 31 Instances</summary>
File: packages/contracts/contracts/CdpManager.sol

/// @audit MCR
369:             while (currentBorrower != address(0) && getSyncedICR(_cId, totals.price) < MCR) {

/// @audit sortedCdps
370:                 _cId = sortedCdps.getPrev(_cId);

/// @audit sortedCdps
371:                 currentBorrower = sortedCdps.getOwnerAddress(_cId);

/// @audit sortedCdps
500:             _id = sortedCdps.getNext(_id);
File LinkInstance CountInstance Links
CdpManager.sol4369,370,371,500

File: packages/contracts/contracts/Governor.sol

/// @audit users
46:         for (uint256 i = 0; i < users.length(); i++) {
File LinkInstance CountInstance Link
Governor.sol146

File: packages/contracts/contracts/HintHelpers.sol

/// @audit cdpManager, MCR
70:                 cdpManager.getSyncedICR(vars.currentCdpId, _price) < MCR

/// @audit sortedCdps
72:                 vars.currentCdpId = sortedCdps.getPrev(vars.currentCdpId);

/// @audit sortedCdps
73:                 vars.currentCdpUser = sortedCdps.getOwnerAddress(vars.currentCdpId);

/// @audit MIN_NET_STETH_BALANCE
101:                     if (
102:                         collateral.getPooledEthByShares(partialRedemptionNewColl) <
103:                         MIN_NET_STETH_BALANCE
104:                     ) {

/// @audit MIN_NET_STETH_BALANCE, collateral
102:                         collateral.getPooledEthByShares(partialRedemptionNewColl) <
103:                         MIN_NET_STETH_BALANCE

/// @audit sortedCdps
116:                 vars.currentCdpId = sortedCdps.getPrev(vars.currentCdpId);

/// @audit sortedCdps
117:                 vars.currentCdpUser = sortedCdps.getOwnerAddress(vars.currentCdpId);
File LinkInstance CountInstance Links
HintHelpers.sol770,72,73,101,102,116,117

File: packages/contracts/contracts/LiquidationLibrary.sol

/// @audit Cdps
756:             if (vars.cdpId != bytes32(0) && Cdps[vars.cdpId].status == Status.active) {

/// @audit Cdps
756:             if (vars.cdpId != bytes32(0) && Cdps[vars.cdpId].status == Status.active) {

/// @audit CCR
788:                     vars.backToNormalMode = _TCR < CCR ? false : true;

/// @audit CCR
788:                     vars.backToNormalMode = _TCR < CCR ? false : true;

/// @audit CCR
788:                     vars.backToNormalMode = _TCR < CCR ? false : true;

/// @audit Cdps
819:             if (vars.cdpId != bytes32(0) && Cdps[vars.cdpId].status == Status.active) {

/// @audit Cdps
819:             if (vars.cdpId != bytes32(0) && Cdps[vars.cdpId].status == Status.active) {
File LinkInstance CountInstance Links
LiquidationLibrary.sol7756,756,788,788,788,819,819

File: packages/contracts/contracts/SortedCdps.sol

/// @audit dummyId
185:         while (_currentCdpId != dummyId) {

/// @audit data
199:             _currentCdpId = data.nodes[_currentCdpId].prevId;

/// @audit dummyId
248:         while (_currentCdpId != dummyId) {

/// @audit data
256:             _currentCdpId = data.nodes[_currentCdpId].prevId;

/// @audit dummyId
318:         while (_currentCdpId != dummyId) {

/// @audit data
327:             _currentCdpId = data.nodes[_currentCdpId].prevId;

/// @audit dummyId
629:         while (prevId != dummyId && !_validInsertPosition(_NICR, prevId, nextId)) {

/// @audit data
630:             prevId = data.nodes[prevId].nextId;

/// @audit data
631:             nextId = data.nodes[prevId].nextId;

/// @audit dummyId
652:         while (nextId != dummyId && !_validInsertPosition(_NICR, prevId, nextId)) {

/// @audit data
653:             nextId = data.nodes[nextId].prevId;

/// @audit data
654:             prevId = data.nodes[nextId].prevId;
File LinkInstance CountInstance Links
SortedCdps.sol12185,199,248,256,318,327,629,630,631,652,653,654

</details>
<a id="g-18"></a> [G-18] The result of function calls should be cached rather than re-calling the function
Description:

The instances below point to the second+ call of the function within a single function.

Instances:

There is 1 instance of this issue.

File: packages/contracts/contracts/CdpManager.sol

/// @audit sortedCdps.nonExistId() on line 277
285:         return nextCdp == sortedCdps.nonExistId() || getSyncedICR(nextCdp, _price) < MCR;
File LinkInstance CountInstance Link
CdpManager.sol1285

<a id="g-19"></a> [G-19] unchecked {} can be used on the division of two uints in order to save gas
Description:

The division cannot overflow, since both the numerator and the denominator are non-negative. Using unchecked {} will save 20 gas per instance.

Instances:

There are 31 instances of this issue.

<details><summary>View 31 Instances</summary>
File: packages/contracts/contracts/ActivePool.sol

321:         return (amount * feeBps) / MAX_BPS;
File LinkInstance CountInstance Link
ActivePool.sol1321

File: packages/contracts/contracts/BorrowerOperations.sol

1118:         return (amount * feeBps) / MAX_BPS;
File LinkInstance CountInstance Link
BorrowerOperations.sol11118

File: packages/contracts/contracts/CdpManager.sol

146:             (singleRedemption.debtToRedeem * DECIMAL_PRECISION) / _redeemColFromCdp.price

621:         uint256 redeemedEBTCFraction = (collateral.getPooledEthByShares(_ETHDrawn) * _price) /
622:             _totalEBTCSupply;

624:         uint256 newBaseRate = decayedBaseRate + (redeemedEBTCFraction / beta);

671:         uint256 redemptionFee = (_redemptionRate * _ETHDrawn) / DECIMAL_PRECISION;

706:         return (baseRate * decayFactor) / DECIMAL_PRECISION;

712:                 ? ((block.timestamp - lastRedemptionTimestamp) / SECONDS_IN_ONE_MINUTE)
File LinkInstance CountInstance Links
CdpManager.sol6146,621,624,671,706,712

File: packages/contracts/contracts/CdpManagerStorage.sol

316:             pendingEBTCDebtReward = (cdp.stake * _debtIndexDiff) / DECIMAL_PRECISION;

454:             stake = (_coll * totalStakesSnapshot) / totalCollateralSnapshot;

558:         uint256 deltaIndexFees = (deltaIndex * stakingRewardSplit) / MAX_REWARD_SPLIT;

564:         uint256 _feeTaken = collateral.getSharesByPooledEth(_deltaFeeSplit) / DECIMAL_PRECISION;

567:         uint256 _deltaFeePerUnit = _deltaFeeSplitShare / _cachedAllStakes;

639:                 (_scaledCdpColl - _feeSplitDistributed) / DECIMAL_PRECISION
File LinkInstance CountInstance Links
CdpManagerStorage.sol6316,454,558,564,567,639

File: packages/contracts/contracts/Dependencies/EbtcBase.sol

108:         uint256 feePercentage = (_fee * DECIMAL_PRECISION) / _amount;

119:         return (_debt * _price) / DECIMAL_PRECISION;
File LinkInstance CountInstance Links
EbtcBase.sol2108,119

File: packages/contracts/contracts/Dependencies/EbtcMath.sol

38:         decProd = (prod_xy + (DECIMAL_PRECISION / 2)) / DECIMAL_PRECISION;

94:             return (_collShares * NICR_PRECISION) / _debt;

110:             uint256 newCollRatio = (_stEthBalance * _price) / _debt;
File LinkInstance CountInstance Links
EbtcMath.sol338,94,110

File: packages/contracts/contracts/HintHelpers.sol

145:             (maxRedeemableEBTC * DECIMAL_PRECISION) / _price
File LinkInstance CountInstance Link
HintHelpers.sol1145

File: packages/contracts/contracts/LiquidationLibrary.sol

278:         uint _debtToColl = (_totalDebtToBurn * DECIMAL_PRECISION) / _liqState.price;

365:         uint _debtToColl = (_totalDebtToBurn * DECIMAL_PRECISION) / _recoveryState.price;

435:             uint _debtToColl = (_partialDebt * DECIMAL_PRECISION) / _partialState.price;

555:             _incentiveColl = (_totalDebtToBurn * (_ICR > MCR ? MCR : _ICR)) / _price;

558:             _incentiveColl = (_totalDebtToBurn * LICR) / _price;

579:             _incentiveColl = (_totalDebtToBurn * (_ICR > MCR ? MCR : _ICR)) / _price;

592:             uint256 _debtToRepay = (_incentiveColl * _price) / LICR;

882:         uint256 EBTCDebtRewardPerUnitStaked = EBTCDebtNumerator / _totalStakes;
File LinkInstance CountInstance Links
LiquidationLibrary.sol8278,365,435,555,558,579,592,882

File: packages/contracts/contracts/PriceFeed.sol

458:             ? ((maxPrice - minPrice) * EbtcMath.DECIMAL_PRECISION) / maxPrice

534:         uint256 percentPriceDifference = ((maxPrice - minPrice) * EbtcMath.DECIMAL_PRECISION) /
535:             minPrice;

801:             (_scaledDecimal *
802:                 uint256(_ethBtcAnswer) *
803:                 uint256(_stEthEthAnswer) *
804:                 EbtcMath.DECIMAL_PRECISION) / 10 ** (_decimalDenominator * 2);
File LinkInstance CountInstance Links
PriceFeed.sol3458,534,801

</details>
<a id="g-20"></a> [G-20] Usage of uints/ints smaller than 32 bytes (256 bits) incurs overhead
Description:

According to the Solidity docs, "When using elements that are smaller than 32 bytes, your contract's gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size." Each operation involving a uint8 costs an extra 22-28 gas (depending on whether the other operand is also a variable of type uint8) as compared to ones involving uint256, due to the compiler having to clear the higher bits of the memory word before operating on the uint8, as well as the associated stack operations of doing so.

Recommendation:

Use uint256/int256 for integers, then downcast (using OpenZeppelin's SafeCast) where needed.

Instances:

There are 9 instances of this issue.

<details><summary>View 9 Instances</summary>
File: packages/contracts/contracts/CdpManager.sol

/// @audit uint128 index
559:         index = uint128(CdpIds.length - 1);
File LinkInstance CountInstance Link
CdpManager.sol1559

File: packages/contracts/contracts/Governor.sol

/// @audit uint8[] rolesForUser
83:             rolesForUser = new uint8[](count);

/// @audit uint8[] rolesForUser
86:                     rolesForUser[j] = i;

/// @audit uint8[] roleIds
106:             roleIds = new uint8[](count);

/// @audit uint8[] roleIds
110:                     roleIds[j] = i;
File LinkInstance CountInstance Links
Governor.sol483,86,106,110

File: packages/contracts/contracts/PriceFeed.sol

/// @audit uint8 ethBtcDecimals
617:             ethBtcDecimals = decimals;

/// @audit uint8 stEthEthDecimals
625:             stEthEthDecimals = decimals;

/// @audit uint8 ethBtcDecimals
705:             ethBtcDecimals = decimals;

/// @audit uint8 stEthEthDecimals
713:             stEthEthDecimals = decimals;
File LinkInstance CountInstance Links
PriceFeed.sol4617,625,705,713

</details>
<a id="g-21"></a> [G-21] Use assembly for small keccak256 hashes, in order to save gas
Description:

If the arguments to the encode call can fit into the scratch space (two words or fewer), then it is more efficient to use assembly to generate the hash (80 gas).

Recommendation:

Use assembly as shown in the following example:

// Before:
keccak256(abi.encodePacked(x, y));

// After
assembly {
  mstore(0x00, a);
  mstore(0x20, b);
  let hash := keccak256(0x00, 0x40);
}
Instances:

There is 1 instance of this issue.

File: packages/contracts/contracts/HintHelpers.sol

182:             latestRandomSeed = uint256(keccak256(abi.encodePacked(latestRandomSeed)));
File LinkInstance CountInstance Link
HintHelpers.sol1182

<a id="g-22"></a> [G-22] Use assembly to emit events, in order to save gas
Description:

Using the scratch space for event arguments (two words or fewer) will save gas over needing Solidity's full abi memory expansion used for emitting normally.

Instances:

There are 55 instances of this issue.

<details><summary>View 55 Instances</summary>
File: packages/contracts/contracts/ActivePool.sol

65:         emit FeeRecipientAddressChanged(_feeRecipientAddress);

112:         emit SystemCollSharesUpdated(cachedSystemCollShares);

113:         emit CollSharesTransferred(_account, _shares);

145:         emit SystemCollSharesUpdated(cachedSystemCollShares);

146:         emit CollSharesTransferred(_account, totalShares);

173:         emit SystemCollSharesUpdated(cachedSystemCollShares);

174:         emit FeeRecipientClaimableCollSharesIncreased(cachedFeeRecipientCollShares, _shares);

200:         emit ActivePoolEBTCDebtUpdated(cachedSystemDebt);

213:         emit ActivePoolEBTCDebtUpdated(cachedSystemDebt);

247:         emit SystemCollSharesUpdated(cachedSystemCollShares);

360:         emit FeeRecipientClaimableCollSharesDecreased(cachedFeeRecipientCollShares, _shares);

399:         emit FeeRecipientAddressChanged(_feeRecipientAddress);

421:         emit FlashLoansPaused(msg.sender, _paused);
File LinkInstance CountInstance Links
ActivePool.sol1365,112,113,145,146,173,174,200,213,247,360,399,421

File: packages/contracts/contracts/BorrowerOperations.sol

136:         emit FeeRecipientAddressChanged(_feeRecipientAddress);

1149:         emit FeeRecipientAddressChanged(_feeRecipientAddress);

1171:         emit FlashLoansPaused(msg.sender, _paused);
File LinkInstance CountInstance Links
BorrowerOperations.sol3136,1149,1171

File: packages/contracts/contracts/CdpManager.sol

55:         emit StakingRewardSplitSet(stakingRewardSplit);

630:         emit BaseRateUpdated(newBaseRate);

681:         emit BaseRateUpdated(decayedBaseRate);

698:             emit LastRedemptionTimestampUpdated(block.timestamp);

782:         emit StakingRewardSplitSet(_stakingRewardSplit);

801:         emit RedemptionFeeFloorSet(_redemptionFeeFloor);

824:         emit MinuteDecayFactorSet(_minuteDecayFactor);

836:         emit BetaSet(_beta);

848:         emit RedemptionsPaused(_paused);
File LinkInstance CountInstance Links
CdpManager.sol955,630,681,698,782,801,824,836,848

File: packages/contracts/contracts/CdpManagerStorage.sol

50:         emit TCRNotified(_tcr);

64:         emit TCRNotified(_tcr);

119:         emit GracePeriodDurationSet(_gracePeriod);

300:         emit SystemSnapshotsUpdated(_totalStakesSnapshot, _totalCollateralSnapshot);

340:         emit CdpDebtRedistributionIndexUpdated(_cdpId, _systemDebtRedistributionIndex);

414:         emit TotalStakesUpdated(_newTotalStakes);

425:         emit TotalStakesUpdated(_newTotalStakes);

481:         emit CdpArrayIndexUpdated(idToMove, index);
File LinkInstance CountInstance Links
CdpManagerStorage.sol850,64,119,300,340,414,425,481

File: packages/contracts/contracts/CollSurplusPool.sol

83:         emit SurplusCollSharesUpdated(_account, newAmount);

95:         emit SurplusCollSharesUpdated(_account, 0);

104:         emit CollSharesTransferred(_account, claimableColl);
File LinkInstance CountInstance Links
CollSurplusPool.sol383,95,104

File: packages/contracts/contracts/Dependencies/Auth.sol

22:         emit OwnershipTransferred(msg.sender, _owner);

23:         emit AuthorityUpdated(msg.sender, _authority);

49:         emit AuthorityUpdated(msg.sender, newAuthority);

55:         emit OwnershipTransferred(msg.sender, newOwner);
File LinkInstance CountInstance Links
Auth.sol422,23,49,55

File: packages/contracts/contracts/Dependencies/AuthNoOwner.sol

50:         emit AuthorityUpdated(msg.sender, Authority(newAuthority));

62:         emit AuthorityUpdated(address(this), Authority(newAuthority));
File LinkInstance CountInstance Links
AuthNoOwner.sol250,62

File: packages/contracts/contracts/Dependencies/RolesAuthority.sol

140:         emit CapabilityBurned(target, functionSig);
File LinkInstance CountInstance Link
RolesAuthority.sol1140

File: packages/contracts/contracts/Governor.sol

157:         emit RoleNameSet(role, roleName);
File LinkInstance CountInstance Link
Governor.sol1157

File: packages/contracts/contracts/LeverageMacroFactory.sol

56:         emit DeployNewMacro(_owner, addy);
File LinkInstance CountInstance Link
LeverageMacroFactory.sol156

File: packages/contracts/contracts/LiquidationLibrary.sol

891:         emit SystemDebtRedistributionIndexUpdated(systemDebtRedistributionIndex);
File LinkInstance CountInstance Link
LiquidationLibrary.sol1891

File: packages/contracts/contracts/PriceFeed.sol

67:         emit FallbackCallerChanged(address(0), _fallbackCallerAddress);

378:                     emit FallbackCallerChanged(oldFallbackCaller, _fallbackCaller);

381:                 emit UnhealthyFallbackCaller(_fallbackCaller, block.timestamp);

387:             emit FallbackCallerChanged(oldFallbackCaller, _fallbackCaller);

548:         emit PriceFeedStatusChanged(_status);

555:         emit LastGoodPriceUpdated(_currentPrice);
File LinkInstance CountInstance Links
PriceFeed.sol667,378,381,387,548,555

File: packages/contracts/contracts/SortedCdps.sol

405:         emit NodeAdded(_id, _NICR);

451:             emit NodeRemoved(_ids[i]);

490:         emit NodeRemoved(_id);
File LinkInstance CountInstance Links
SortedCdps.sol3405,451,490

</details>
<a id="g-23"></a> [G-23] Use custom errors rather than revert()/require() strings to save gas

Note: This issue was listed in the automated findings output; however, additional instances of the issue are listed here.

Description:

Custom errors are available since Solidity 0.8.4. Custom errors save ~50 gas each time they are hit by avoiding having to allocate and store the revert string. Not defining the strings will also save deployment gas.

Instances:

There are 162 instances of this issue.

<details><summary>View 162 Instances</summary>
File: packages/contracts/contracts/ActivePool.sol

104:         require(cachedSystemCollShares >= _shares, "!ActivePoolBal");

137:         require(cachedSystemCollShares >= _shares, "ActivePool: Insufficient collateral shares");

162:         require(cachedSystemCollShares >= _shares, "ActivePool: Insufficient collateral shares");

220:         require(
221:             msg.sender == borrowerOperationsAddress,
222:             "ActivePool: Caller is not BorrowerOperations"
223:         );

228:         require(
229:             msg.sender == borrowerOperationsAddress || msg.sender == cdpManagerAddress,
230:             "ActivePool: Caller is neither BorrowerOperations nor CdpManager"
231:         );

236:         require(msg.sender == cdpManagerAddress, "ActivePool: Caller is not CdpManager");

267:         require(amount > 0, "ActivePool: 0 Amount");

269:         require(amount <= maxFlashLoan(token), "ActivePool: Too much");

277:         require(
278:             receiver.onFlashLoan(msg.sender, token, amount, fee, data) == FLASH_SUCCESS_VALUE,
279:             "ActivePool: IERC3156: Callback failed"
280:         );

294:         require(
295:             collateral.balanceOf(address(this)) >= collateral.getPooledEthByShares(systemCollShares),
296:             "ActivePool: Must repay Balance"
297:         );

298:         require(
299:             collateral.sharesOf(address(this)) >= systemCollShares,
300:             "ActivePool: Must repay Share"
301:         );

302:         require(
303:             collateral.getPooledEthByShares(DECIMAL_PRECISION) == oldRate,
304:             "ActivePool: Should keep same collateral share rate"
305:         );

318:         require(token == address(collateral), "ActivePool: collateral Only");

319:         require(!flashLoansPaused, "ActivePool: Flash Loans Paused");

350:         require(
351:             cachedFeeRecipientCollShares >= _shares,
352:             "ActivePool: Insufficient fee recipient coll"
353:         );

374:         require(token != address(collateral), "ActivePool: Cannot Sweep Collateral");

377:         require(amount <= balance, "ActivePool: Attempt to sweep more than balance");

393:         require(
394:             _feeRecipientAddress != address(0),
395:             "ActivePool: Cannot set fee recipient to zero address"
396:         );

407:         require(_newFee <= MAX_FEE_BPS, "ERC3156FlashLender: _newFee should <= MAX_FEE_BPS");
File LinkInstance CountInstance Links
ActivePool.sol19104,137,162,220,228,236,267,269,277,294,298,302,318,319,350,374,377,393,407

File: packages/contracts/contracts/BorrowerOperations.sol

145:         require(locked == OPEN, "BorrowerOperations: Reentrancy in nonReentrant call");

146:         require(
147:             ReentrancyGuard(address(cdpManager)).locked() == OPEN,
148:             "CdpManager: Reentrancy in nonReentrant call"
149:         );

368:         require(
369:             _stEthBalanceDecrease <= _cdpStEthBalance,
370:             "BorrowerOperations: Cannot withdraw greater stEthBalance than the value in Cdp"
371:         );

463:         require(vars.netStEthBalance > 0, "BorrowerOperations: zero collateral for openCdp()!");

541:         require(
542:             vars.netStEthBalance + LIQUIDATOR_REWARD == _stEthBalance,
543:             "BorrowerOperations: deposited collateral mismatch!"
544:         );

715:         require(_deadline >= block.timestamp, "BorrowerOperations: Position manager permit expired");

734:         require(
735:             recoveredAddress != address(0) && recoveredAddress == _borrower,
736:             "BorrowerOperations: Invalid signature"
737:         );

807:         require(
808:             _stEthBalanceIncrease == 0 || _stEthBalanceDecrease == 0,
809:             "BorrowerOperations: Cannot add and withdraw collateral in same operation"
810:         );

818:         require(
819:             _stEthBalanceIncrease != 0 || _stEthBalanceDecrease != 0 || _debtChange != 0,
820:             "BorrowerOperations: There must be either a collateral change or a debt change"
821:         );

826:         require(status == 1, "BorrowerOperations: Cdp does not exist or is closed");

831:         require(status == 0, "BorrowerOperations: Cdp is active or has been previously closed");

835:         require(_debtChange > 0, "BorrowerOperations: Debt increase requires non-zero debtChange");

839:         require(
840:             !_checkRecoveryModeForTCR(_tcr),
841:             "BorrowerOperations: Operation not permitted during Recovery Mode"
842:         );

846:         require(
847:             _stEthBalanceDecrease == 0,
848:             "BorrowerOperations: Collateral withdrawal not permitted during Recovery Mode"
849:         );

911:         require(
912:             _newICR >= MCR,
913:             "BorrowerOperations: An operation that would result in ICR < MCR is not permitted"
914:         );

918:         require(_newICR >= CCR, "BorrowerOperations: Operation must leave cdp with ICR >= CCR");

922:         require(
923:             _newICR >= _oldICR,
924:             "BorrowerOperations: Cannot decrease your Cdp's ICR in Recovery Mode"
925:         );

929:         require(
930:             _newTCR >= CCR,
931:             "BorrowerOperations: An operation that would result in TCR < CCR is not permitted"
932:         );

936:         require(_debt > 0, "BorrowerOperations: Debt must be non-zero");

940:         require(
941:             _stEthBalance >= MIN_NET_STETH_BALANCE,
942:             "BorrowerOperations: Cdp's net stEth balance must not fall below minimum"
943:         );

947:         require(
948:             _debtRepayment <= _currentDebt,
949:             "BorrowerOperations: Amount repaid must not be larger than the Cdp's debt"
950:         );

957:         require(
958:             ebtcToken.balanceOf(_account) >= _debtRepayment,
959:             "BorrowerOperations: Caller doesnt have enough eBTC to make repayment"
960:         );

970:         require(
971:             _approval != PositionManagerApproval.None,
972:             "BorrowerOperations: Only borrower account or approved position manager can OpenCdp on borrower's behalf"
973:         );

1083:         require(amount > 0, "BorrowerOperations: 0 Amount");

1085:         require(amount <= maxFlashLoan(token), "BorrowerOperations: Too much");

1091:         require(
1092:             receiver.onFlashLoan(msg.sender, token, amount, fee, data) == FLASH_SUCCESS_VALUE,
1093:             "IERC3156: Callback failed"
1094:         );

1115:         require(token == address(ebtcToken), "BorrowerOperations: EBTC Only");

1116:         require(!flashLoansPaused, "BorrowerOperations: Flash Loans Paused");

1141:         require(
1142:             _feeRecipientAddress != address(0),
1143:             "BorrowerOperations: Cannot set feeRecipient to zero address"
1144:         );

1155:         require(_newFee <= MAX_FEE_BPS, "ERC3156FlashLender: _newFee should <= MAX_FEE_BPS");

File: packages/contracts/contracts/CdpManager.sol

332:         require(redemptionsPaused == false, "CdpManager: Redemptions Paused");

431:         require(totals.collSharesDrawn > 0, "CdpManager: Unable to redeem any amount");

502:         require(_toRemoveIds[0] == _start, "CdpManager: batchRemoveSortedCdpIds check start error");

503:         require(
504:             _toRemoveIds[_total - 1] == _end,
505:             "CdpManager: batchRemoveSortedCdpIds check end error"
506:         );

626:         require(newBaseRate > 0, "CdpManager: new baseRate is zero!"); // Base rate is always non-zero after redemption

672:         require(redemptionFee < _ETHDrawn, "CdpManager: Fee would eat up all returned collateral");

678:         require(decayedBaseRate <= DECIMAL_PRECISION, "CdpManager: baseRate too large!"); // The baseRate can decay to 0

743:         require(
744:             callerBalance >= _amount,
745:             "CdpManager: Requested redemption amount must be <= user's EBTC token balance"
746:         );

747:         require(
748:             callerBalance <= _totalSupply,
749:             "CdpManager: redeemer's EBTC balance exceeds total supply!"
750:         );

754:         require(_amount > 0, "CdpManager: Amount must be greater than zero");

758:         require(_TCR >= MCR, "CdpManager: Cannot redeem when TCR < MCR");

762:         require(
763:             _maxFeePercentage >= redemptionFeeFloor && _maxFeePercentage <= DECIMAL_PRECISION,
764:             "Max fee percentage must be between redemption fee floor and 100%"
765:         );

774:         require(
775:             _stakingRewardSplit <= MAX_REWARD_SPLIT,
776:             "CDPManager: new staking reward split exceeds max"
777:         );

789:         require(
790:             _redemptionFeeFloor >= MIN_REDEMPTION_FEE_FLOOR,
791:             "CDPManager: new redemption fee floor is lower than minimum"
792:         );

793:         require(
794:             _redemptionFeeFloor <= DECIMAL_PRECISION,
795:             "CDPManager: new redemption fee floor is higher than maximum"
796:         );

808:         require(
809:             _minuteDecayFactor >= MIN_MINUTE_DECAY_FACTOR,
810:             "CDPManager: new minute decay factor out of range"
811:         );

812:         require(
813:             _minuteDecayFactor <= MAX_MINUTE_DECAY_FACTOR,
814:             "CDPManager: new minute decay factor out of range"
815:         );
File LinkInstance CountInstance Links
CdpManager.sol17332,431,502,503,626,672,678,743,747,754,758,762,774,789,793,808,812

File: packages/contracts/contracts/CdpManagerStorage.sol

112:         require(
113:             _gracePeriod >= MINIMUM_GRACE_PERIOD,
114:             "CdpManager: Grace period below minimum duration"
115:         );

242:         require(locked == OPEN, "CdpManager: Reentrancy in nonReentrant call");

243:         require(
244:             ReentrancyGuard(borrowerOperationsAddress).locked() == OPEN,
245:             "BorrowerOperations: Reentrancy in nonReentrant call"
246:         );

261:         require(
262:             closedStatus != Status.nonExistent && closedStatus != Status.active,
263:             "CdpManagerStorage: close non-exist or non-active CDP!"
264:         );

453:             require(totalStakesSnapshot > 0, "CdpManagerStorage: zero totalStakesSnapshot!");

466:         require(
467:             cdpStatus != Status.nonExistent && cdpStatus != Status.active,
468:             "CdpManagerStorage: remove non-exist or non-active CDP!"
469:         );

475:         require(index <= idxLast, "CdpManagerStorage: CDP indexing overflow!");

556:         require(_newIndex > _prevIndex, "CDPManager: only take fee with bigger new index");

584:         require(activePool.getSystemCollShares() > _feeTaken, "CDPManager: fee split is too big");

649:         require(Cdps[_cdpId].status == Status.active, "CdpManager: Cdp does not exist or is closed");

653:         require(
654:             CdpOwnersArrayLength > 1 && sortedCdps.getSize() > 1,
655:             "CdpManager: Only one cdp in the system"
656:         );

660:         require(
661:             msg.sender == borrowerOperationsAddress,
662:             "CdpManager: Caller is not the BorrowerOperations contract"
663:         );
File LinkInstance CountInstance Links
CdpManagerStorage.sol12112,242,243,261,453,466,475,556,584,649,653,660

File: packages/contracts/contracts/CollSurplusPool.sol

92:         require(claimableColl > 0, "CollSurplusPool: No collateral available to claim");

99:         require(cachedTotalSurplusCollShares >= claimableColl, "!CollSurplusPoolBal");

113:         require(
114:             msg.sender == borrowerOperationsAddress,
115:             "CollSurplusPool: Caller is not Borrower Operations"
116:         );

120:         require(msg.sender == cdpManagerAddress, "CollSurplusPool: Caller is not CdpManager");

124:         require(msg.sender == activePoolAddress, "CollSurplusPool: Caller is not Active Pool");

143:         require(token != address(collateral), "CollSurplusPool: Cannot Sweep Collateral");

146:         require(amount <= balance, "CollSurplusPool: Attempt to sweep more than balance");
File LinkInstance CountInstance Links
CollSurplusPool.sol792,99,113,120,124,143,146

File: packages/contracts/contracts/Dependencies/Auth.sol

27:         require(isAuthorized(msg.sender, msg.sig), "Auth: UNAUTHORIZED");

45:         require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig));
File LinkInstance CountInstance Links
Auth.sol227,45

File: packages/contracts/contracts/Dependencies/AuthNoOwner.sol

17:         require(isAuthorized(msg.sender, msg.sig), "Auth: UNAUTHORIZED");

41:         require(_authority.canCall(msg.sender, address(this), msg.sig));

56:         require(address(_authority) == address(0), "Auth: authority is non-zero");

57:         require(!_authorityInitialized, "Auth: authority already initialized");
File LinkInstance CountInstance Links
AuthNoOwner.sol417,41,56,57

File: packages/contracts/contracts/Dependencies/EbtcBase.sol

109:         require(feePercentage <= _maxFeePercentage, "Fee exceeded provided maximum");
File LinkInstance CountInstance Link
EbtcBase.sol1109

File: packages/contracts/contracts/Dependencies/ReentrancyGuard.sol

14:         require(locked == OPEN, "ReentrancyGuard: Reentrancy in nonReentrant call");
File LinkInstance CountInstance Link
ReentrancyGuard.sol114

File: packages/contracts/contracts/Dependencies/RolesAuthority.sol

90:         require(
91:             capabilityFlag[target][functionSig] != CapabilityFlag.Burned,
92:             "RolesAuthority: Capability Burned"
93:         );

134:         require(
135:             capabilityFlag[target][functionSig] != CapabilityFlag.Burned,
136:             "RolesAuthority: Capability Burned"
137:         );
File LinkInstance CountInstance Links
RolesAuthority.sol290,134

File: packages/contracts/contracts/EBTCToken.sol

144:             require(cachedAllowance >= amount, "ERC20: transfer amount exceeds allowance");

165:         require(cachedAllowances >= subtractedValue, "ERC20: decreased allowance below zero");

208:         require(deadline >= block.timestamp, "EBTC: expired deadline");

219:         require(recoveredAddress == owner, "EBTC: invalid signature");

247:         require(sender != address(0), "EBTCToken: zero sender!");

248:         require(recipient != address(0), "EBTCToken: zero recipient!");

251:         require(cachedSenderBalances >= amount, "ERC20: transfer amount exceeds balance");

263:         require(account != address(0), "EBTCToken: mint to zero recipient!");

271:         require(account != address(0), "EBTCToken: burn from zero account!");

274:         require(cachedBalance >= amount, "ERC20: burn amount exceeds balance");

286:         require(owner != address(0), "EBTCToken: zero approve owner!");

287:         require(spender != address(0), "EBTCToken: zero approve spender!");

296:         require(
297:             _recipient != address(0) && _recipient != address(this),
298:             "EBTC: Cannot transfer tokens directly to the EBTC token contract or the zero address"
299:         );

300:         require(
301:             _recipient != cdpManagerAddress && _recipient != borrowerOperationsAddress,
302:             "EBTC: Cannot transfer tokens directly to the CdpManager or BorrowerOps"
303:         );

307:         require(
308:             msg.sender == borrowerOperationsAddress,
309:             "EBTCToken: Caller is not BorrowerOperations"
310:         );

315:         require(
316:             msg.sender == borrowerOperationsAddress ||
317:                 msg.sender == cdpManagerAddress ||
318:                 isAuthorized(msg.sender, msg.sig),
319:             "EBTC: Caller is neither BorrowerOperations nor CdpManager nor authorized"
320:         );

324:         require(msg.sender == cdpManagerAddress, "EBTC: Caller is not CdpManager");
File LinkInstance CountInstance Links
EBTCToken.sol17144,165,208,219,247,248,251,263,271,274,286,287,296,300,307,315,324

File: packages/contracts/contracts/LeverageMacroBase.sol

40:         revert("Must be overridden");

45:         require(owner() == msg.sender, "Must be owner");

179:             require(
180:                 cdpInfo.status == checkParams.expectedStatus,
181:                 "!LeverageMacroReference: openCDP status check"
182:             );

191:             require(
192:                 cdpInfo.status == checkParams.expectedStatus,
193:                 "!LeverageMacroReference: adjustCDP status check"
194:             );

201:             require(
202:                 cdpInfo.status == checkParams.expectedStatus,
203:                 "!LeverageMacroReference: closeCDP status check"
204:             );

249:             require(check.value >= valueToCheck, "!LeverageMacroReference: gte post check");

251:             require(check.value <= valueToCheck, "!LeverageMacroReference: let post check");

253:             require(check.value == valueToCheck, "!LeverageMacroReference: equal post check");

255:             revert("Operator not found");

352:         require(initiator == address(this), "LeverageMacroReference: wrong initiator for flashloan");

356:             require(
357:                 msg.sender == address(borrowerOperations),
358:                 "LeverageMacroReference: wrong lender for eBTC flashloan"
359:             );

362:             require(
363:                 msg.sender == address(activePool),
364:                 "LeverageMacroReference: wrong lender for stETH flashloan"
365:             );

421:         require(success, "Call has failed");

440:                 require(
441:                     IERC20(swapChecks[i].tokenToCheck).balanceOf(address(this)) >
442:                         swapChecks[i].expectedMinOut,
443:                     "LeverageMacroReference: swap check failure!"
444:                 );

452:         require(addy != address(borrowerOperations));

453:         require(addy != address(sortedCdps));

454:         require(addy != address(activePool));

455:         require(addy != address(cdpManager));

456:         require(addy != address(this)); // If it could call this it could fake the forwarded caller
File LinkInstance CountInstance Links
LeverageMacroBase.sol1940,45,179,191,201,249,251,253,255,352,356,362,421,440,452,453,454,455,456

File: packages/contracts/contracts/LiquidationLibrary.sol

56:         require(_partialAmount != 0, "LiquidationLibrary: use `liquidate` for 100%");

82:             require(
83:                 _checkICRAgainstLiqThreshold(_ICR, _TCR),
84:                 "LiquidationLibrary: ICR is not below liquidation threshold in current mode"
85:             );

89:             require(
90:                 cachedLastGracePeriodStartTimestamp != UNSET_TIMESTAMP,
91:                 "LiquidationLibrary: Recovery Mode grace period not started"
92:             );

93:             require(
94:                 block.timestamp >
95:                     cachedLastGracePeriodStartTimestamp + recoveryModeGracePeriodDuration,
96:                 "LiquidationLibrary: Recovery mode grace period still in effect"
97:             );

477:             require(
478:                 getCachedICR(_cdpId, _partialState.price) >= _partialState.ICR,
479:                 "LiquidationLibrary: !_newICR>=_ICR"
480:             );

680:         require(
681:             _cdpArray.length != 0,
682:             "LiquidationLibrary: Calldata address array must not be empty"
683:         );

710:         require(totals.totalDebtInSequence > 0, "LiquidationLibrary: nothing to liquidate");

901:         require(
902:             (_partialDebt + _convertDebtDenominationToBtc(MIN_NET_STETH_BALANCE, _price)) <=
903:                 _entireDebt,
904:             "LiquidationLibrary: Partial debt liquidated must be less than total debt"
905:         );

909:         require(
910:             _entireColl >= MIN_NET_STETH_BALANCE,
911:             "LiquidationLibrary: Coll remaining in partially liquidated CDP must be >= minimum"
912:         );
File LinkInstance CountInstance Links
LiquidationLibrary.sol956,82,89,93,477,680,710,901,909

File: packages/contracts/contracts/PriceFeed.sol

79:         require(
80:             !_chainlinkIsBroken(chainlinkResponse, prevChainlinkResponse) &&
81:                 !_chainlinkIsFrozen(chainlinkResponse),
82:             "PriceFeed: Chainlink must be working and current"
83:         );
File LinkInstance CountInstance Link
PriceFeed.sol179

File: packages/contracts/contracts/SimplifiedDiamondLike.sol

52:         require(msg.sender == owner);

56:         require(sig != 0x94b24d09);

67:         require(msg.sender == owner);

77:         require(msg.sender == address(this)); // Must call this via `execute` to explicitly set the flag

111:         require(msg.sender == owner, "Must be owner");

154:             require(success);

179:             require(ds.settings.callbackEnabledForCall, "Only Enabled Callbacks");

187:         require(facet != address(0), "Diamond: Function does not exist");
File LinkInstance CountInstance Links
SimplifiedDiamondLike.sol852,56,67,77,111,154,179,187

File: packages/contracts/contracts/SortedCdps.sol

352:         require(cdpManager.getCdpStatus(_id) == 0, "SortedCdps: new id is NOT nonExistent!");

365:         require(!isFull(), "SortedCdps: List is full");

367:         require(!contains(_id), "SortedCdps: List already contains the node");

369:         require(_id != dummyId, "SortedCdps: Id cannot be zero");

371:         require(_NICR > 0, "SortedCdps: NICR must be positive");

422:         require(_len > 1, "SortedCdps: batchRemove() only apply to multiple cdpIds!");

427:         require(
428:             _firstPrev != dummyId || _lastNext != dummyId,
429:             "SortedCdps: batchRemove() leave ZERO node left!"
430:         );

433:             require(contains(_ids[i]), "SortedCdps: List does not contain the id");

458:         require(contains(_id), "SortedCdps: List does not contain the id");

506:         require(contains(_id), "SortedCdps: List does not contain the id");

508:         require(_newNICR > 0, "SortedCdps: NICR must be positive");

715:         require(msg.sender == address(cdpManager), "SortedCdps: Caller is not the CdpManager");

720:         require(
721:             msg.sender == borrowerOperationsAddress || msg.sender == address(cdpManager),
722:             "SortedCdps: Caller is neither BO nor CdpM"
723:         );
File LinkInstance CountInstance Links
SortedCdps.sol13352,365,367,369,371,422,427,433,458,506,508,715,720

</details>
<a id="g-24"></a> [G-24] Use predefined address instead of address(this)
Description:

Instead of using address(this), it is more gas-efficient to pre-calculate and use the predefined address. Foundry's script.sol and Solmate's LibRlp.sol contracts can help pre-determine the address (see computeCreateAddress). The address can be passed in via a constructor argument and assigned to an immutable variable (rather than using a hardcoded constant) so that the code can remain the same across deployments on different networks.

Instances:

There are 27 instances of this issue.

<details><summary>View 27 Instances</summary>
File: packages/contracts/contracts/ActivePool.sol

283:         collateral.transferFrom(address(receiver), address(this), amountWithFee);

295:             collateral.balanceOf(address(this)) >= collateral.getPooledEthByShares(systemCollShares),

299:             collateral.sharesOf(address(this)) >= systemCollShares,

337:         return collateral.balanceOf(address(this));

376:         uint256 balance = IERC20(token).balanceOf(address(this));
File LinkInstance CountInstance Links
ActivePool.sol5283,295,299,337,376

File: packages/contracts/contracts/BorrowerOperations.sol

682:         return keccak256(abi.encode(typeHash, name, version, _chainID(), address(this)));
File LinkInstance CountInstance Link
BorrowerOperations.sol1682

File: packages/contracts/contracts/CollSurplusPool.sol

145:         uint256 balance = IERC20(token).balanceOf(address(this));
File LinkInstance CountInstance Link
CollSurplusPool.sol1145

File: packages/contracts/contracts/Dependencies/Auth.sol

38:             (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) ||

45:         require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig));
File LinkInstance CountInstance Links
Auth.sol238,45

File: packages/contracts/contracts/Dependencies/AuthNoOwner.sol

35:         return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig));

41:         require(_authority.canCall(msg.sender, address(this), msg.sig));

62:         emit AuthorityUpdated(address(this), Authority(newAuthority));
File LinkInstance CountInstance Links
AuthNoOwner.sol335,41,62

File: packages/contracts/contracts/EBTCToken.sol

240:         return keccak256(abi.encode(typeHash, name, version, _chainID(), address(this)));

297:             _recipient != address(0) && _recipient != address(this),
File LinkInstance CountInstance Links
EBTCToken.sol2240,297

File: packages/contracts/contracts/Governor.sol

36:     constructor(address _owner) RolesAuthority(_owner, Authority(address(this))) {}
File LinkInstance CountInstance Link
Governor.sol136

File: packages/contracts/contracts/LeverageMacroBase.sol

131:                 address(this),

143:             initialCdpIndex = sortedCdps.cdpCountOf(address(this));

149:                 IERC3156FlashBorrower(address(this)),

156:                 IERC3156FlashBorrower(address(this)),

173:             bytes32 cdpId = sortedCdps.cdpOfOwnerByIndex(address(this), initialCdpIndex);

220:         uint256 ebtcBal = ebtcToken.balanceOf(address(this));

221:         uint256 collateralBal = stETH.sharesOf(address(this));

352:         require(initiator == address(this), "LeverageMacroReference: wrong initiator for flashloan");

441:                     IERC20(swapChecks[i].tokenToCheck).balanceOf(address(this)) >

456:         require(addy != address(this)); // If it could call this it could fake the forwarded caller
File LinkInstance CountInstance Links
LeverageMacroBase.sol10131,143,149,156,173,220,221,352,441,456

File: packages/contracts/contracts/LeverageMacroDelegateTarget.sol

64:         address _owner = IOwnerLike(address(this)).owner();
File LinkInstance CountInstance Link
LeverageMacroDelegateTarget.sol164

File: packages/contracts/contracts/SimplifiedDiamondLike.sol

77:         require(msg.sender == address(this)); // Must call this via `execute` to explicitly set the flag
File LinkInstance CountInstance Link
SimplifiedDiamondLike.sol177

</details>
<a id="g-25"></a> [G-25] Use uint256(1)/uint256(2) instead of true/false to save gas for changes
Description:

Using a uint256 instead of a bool avoids a Gsset (20,000 gas) when changing from false to true, after having been true in the past.

Instances:

There are 3 instances of this issue.

File: packages/contracts/contracts/CdpManagerStorage.sol

143:     bool public redemptionsPaused;
File LinkInstance CountInstance Link
CdpManagerStorage.sol1143

File: packages/contracts/contracts/Dependencies/AuthNoOwner.sol

14:     bool private _authorityInitialized;
File LinkInstance CountInstance Link
AuthNoOwner.sol114

File: packages/contracts/contracts/Dependencies/ERC3156FlashLender.sol

15:     bool public flashLoansPaused;
File LinkInstance CountInstance Link
ERC3156FlashLender.sol115

<a id="g-26"></a> [G-26] Using constants directly, rather than caching the value, saves gas
Description:

Avoid assigning constants to a variable. Instead, use the constant directly.

Instances:

There is 1 instance of this issue.

File: packages/contracts/contracts/Dependencies/EbtcMath.sol

/// @audit DECIMAL_PRECISION
68:         uint256 y = DECIMAL_PRECISION;
File LinkInstance CountInstance Link
EbtcMath.sol168

<a id="g-27"></a> [G-27] Using storage instead of memory for structs/arrays saves gas
Description:

When fetching data from a storage location, assigning the data to a memory variable causes all fields of the struct/array to be read from storage, which incurs a Gcoldsload (2,100 gas) for each field of the struct/array. If the fields are read from the new memory variable, they incur an additional MLOAD rather than a cheap stack read. Instead of declaring the variable with the memory keyword, declaring the variable with the storage keyword and caching any fields that need to be re-read in stack variables, will be much cheaper, only incurring the Gcoldsload for the fields actually read. The only time it makes sense to read the whole struct/array into a memory variable is if the full struct/array is being returned by the function, is being passed to a function that requires memory, or if the array/struct is being read from another memory array/struct.

Instances:

There are 3 instances of this issue.

File: packages/contracts/contracts/LiquidationLibrary.sol

699:             totals = _getTotalFromBatchLiquidate_RecoveryMode(
700:                 vars.price,
701:                 systemColl,
702:                 systemDebt,
703:                 _cdpArray
704:             );

707:             totals = _getTotalsFromBatchLiquidate_NormalMode(vars.price, _TCR, _cdpArray);
File LinkInstance CountInstance Links
LiquidationLibrary.sol2699,707

File: packages/contracts/contracts/SortedCdps.sol

522:             Node memory _node = data.nodes[_id];
File LinkInstance CountInstance Link
SortedCdps.sol1522

#0 - c4-pre-sort

2023-11-17T14:39:01Z

bytes032 marked the issue as sufficient quality report

#1 - c4-judge

2023-11-28T02:44:56Z

jhsagd76 marked the issue as grade-b

#2 - jhsagd76

2023-12-06T20:22:54Z

1 * 13 + 2*22 - 3 * 1 + 1 * 0

54

#3 - c4-judge

2023-12-06T20:54:06Z

jhsagd76 marked the issue as grade-a

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter