Kelp DAO | rsETH - desaperh's results

A collective DAO designed to unlock liquidity, DeFi and higher rewards for restaked assets through liquid restaking.

General Information

Platform: Code4rena

Start Date: 10/11/2023

Pot Size: $28,000 USDC

Total HM: 5

Participants: 185

Period: 5 days

Judge: 0xDjango

Id: 305

League: ETH

Kelp DAO

Findings Distribution

Researcher Performance

Rank: 141/185

Findings: 1

Award: $2.76

QA:
grade-b

🌟 Selected for report: 0

πŸš€ Solo Findings: 0

Awards

2.7592 USDC - $2.76

Labels

bug
grade-b
QA (Quality Assurance)
sufficient quality report
Q-112

External Links

Audit report markdown format

Report

Audit report for REPO_GITHUB generated by Dowsers<br>

Summary

Low issues

Total 32 instances over 3 issues<br>

IDIssueInstances
SWC-107Reentrancy13
SWC-120Weak sources of randomness from chain attributes18
SWC-127Arbitrary jump with function type variable1

Non-Critical/Quality issues

Total 214 instances over 4 issues<br>

IDIssueInstances
SWC-XX1Insufficient coverage80
SWC-111Use of deprecated functions, aliases and keywords48
SWC-XX2Incorrect comparison implementation80
SWC-110require() should be used instead of assert()6

Low issues

[SWC-107] Reentrancy

Description:<br> Reduce the attack surface for malicious contracts trying to hijack control flow after an external call. <br> https://swcregistry.io/docs/SWC-107 <br> https://fravoll.github.io/solidity-patterns/checks_effects_interactions.html <br>Recommendation:<br> The pattern of Checks Effects Interactions should be checked and analysed in order to prevent re-entrancy attacks. <br> <br><br> There are 13 instances of this issue:

<details><summary>see instances</summary>
File: /packages/contracts/contracts/BorrowerOperations.sol
range(211, 225): withdraws `_stEthBalanceDecrease` amount of collateral from the specified Cdp
    /// @dev If caller is different from Cdp owner, it will need approval from Cdp owner for this call
    /// @notice Successful execution is conditional on whether the withdrawal would bring down the ICR or TCR to the minimum requirement, e.g., MCR or CCR
    /// @param _cdpId The CdpId on which this operation is operated
    /// @param _stEthBalanceDecrease The total stETH collateral amount withdrawn (reduced) for the specified Cdp
    /// @param _upperHint The expected CdpId of neighboring higher ICR within SortedCdps, could be simply bytes32(0)
    /// @param _lowerHint The expected CdpId of neighboring lower ICR within SortedCdps, could be simply bytes32(0)
    function withdrawColl(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        bytes32 _upperHint,
        bytes32 _lowerHint
    ) external override nonReentrantSelfAndCdpM {
        _adjustCdpInternal(_cdpId, _stEthBalanceDecrease, 0, false, _upperHint, _lowerHint, 0);
range(227, 241): withdraws `_debt` amount of eBTC token from the specified Cdp, thus increasing its debt accounting
    /// @dev If caller is different from Cdp owner, it will need approval from Cdp owner for this call
    /// @notice Successful execution is conditional on whether the withdrawal would bring down the ICR or TCR to the minimum requirement, e.g., MCR or CCR
    /// @param _cdpId The CdpId on which this operation is operated
    /// @param _debt The total debt collateral amount increased for the specified Cdp
    /// @param _upperHint The expected CdpId of neighboring higher ICR within SortedCdps, could be simply bytes32(0)
    /// @param _lowerHint The expected CdpId of neighboring lower ICR within SortedCdps, could be simply bytes32(0)
    function withdrawDebt(
        bytes32 _cdpId,
        uint256 _debt,
        bytes32 _upperHint,
        bytes32 _lowerHint
    ) external override nonReentrantSelfAndCdpM {
        _adjustCdpInternal(_cdpId, 0, _debt, true, _upperHint, _lowerHint, 0);
range(259, 285): withdraws eBTC token and reduces stETH collateral)
    /// @notice or holding more safer position (repays eBTC token) with the specified Cdp.
    /// @notice If end user want to add collateral and change debt at the same time, use adjustCdpWithColl() instead
    /// @dev If caller is different from Cdp owner, it will need approval from Cdp owner for this call
    /// @param _cdpId The CdpId on which this operation is operated
    /// @param _stEthBalanceDecrease The total stETH collateral amount withdrawn from the specified Cdp
    /// @param _debtChange The total eBTC debt amount withdrawn or repaid for the specified Cdp
    /// @param _isDebtIncrease The flag (true or false) to indicate whether this is a eBTC token withdrawal (debt increase) or a repayment (debt reduce)
    /// @param _upperHint The expected CdpId of neighboring higher ICR within SortedCdps, could be simply bytes32(0)
    /// @param _lowerHint The expected CdpId of neighboring lower ICR within SortedCdps, could be simply bytes32(0)
    function adjustCdp(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        uint256 _debtChange,
        bool _isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint
    ) external override nonReentrantSelfAndCdpM {
        _adjustCdpInternal(
            _cdpId,
            _stEthBalanceDecrease,
            _debtChange,
            _isDebtIncrease,
            _upperHint,
            _lowerHint,
            0
range(289, 316): withdraws eBTC token and reduces stETH collateral)
    /// @notice or holding more safer position (repays eBTC token and adds stETH collateral) with the specified Cdp.
    /// @dev If caller is different from Cdp owner, it will need approval from Cdp owner for this call
    /// @param _cdpId The CdpId on which this operation is operated
    /// @param _stEthBalanceDecrease The total stETH collateral amount withdrawn from the specified Cdp
    /// @param _debtChange The total eBTC debt amount withdrawn or repaid for the specified Cdp
    /// @param _isDebtIncrease The flag (true or false) to indicate whether this is a eBTC token withdrawal (debt increase) or a repayment (debt reduce)
    /// @param _upperHint The expected CdpId of neighboring higher ICR within SortedCdps, could be simply bytes32(0)
    /// @param _lowerHint The expected CdpId of neighboring lower ICR within SortedCdps, could be simply bytes32(0)
    /// @param _stEthBalanceIncrease The total stETH collateral amount deposited (added) for the specified Cdp
    function adjustCdpWithColl(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        uint256 _debtChange,
        bool _isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _stEthBalanceIncrease
    ) external override nonReentrantSelfAndCdpM {
        _adjustCdpInternal(
            _cdpId,
            _stEthBalanceDecrease,
            _debtChange,
            _isDebtIncrease,
            _upperHint,
            _lowerHint,
            _stEthBalanceIncrease
range(321, 350): withdrawal.
     *
     * It therefore expects either a positive _stEthBalanceIncrease, or a positive _stEthBalanceDecrease argument.
     *
     * If both are positive, it will revert.
     */
    function _adjustCdpInternal(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        uint256 _debtChange,
        bool _isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _stEthBalanceIncrease
    ) internal {
        // Confirm the operation is the borrower or approved position manager adjusting its own cdp
        address _borrower = sortedCdps.getOwnerAddress(_cdpId);
        _requireBorrowerOrPositionManagerAndUpdateManagerApproval(_borrower);

        _requireCdpisActive(cdpManager, _cdpId);

        cdpManager.syncAccounting(_cdpId);

        AdjustCdpLocals memory vars;

        vars.price = priceFeed.fetchPrice();

        if (_isDebtIncrease) {
            _requireNonZeroDebtChange(_debtChange);
range(369, 396): withdraw greater stEthBalance than the value in Cdp"
        );
        vars.oldICR = EbtcMath._computeCR(_cdpStEthBalance, vars.debt, vars.price);
        vars.newICR = _getNewICRFromCdpChange(
            vars.collShares,
            vars.debt,
            vars.collSharesChange,
            vars.isCollIncrease,
            vars.netDebtChange,
            _isDebtIncrease,
            vars.price
        );

        // Check the adjustment satisfies all conditions for the current system mode
        bool isRecoveryMode = _checkRecoveryModeForTCR(_getCachedTCR(vars.price));
        _requireValidAdjustmentInCurrentMode(
            isRecoveryMode,
            _stEthBalanceDecrease,
            _isDebtIncrease,
            vars
        );

        // When the adjustment is a debt repayment, check it's a valid amount, that the caller has enough EBTC, and that the resulting debt is >0
        if (!_isDebtIncrease && _debtChange > 0) {
            _requireValidDebtRepayment(vars.debt, vars.netDebtChange);
            _requireSufficientEbtcTokenBalance(msg.sender, vars.netDebtChange);
            _requireNonZeroDebt(vars.debt - vars.netDebtChange);
range(528, 546): withdrawDebt(msg.sender, _debt);

        /**
            Note that only NET stEth balance (as shares) is considered part of the Cdp.
            The static liqudiation incentive is stored in the gas pool and can be considered a deposit / voucher to be returned upon Cdp close, to the closer.
            The close can happen from the borrower closing their own Cdp, a full liquidation, or a redemption.
        */

        // CEI: Move the collateral and liquidator gas compensation to the Active Pool. Track only net collateral for TCR purposes.
        _activePoolAddColl(_stEthBalance, _netCollAsShares);

        // Invariant check
        require(
            vars.netStEthBalance + LIQUIDATOR_REWARD == _stEthBalance,
            "BorrowerOperations: deposited collateral mismatch!"
        );

        return _cdpId;
range(548, 592): withdraw collateral, and close the specified Cdp
    /// @notice Caller should have enough eBTC token to repay off the debt fully for specified Cdp
    /// @dev If caller is different from Cdp owner, it will need approval from Cdp owner for this call
    /// @param _cdpId The CdpId on which this operation is operated
    function closeCdp(bytes32 _cdpId) external override {
        address _borrower = sortedCdps.getOwnerAddress(_cdpId);
        _requireBorrowerOrPositionManagerAndUpdateManagerApproval(_borrower);

        _requireCdpisActive(cdpManager, _cdpId);

        cdpManager.syncAccounting(_cdpId);

        uint256 price = priceFeed.fetchPrice();
        _requireNotInRecoveryMode(_getCachedTCR(price));

        uint256 collShares = cdpManager.getCdpCollShares(_cdpId);
        uint256 debt = cdpManager.getCdpDebt(_cdpId);
        uint256 liquidatorRewardShares = cdpManager.getCdpLiquidatorRewardShares(_cdpId);

        _requireSufficientEbtcTokenBalance(msg.sender, debt);

        uint256 newTCR = _getNewTCRFromCdpChange(
            collateral.getPooledEthByShares(collShares),
            false,
            debt,
            false,
            price
        );
        _requireNewTCRisNotBelowCCR(newTCR);

        // == Grace Period == //
        // By definition we are not in RM, notify CDPManager to ensure "Glass is on"
        cdpManager.notifyEndGracePeriod(newTCR);

        cdpManager.closeCdp(_cdpId, _borrower, debt, collShares);

        // Burn the repaid EBTC from the user's balance
        _repayDebt(msg.sender, debt);

        // CEI: Send the collateral and liquidator reward shares back to the user
        activePool.transferSystemCollSharesAndLiquidatorReward(
            msg.sender,
            collShares,
            liquidatorRewardShares
range(762, 763): withdraw
range(789, 792): withdrawDebt(address _account, uint256 _debt) internal {
        activePool.increaseSystemDebt(_debt);
        ebtcToken.mint(_account, _debt);
range(808, 809): withdraw
range(847, 848): withdraw
File: /packages/contracts/contracts/Interfaces/IBorrowerOperations.sol
range(41, 86): withdrawColl(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        bytes32 _upperHint,
        bytes32 _lowerHint
    ) external;

    function withdrawDebt(
        bytes32 _cdpId,
        uint256 _amount,
        bytes32 _upperHint,
        bytes32 _lowerHint
    ) external;

    function repayDebt(
        bytes32 _cdpId,
        uint256 _amount,
        bytes32 _upperHint,
        bytes32 _lowerHint
    ) external;

    function closeCdp(bytes32 _cdpId) external;

    function adjustCdp(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        uint256 _debtChange,
        bool isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint
    ) external;

    function adjustCdpWithColl(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        uint256 _debtChange,
        bool isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _stEthBalanceIncrease
    ) external;

    function claimSurplusCollShares() external;

    function feeRecipientAddress() external view returns (address);
</details>

[SWC-120] Weak sources of randomness from chain attributes

Description:<br>Creating a strong enough source of randomness in Ethereum is very challenging. For example, use of block.timestamp is insecure, as a miner can choose to provide any timestamp within a few seconds and still get his block accepted by others. Use of blockhash, block.difficulty and other fields is also insecure, as they're controlled by the miner. If the stakes are high, the miner can mine lots of blocks in a short time by renting hardware, pick the block that has required block hash for him to win, and drop all others.<br>https://swcregistry.io/docs/SWC-120 <br>Recommendation:<br>Using commitment scheme, e.g. RANDAO.<br>Using external sources of randomness via oracles, e.g. Oraclize. Note that this approach requires trusting in oracle, thus it may be reasonable to use multiple oracles. <br>Using Bitcoin block hashes, as they are more expensive to mine.<br><br> There are 18 instances of this issue:

<details><summary>see instances</summary>
File: /packages/contracts/contracts/BorrowerOperations.sol
715: block.timestamp
File: /packages/contracts/contracts/CdpManager.sol
690: block.timestamp
691: block.timestamp
696: block.timestamp
698: block.timestamp
711: block.timestamp
712: block.timestamp
File: /packages/contracts/contracts/LiquidationLibrary.sol
94: block.timestamp
File: /packages/contracts/contracts/CdpManagerStorage.sol
53: block.timestamp
228: block.timestamp
542: block.timestamp
900: block.timestamp
File: /packages/contracts/contracts/EBTCToken.sol
208: block.timestamp
File: /packages/contracts/contracts/PriceFeed.sol
381: block.timestamp
421: block.timestamp
423: block.timestamp
471: block.timestamp
494: block.timestamp
</details>

[SWC-127] Arbitrary jump with function type variable

Description:<br> Solidity supports function types. That is, a variable of function type can be assigned with a reference to a function with a matching signature. The function saved to such variable can be called just like a regular function.The problem arises when a user has the ability to arbitrarily change the function type variable and thus execute random code instructions. As Solidity doesn't support pointer arithmetics, it's impossible to change such variable to an arbitrary value. However, if the developer uses assembly instructions, such as mstore or assign operator, in the worst case scenario an attacker is able to point a function type variable to any code instruction, violating required validations and required state changes.<br> https://swcregistry.io/docs/SWC-127 <br> <br>Recommendation:<br> The use of assembly should be minimal. A developer should not allow a user to assign arbitrary values to function type variables. <br><br> There is 1 instance of this issue:

<details><summary>see instance</summary>
File: /packages/contracts/contracts/LeverageMacroBase.sol
529: mstore
</details>

Non-Critical/Quality issues

[SWC-XX1] Insufficient coverage

Description:<br> TBD<br> <br><br>Recommendation:<br> TBD<br> <br><br> There are 80 instances of this issue:

<details><summary>see instances</summary>
File: /packages/contracts/contracts/ActivePool.sol
range(235, 236): (msg.sender == cdpManagerAddress, "ActivePool: Caller is not CdpManager")
range(268, 269): (amount <= maxFlashLoan(token), "ActivePool: Too much")
range(317, 318): (token == address(collateral), "ActivePool: collateral Only")
range(373, 374): (token != address(collateral), "ActivePool: Cannot Sweep Collateral")
range(376, 377): (amount <= balance, "ActivePool: Attempt to sweep more than balance")
range(406, 407): (_newFee <= MAX_FEE_BPS, "ERC3156FlashLender: _newFee should <= MAX_FEE_BPS")
File: /packages/contracts/contracts/BorrowerOperations.sol
range(144, 145): (locked == OPEN, "BorrowerOperations: Reentrancy in nonReentrant call")
range(665, 666): () == _CACHED_CHAIN_ID)
range(825, 826): (status == 1, "BorrowerOperations: Cdp does not exist or is closed")
range(830, 831): (status == 0, "BorrowerOperations: Cdp is active or has been previously closed")
range(1084, 1085): (amount <= maxFlashLoan(token), "BorrowerOperations: Too much")
range(1114, 1115): (token == address(ebtcToken), "BorrowerOperations: EBTC Only")
range(1154, 1155): (_newFee <= MAX_FEE_BPS, "ERC3156FlashLender: _newFee should <= MAX_FEE_BPS")
File: /packages/contracts/contracts/CdpManager.sol
range(331, 332): (redemptionsPaused == false, "CdpManager: Redemptions Paused")
range(368, 369): (currentBorrower != address(0) && getSyncedICR(_cId, totals.price) < MCR)
range(496, 497): (_cnt > 0 && _id != bytes32(0))
range(501, 502): (_toRemoveIds[0] == _start, "CdpManager: batchRemoveSortedCdpIds check start error")
range(677, 678): (decayedBaseRate <= DECIMAL_PRECISION, "CdpManager: baseRate too large!")
File: /packages/contracts/contracts/LiquidationLibrary.sol
range(55, 56): (_partialAmount != 0, "LiquidationLibrary: use `liquidate` for 100%")
range(602, 603): (toLiquidator == _totalColToSend)
range(755, 756): (0) && Cdps[vars.cdpId].status == Status.active)
range(818, 819): (0) && Cdps[vars.cdpId].status == Status.active)
File: /packages/contracts/contracts/CdpManagerStorage.sol
range(145, 146): (1/2) = d^720 => d = (1/2)^(1/720)
range(241, 242): (locked == OPEN, "CdpManager: Reentrancy in nonReentrant call")
range(474, 475): (index <= idxLast, "CdpManagerStorage: CDP indexing overflow!")
range(648, 649): (Cdps[_cdpId].status == Status.active, "CdpManager: Cdp does not exist or is closed")
File: /packages/contracts/contracts/CollSurplusPool.sol
range(119, 120): (msg.sender == cdpManagerAddress, "CollSurplusPool: Caller is not CdpManager")
range(123, 124): (msg.sender == activePoolAddress, "CollSurplusPool: Caller is not Active Pool")
range(142, 143): (token != address(collateral), "CollSurplusPool: Cannot Sweep Collateral")
range(145, 146): (amount <= balance, "CollSurplusPool: Attempt to sweep more than balance")
File: /packages/contracts/contracts/EBTCToken.sol
range(182, 183): () == _CACHED_CHAIN_ID)
range(218, 219): (recoveredAddress == owner, "EBTC: invalid signature")
range(246, 247): (sender != address(0), "EBTCToken: zero sender!")
range(247, 248): (recipient != address(0), "EBTCToken: zero recipient!")
range(262, 263): (account != address(0), "EBTCToken: mint to zero recipient!")
range(270, 271): (account != address(0), "EBTCToken: burn from zero account!")
range(285, 286): (owner != address(0), "EBTCToken: zero approve owner!")
range(286, 287): (spender != address(0), "EBTCToken: zero approve spender!")
range(296, 297): (0) && _recipient != address(this)
range(323, 324): (msg.sender == cdpManagerAddress, "EBTC: Caller is not CdpManager")
File: /packages/contracts/contracts/PriceFeed.sol
range(223, 224): (fallbackCaller) == address(0))
range(586, 587): (fallbackCaller) != address(0))
File: /packages/contracts/contracts/SortedCdps.sol
range(180, 181): (startNodeId == dummyId ? data.tail : startNodeId)
range(184, 185): (_currentCdpId != dummyId)
range(186, 187): (_currentCdpId) == owner)
range(243, 244): (startNodeId == dummyId ? data.tail : startNodeId)
range(247, 248): (_currentCdpId != dummyId)
range(249, 250): (_currentCdpId) == owner)
range(315, 316): (startNodeId == dummyId ? data.tail : startNodeId)
range(317, 318): (_currentCdpId != dummyId)
range(319, 320): (_currentCdpId) == owner)
range(351, 352): (cdpManager.getCdpStatus(_id) == 0, "SortedCdps: new id is NOT nonExistent!")
range(368, 369): (_id != dummyId, "SortedCdps: Id cannot be zero")
range(519, 520): (data.head == _id || data.tail == _id)
range(522, 523): (_node.nextId != dummyId && _node.prevId != dummyId)
range(628, 629): (prevId != dummyId && !_validInsertPosition(_NICR, prevId, nextId))
range(651, 652): (nextId != dummyId && !_validInsertPosition(_NICR, prevId, nextId))
range(714, 715): (msg.sender == address(cdpManager), "SortedCdps: Caller is not the CdpManager")
File: /packages/contracts/contracts/LeverageMacroBase.sol
range(44, 45): (owner() == msg.sender, "Must be owner")
range(250, 251): (check.value <= valueToCheck, "!LeverageMacroReference: let post check")
range(252, 253): (check.value == valueToCheck, "!LeverageMacroReference: equal post check")
range(351, 352): (initiator == address(this), "LeverageMacroReference: wrong initiator for flashloan")
range(451, 452): (addy != address(borrowerOperations))
range(452, 453): (addy != address(sortedCdps))
range(453, 454): (addy != address(activePool))
range(454, 455): (addy != address(cdpManager))
range(455, 456): (addy != address(this))
File: /packages/contracts/contracts/SimplifiedDiamondLike.sol
range(51, 52): (msg.sender == owner)
range(55, 56): (sig != 0x94b24d09)
range(66, 67): (msg.sender == owner)
range(76, 77): (msg.sender == address(this))
range(110, 111): (msg.sender == owner, "Must be owner")
range(186, 187): (facet != address(0), "Diamond: Function does not exist")
File: /packages/contracts/contracts/Dependencies/Auth.sol
range(37, 38): (address(auth) != address(0) && auth.canCall(user, address(this), functionSig))
range(44, 45): (msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig))
File: /packages/contracts/contracts/Dependencies/AuthNoOwner.sol
range(34, 35): (address(auth) != address(0) && auth.canCall(user, address(this), functionSig))
range(55, 56): (address(_authority) == address(0), "Auth: authority is non-zero")
File: /packages/contracts/contracts/Dependencies/EbtcBase.sol
range(108, 109): (feePercentage <= _maxFeePercentage, "Fee exceeded provided maximum")
File: /packages/contracts/contracts/Dependencies/ReentrancyGuard.sol
range(13, 14): (locked == OPEN, "ReentrancyGuard: Reentrancy in nonReentrant call")
File: /packages/contracts/contracts/Dependencies/RolesAuthority.sol
range(123, 124): () == 0)
</details>

[SWC-111] Use of deprecated functions, aliases and keywords

Description:<br> Several functions and operators in Solidity are deprecated. Using them leads to reduced code quality. With new major versions of the Solidity compiler, deprecated functions and operators may result in side effects and compile errors. https://swcregistry.io/docs/SWC-111 <br> <br>Recommendation:<br> Solidity provides alternatives to the deprecated constructions. Most of them are aliases, thus replacing old constructions will not break current behavior. <br> <br><br> There are 48 instances of this issue:

<details><summary>see instances</summary>
File: /packages/contracts/contracts/ActivePool.sol
24:     string public constant NAME = "ActivePool";
File: /packages/contracts/contracts/BorrowerOperations.sol
29:     string public constant NAME = "BorrowerOperations";
32:     bytes32 private constant _PERMIT_POSITION_MANAGER_TYPEHASH =
38:     bytes32 private constant _TYPE_HASH =
41:     string internal constant _VERSION = "1";
File: /packages/contracts/contracts/CdpManagerStorage.sol
21:     uint128 public constant UNSET_TIMESTAMP = type(uint128).max;
22:     uint128 public constant MINIMUM_GRACE_PERIOD = 15 minutes;
122:     string public constant NAME = "CdpManager";
139:     uint256 public constant SECONDS_IN_ONE_MINUTE = 60;
141:     uint256 public constant MIN_REDEMPTION_FEE_FLOOR = (DECIMAL_PRECISION * 5) / 1000; // 0.5%
149:     uint256 public constant MIN_MINUTE_DECAY_FACTOR = 1; // Non-zero
150:     uint256 public constant MAX_MINUTE_DECAY_FACTOR = 999999999999999999; // Corresponds to a very fast decay rate, but not too extreme
File: /packages/contracts/contracts/CollSurplusPool.sol
19:     string public constant NAME = "CollSurplusPool";
File: /packages/contracts/contracts/EBTCToken.sol
28:     string internal constant _NAME = "EBTC Stablecoin";
29:     string internal constant _SYMBOL = "EBTC";
30:     string internal constant _VERSION = "1";
31:     uint8 internal constant _DECIMALS = 18;
36:     bytes32 private constant _PERMIT_TYPEHASH =
39:     bytes32 private constant _TYPE_HASH =
File: /packages/contracts/contracts/PriceFeed.sol
22:     string public constant NAME = "PriceFeed";
32:     uint256 public constant TIMEOUT_ETH_BTC_FEED = 4800; // 1 hours & 20min: 60 * 80
33:     uint256 public constant TIMEOUT_STETH_ETH_FEED = 90000; // 25 hours: 60 * 60 * 25
36:     uint256 public constant MAX_PRICE_DEVIATION_FROM_PREVIOUS_ROUND = 5e17; // 50%
42:     uint256 public constant MAX_PRICE_DIFFERENCE_BETWEEN_ORACLES = 5e16; // 5%
File: /packages/contracts/contracts/SortedCdps.sol
52:     string public constant NAME = "SortedCdps";
60:     uint256 constant ADDRESS_SHIFT = 96; // 8 * 12; Puts the address at leftmost bytes32 position
61:     uint256 constant BLOCK_SHIFT = 64; // 8 * 8; Puts the block value after the address
80:     bytes32 public constant dummyId =
File: /packages/contracts/contracts/HintHelpers.sol
12:     string public constant NAME = "HintHelpers";
File: /packages/contracts/contracts/LeverageMacroBase.sol
37:     bytes32 constant FLASH_LOAN_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");
File: /packages/contracts/contracts/SimplifiedDiamondLike.sol
39:     bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");
File: /packages/contracts/contracts/Dependencies/ERC3156FlashLender.sol
9:     uint256 public constant MAX_BPS = 10_000;
10:     uint256 public constant MAX_FEE_BPS = 1_000; // 10%
11:     bytes32 public constant FLASH_SUCCESS_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan");
File: /packages/contracts/contracts/Dependencies/EbtcBase.sol
19:     uint256 public constant LICR = 1030000000000000000; // 103%
22:     uint256 public constant MCR = 1100000000000000000; // 110%
25:     uint256 public constant CCR = 1250000000000000000; // 125%
28:     uint256 public constant LIQUIDATOR_REWARD = 2e17;
31:     uint256 public constant MIN_NET_STETH_BALANCE = 2e18;
33:     uint256 public constant PERCENT_DIVISOR = 200; // dividing by 200 yields 0.5%
35:     uint256 public constant BORROWING_FEE_FLOOR = 0; // 0.5%
37:     uint256 public constant STAKING_REWARD_SPLIT = 5_000; // taking 50% cut from staking reward
39:     uint256 public constant MAX_REWARD_SPLIT = 10_000;
File: /packages/contracts/contracts/Dependencies/EbtcMath.sol
6:     uint256 internal constant DECIMAL_PRECISION = 1e18;
7:     uint256 public constant MAX_TCR = type(uint256).max;
18:     uint256 internal constant NICR_PRECISION = 1e20;
File: /packages/contracts/contracts/Dependencies/ReentrancyGuard.sol
8:     uint256 internal constant OPEN = 1;
9:     uint256 internal constant LOCKED = 2;
</details>

[SWC-XX2] Incorrect comparison implementation

Description:<br> Comparison will be ignored.<br> <br><br>Recommendation:<br> Use require or if to compare values.<br> <br><br> There are 80 instances of this issue:

<details><summary>see instances</summary>
File: /packages/contracts/contracts/ActivePool.sol
range(235, 236): (msg.sender == cdpManagerAddress, "ActivePool: Caller is not CdpManager")
range(268, 269): (amount <= maxFlashLoan(token), "ActivePool: Too much")
range(317, 318): (token == address(collateral), "ActivePool: collateral Only")
range(373, 374): (token != address(collateral), "ActivePool: Cannot Sweep Collateral")
range(376, 377): (amount <= balance, "ActivePool: Attempt to sweep more than balance")
range(406, 407): (_newFee <= MAX_FEE_BPS, "ERC3156FlashLender: _newFee should <= MAX_FEE_BPS")
File: /packages/contracts/contracts/BorrowerOperations.sol
range(144, 145): (locked == OPEN, "BorrowerOperations: Reentrancy in nonReentrant call")
range(665, 666): () == _CACHED_CHAIN_ID)
range(825, 826): (status == 1, "BorrowerOperations: Cdp does not exist or is closed")
range(830, 831): (status == 0, "BorrowerOperations: Cdp is active or has been previously closed")
range(1084, 1085): (amount <= maxFlashLoan(token), "BorrowerOperations: Too much")
range(1114, 1115): (token == address(ebtcToken), "BorrowerOperations: EBTC Only")
range(1154, 1155): (_newFee <= MAX_FEE_BPS, "ERC3156FlashLender: _newFee should <= MAX_FEE_BPS")
File: /packages/contracts/contracts/CdpManager.sol
range(331, 332): (redemptionsPaused == false, "CdpManager: Redemptions Paused")
range(368, 369): (currentBorrower != address(0) && getSyncedICR(_cId, totals.price) < MCR)
range(496, 497): (_cnt > 0 && _id != bytes32(0))
range(501, 502): (_toRemoveIds[0] == _start, "CdpManager: batchRemoveSortedCdpIds check start error")
range(677, 678): (decayedBaseRate <= DECIMAL_PRECISION, "CdpManager: baseRate too large!")
File: /packages/contracts/contracts/LiquidationLibrary.sol
range(55, 56): (_partialAmount != 0, "LiquidationLibrary: use `liquidate` for 100%")
range(602, 603): (toLiquidator == _totalColToSend)
range(755, 756): (0) && Cdps[vars.cdpId].status == Status.active)
range(818, 819): (0) && Cdps[vars.cdpId].status == Status.active)
File: /packages/contracts/contracts/CdpManagerStorage.sol
range(145, 146): (1/2) = d^720 => d = (1/2)^(1/720)
range(241, 242): (locked == OPEN, "CdpManager: Reentrancy in nonReentrant call")
range(474, 475): (index <= idxLast, "CdpManagerStorage: CDP indexing overflow!")
range(648, 649): (Cdps[_cdpId].status == Status.active, "CdpManager: Cdp does not exist or is closed")
File: /packages/contracts/contracts/CollSurplusPool.sol
range(119, 120): (msg.sender == cdpManagerAddress, "CollSurplusPool: Caller is not CdpManager")
range(123, 124): (msg.sender == activePoolAddress, "CollSurplusPool: Caller is not Active Pool")
range(142, 143): (token != address(collateral), "CollSurplusPool: Cannot Sweep Collateral")
range(145, 146): (amount <= balance, "CollSurplusPool: Attempt to sweep more than balance")
File: /packages/contracts/contracts/EBTCToken.sol
range(182, 183): () == _CACHED_CHAIN_ID)
range(218, 219): (recoveredAddress == owner, "EBTC: invalid signature")
range(246, 247): (sender != address(0), "EBTCToken: zero sender!")
range(247, 248): (recipient != address(0), "EBTCToken: zero recipient!")
range(262, 263): (account != address(0), "EBTCToken: mint to zero recipient!")
range(270, 271): (account != address(0), "EBTCToken: burn from zero account!")
range(285, 286): (owner != address(0), "EBTCToken: zero approve owner!")
range(286, 287): (spender != address(0), "EBTCToken: zero approve spender!")
range(296, 297): (0) && _recipient != address(this)
range(323, 324): (msg.sender == cdpManagerAddress, "EBTC: Caller is not CdpManager")
File: /packages/contracts/contracts/PriceFeed.sol
range(223, 224): (fallbackCaller) == address(0))
range(586, 587): (fallbackCaller) != address(0))
File: /packages/contracts/contracts/SortedCdps.sol
range(180, 181): (startNodeId == dummyId ? data.tail : startNodeId)
range(184, 185): (_currentCdpId != dummyId)
range(186, 187): (_currentCdpId) == owner)
range(243, 244): (startNodeId == dummyId ? data.tail : startNodeId)
range(247, 248): (_currentCdpId != dummyId)
range(249, 250): (_currentCdpId) == owner)
range(315, 316): (startNodeId == dummyId ? data.tail : startNodeId)
range(317, 318): (_currentCdpId != dummyId)
range(319, 320): (_currentCdpId) == owner)
range(351, 352): (cdpManager.getCdpStatus(_id) == 0, "SortedCdps: new id is NOT nonExistent!")
range(368, 369): (_id != dummyId, "SortedCdps: Id cannot be zero")
range(519, 520): (data.head == _id || data.tail == _id)
range(522, 523): (_node.nextId != dummyId && _node.prevId != dummyId)
range(628, 629): (prevId != dummyId && !_validInsertPosition(_NICR, prevId, nextId))
range(651, 652): (nextId != dummyId && !_validInsertPosition(_NICR, prevId, nextId))
range(714, 715): (msg.sender == address(cdpManager), "SortedCdps: Caller is not the CdpManager")
File: /packages/contracts/contracts/LeverageMacroBase.sol
range(44, 45): (owner() == msg.sender, "Must be owner")
range(250, 251): (check.value <= valueToCheck, "!LeverageMacroReference: let post check")
range(252, 253): (check.value == valueToCheck, "!LeverageMacroReference: equal post check")
range(351, 352): (initiator == address(this), "LeverageMacroReference: wrong initiator for flashloan")
range(451, 452): (addy != address(borrowerOperations))
range(452, 453): (addy != address(sortedCdps))
range(453, 454): (addy != address(activePool))
range(454, 455): (addy != address(cdpManager))
range(455, 456): (addy != address(this))
File: /packages/contracts/contracts/SimplifiedDiamondLike.sol
range(51, 52): (msg.sender == owner)
range(55, 56): (sig != 0x94b24d09)
range(66, 67): (msg.sender == owner)
range(76, 77): (msg.sender == address(this))
range(110, 111): (msg.sender == owner, "Must be owner")
range(186, 187): (facet != address(0), "Diamond: Function does not exist")
File: /packages/contracts/contracts/Dependencies/Auth.sol
range(37, 38): (address(auth) != address(0) && auth.canCall(user, address(this), functionSig))
range(44, 45): (msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig))
File: /packages/contracts/contracts/Dependencies/AuthNoOwner.sol
range(34, 35): (address(auth) != address(0) && auth.canCall(user, address(this), functionSig))
range(55, 56): (address(_authority) == address(0), "Auth: authority is non-zero")
File: /packages/contracts/contracts/Dependencies/EbtcBase.sol
range(108, 109): (feePercentage <= _maxFeePercentage, "Fee exceeded provided maximum")
File: /packages/contracts/contracts/Dependencies/ReentrancyGuard.sol
range(13, 14): (locked == OPEN, "ReentrancyGuard: Reentrancy in nonReentrant call")
File: /packages/contracts/contracts/Dependencies/RolesAuthority.sol
range(123, 124): () == 0)
</details>

[SWC-110] require() should be used instead of assert()

Description:<br> Prior to solidity version 0.8.0, hitting an assert consumes the remainder of the transaction\’s available gas rather than returning it, as require()/revert() do. assert() should be avoided even past solidity version 0.8.0 as its documentation states that β€œThe assert function creates an error of type Panic(uint256). … Properly functioning code should never create a Panic, not even on invalid external input. If this happens, then there is a bug in your contract which you should fix”. https://swcregistry.io/docs/SWC-110/ <br> <br>Recommendation:<br> Consider whether the condition checked in the assert() is actually an invariant.If not, replace the assert() statement with a require() statement. If the exception is indeed caused by unexpected behaviour of the code, fix the underlying bug(s) that allow the assertion to be violated. <br> <br><br> There are 6 instances of this issue:

<details><summary>see instances</summary>
File: /packages/contracts/contracts/LiquidationLibrary.sol
564:         assert(toLiquidator < _totalColToSend); // Assert is correct here for Echidna
File: /packages/contracts/contracts/LeverageMacroBase.sol
43:     function _assertOwner() internal {
125:         _assertOwner();
215:         _assertOwner();
235:         _assertOwner();
File: /packages/contracts/contracts/LeverageMacroReference.sol
51:         _assertOwner();
</details>

#0 - c4-pre-sort

2023-11-18T00:58:30Z

raymondfam marked the issue as sufficient quality report

#1 - c4-judge

2023-12-01T16:28:08Z

fatherGoose1 marked the issue as grade-b

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