reNFT - 7ashraf's results

Collateral-free, permissionless, and highly customizable EVM NFT rentals.

General Information

Platform: Code4rena

Start Date: 08/01/2024

Pot Size: $83,600 USDC

Total HM: 23

Participants: 116

Period: 10 days

Judge: 0xean

Total Solo HM: 1

Id: 317

League: ETH

reNFT

Findings Distribution

Researcher Performance

Rank: 90/116

Findings: 1

Award: $12.58

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

12.582 USDC - $12.58

Labels

bug
grade-b
QA (Quality Assurance)
sufficient quality report
edited-by-warden
Q-12

External Links

Quality Assurance Report

Summary

The smart contract repository review identified key issues, primarily the need for equal-length array checks in functions like _processBaseOrderOffer and others. Instances of using array objects without validation were noted in _checkTransaction and sections of Create.sol, suggesting the implementation of validation checks. Additionally, the executeAction function in Kernel.sol lacks a final else statement with a revert, impacting event accuracy. Hardcoded zero values, as seen in Stop.sol, could benefit from more descriptive values. Lastly, functions with empty bodies and unclear readability indicate areas for code clarity improvement.

Summary Table:

Issue NumberTitleNumber of Instances
L-01Require the two arrays to have the same length6
L-02Check if the array object is valid or not7
L-03Add final else statement with revert to avoid false emits1
L-04Add a list of known roles to choose from them instead of validating roles1
L-05Avoid using hardcoded zero value1
L-06Disable fee changing when a settle payment is running1
L-07skim should be called after settlePayment and settlePaymentBatch1
N-01Hard to read function, consider cleaning1
N-02Empty function body1
N-03Emit an event on fee change2
N-04Reverting with an error is more convenient than returning address(0)1
N-05Reduce redundant code1

[L-01] Require the two arrays to have the same length

Instances

function _processBaseOrderOffer(
        Item[] memory rentalItems,
        SpentItem[] memory offers,
        uint256 startIndex
    ) internal pure {
+        require rentalItems.length == offers.length;
        ...
    }
function _processPayOrderOffer(
        Item[] memory rentalItems,
        SpentItem[] memory offers,
        uint256 startIndex
    ) internal pure {
+        require rentalItems.length == offers.length;
        ...
    }
    function _processBaseOrderConsideration(
        Item[] memory rentalItems,
        ReceivedItem[] memory considerations,
        uint256 startIndex
    ) internal pure {
+        require rentalItems.length == considerations.length;
        ...
    }
    function _convertToItems(
        SpentItem[] memory offers,
        ReceivedItem[] memory considerations,
        OrderType orderType
    ) internal pure returns (Item[] memory items) {
+        require offers.length == considerations.length;
        ...
    }
    function _addHooks(
        Hook[] memory hooks,
        SpentItem[] memory offerItems,
        address rentalWallet
    ) internal {
+        require hooks.length == offerItems.length;
        ...
    }
    function _removeHooks(
        Hook[] calldata hooks,
        Item[] calldata rentalItems,
        address rentalWallet
    ) internal {
+        require hooks.length == rentalItems.length;
        ...
    }

[L-02] Check if the array object is valid or not

Instances

            ReceivedItem memory consideration = considerations[i];
+           //check for valid consideration
            SpentItem memory offer = offers[i];
            SpentItem memory offer = offers[i];
            ReceivedItem memory consideration = considerations[i];
            target = hooks[i].target;
            RentalAssetUpdate memory asset = rentalAssetUpdates[i];
            RentalAssetUpdate memory asset = rentalAssetUpdates[i];

[L-03] Add final else statement with revert to avoid false emits

Instances

    function executeAction(Actions action_, address target_) external onlyExecutor {
        if (action_ == Actions.InstallModule) {
            ensureContract(target_);
            ensureValidKeycode(Module(target_).KEYCODE());
            _installModule(Module(target_));
        } else if (action_ == Actions.UpgradeModule) {
            ensureContract(target_);
            ensureValidKeycode(Module(target_).KEYCODE());
            _upgradeModule(Module(target_));
        } else if (action_ == Actions.ActivatePolicy) {
            ensureContract(target_);
            _activatePolicy(Policy(target_));
        } else if (action_ == Actions.DeactivatePolicy) {
            ensureContract(target_);
            _deactivatePolicy(Policy(target_));
        } else if (action_ == Actions.MigrateKernel) {
            ensureContract(target_);
            _migrateKernel(Kernel(target_));
        } else if (action_ == Actions.ChangeExecutor) {
            executor = target_;
        } else if (action_ == Actions.ChangeAdmin) {
            admin = target_;
        }
+       //add else statement and revert
        emit Events.ActionExecuted(action_, target_);
    }

[L-04] Add a list of known roles to choose from them instead of validating roles

Instances

    function grantRole(Role role_, address addr_) public onlyAdmin {
        ...
        emit Events.RoleGranted(role_, addr_);
    }

[L-05] Avoid using hardcoded zero value

Instances

        bool success = ISafe(order.rentalWallet).execTransactionFromModule(
            // Stop policy inherits the reclaimer package.
            address(this),
            // value.
172:        0,
            // The encoded call to the `reclaimRentalOrder` function.
            abi.encodeWithSelector(this.reclaimRentalOrder.selector, order),
            // Safe must delegate call to the stop policy so that it is the msg.sender.
            Enum.Operation.DelegateCall
        );

[L-06] Disable fee changing when a settle payment is running

Instances

    function setFee(uint256 feeNumerator) external onlyByProxy permissioned {
+       //Add lock
        // Cannot accept a fee numerator greater than 10000.
        if (feeNumerator > 10000) {
            revert Errors.PaymentEscrow_InvalidFeeNumerator();
        }

        // Set the fee.
        fee = feeNumerator;
+       //Release lock
    }

[L-07] skim should be called after settlePayment and settlePaymentBatch

Instances

    function settlePayment(RentalOrder calldata order) external onlyByProxy permissioned {
        // Settle all payments for the order.
        _settlePayment(
            order.items,
            order.orderType,
            order.lender,
            order.renter,
            order.startTimestamp,
            order.endTimestamp
        );
    }

[N-01] Hard to read function, consider cleaning

Instances

function _checkTransaction(address from, address to, bytes memory data) private view {
    ...
    }

Mitigation

  • Consider adding more comments
  • splitting the code into multiple methods

[N-02] Empty function body

Although it is mentioned that the function is left empty, but is not implementedbefore an audit or a final release. Also no reason was mentioned.

Instances

    /**
     * @notice Performs any checks after execution. This is left unimplemented.
     *
     * @param txHash Hash of the transaction.
     * @param success Whether the transaction succeeded.
     */
    function checkAfterExecution(bytes32 txHash, bool success) external override {}

    /**

[N-03] Emit an event on fee change

Instances

    function setFee(uint256 feeNumerator) external onlyByProxy permissioned {
        // Cannot accept a fee numerator greater than 10000.
        if (feeNumerator > 10000) {
            revert Errors.PaymentEscrow_InvalidFeeNumerator();
        }

        // Set the fee.
        fee = feeNumerator;
+       //emit fee chanaged event
    }

    function settlePaymentBatch(
        RentalOrder[] calldata orders
    ) external onlyByProxy permissioned {
        // Loop through each order.
        for (uint256 i = 0; i < orders.length; ++i) {
            // Settle all payments for the order.
            _settlePayment(
                orders[i].items,
                orders[i].orderType,
                orders[i].lender,
                orders[i].renter,
                orders[i].startTimestamp,
                orders[i].endTimestamp
            );
        }
    }

[N-04] Reverting with an error is more convenient than returning address(0)

Consider adding a revert message like failed to fetch or hook not available instead of returning address(0) to the user for more convenient and understandable logic

Instances

        return hookStatus[hook] != 0 ? hook : address(0);

[N-05] Reduce redundant code

Utilize the use of removeRental inside removeRentalBatch instead of repeating the same logic all over again

Instances

Mitigation

Rewrite the following method

    function removeRentalsBatch(
        bytes32[] calldata orderHashes,
        RentalAssetUpdate[] calldata rentalAssetUpdates
    ) external onlyByProxy permissioned {
        // Delete the orders from storage.
        for (uint256 i = 0; i < orderHashes.length; ++i) {
            // The order must exist to be deleted.
            if (!orders[orderHashes[i]]) {
                revert Errors.StorageModule_OrderDoesNotExist(orderHashes[i]);
            } else {
                // Delete the order from storage.
                delete orders[orderHashes[i]];
            }
        }

        // Process each rental asset.
        for (uint256 i = 0; i < rentalAssetUpdates.length; ++i) {
            RentalAssetUpdate memory asset = rentalAssetUpdates[i];

            // Reduce the amount of tokens for the particular rental ID.
            rentedAssets[asset.rentalId] -= asset.amount;
        }
    }

into something like this

    function removeRentalsBatch(
        bytes32[] calldata orderHashes,
        RentalAssetUpdate[] calldata rentalAssetUpdates
    ) external onlyByProxy permissioned {
        // Delete the orders from storage.
        for (uint256 i = 0; i < orderHashes.length; ++i) {
           removeRental(orderHash[i], rentalAssetUpdates);
        }

       
    }

#0 - 141345

2024-01-22T13:50:04Z

334 7ashraf l r nc 0 1 10

L 1 n L 2 n L 3 n L 4 n L 5 n L 6 d dup of https://github.com/code-423n4/2024-01-renft-findings/issues/463 L 7 r N 1 n N 2 n N 3 n N 4 n N 5 n

#1 - c4-judge

2024-01-27T20:31:10Z

0xean 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