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
Rank: 102/116
Findings: 1
Award: $4.78
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: AkshaySrivastav
Also found by: 0xA5DF, 0xAlix2, 0xDING99YA, 0xdice91, BARW, BI_security, EV_om, J4X, Jorgect, SBSecurity, ZdravkoHr, evmboi32, hals, haxatron, imare, juancito, kaden, marqymarq10, oakcobalt, rbserver, rokinot, rvierdiiev, said, serial-coder, trachev
4.7844 USDC - $4.78
https://github.com/re-nft/smart-contracts/blob/3ddd32455a849c3c6dc3c3aad7a33a6c9b44c291/src/policies/Stop.sol#L194-L250 https://github.com/re-nft/smart-contracts/blob/3ddd32455a849c3c6dc3c3aad7a33a6c9b44c291/src/policies/Create.sol#L464-L520
In Create._rentFromZone()
the function _addHooks()
is used to process each hook but only if the hook's status is set to execute on a rental start
.
The array of hooks is used to generate the rental order, which is then hashed and saved to storage.
function _addHooks( Hook[] memory hooks, SpentItem[] memory offerItems, address rentalWallet ) internal { // Define hook target, offer item index, and an offer item. address target; uint256 itemIndex; SpentItem memory offer; // Loop through each hook in the payload. for (uint256 i = 0; i < hooks.length; ++i) { // Get the hook's target address. target = hooks[i].target; // Check that the hook is reNFT-approved to execute on rental start. if (!STORE.hookOnStart(target)) { revert Errors.Shared_DisabledHook(target); } //More Code... }
When a rental order is being stopped the same RentalOrder
struct generated and emitted during rental creation (that is in Create._rentFromZone()
) is used as the input value for the function Stop.stopRent()
, this means that the values under this order (struct) remain the same.
function _removeHooks( Hook[] calldata hooks, Item[] calldata rentalItems, address rentalWallet ) internal { // Define hook target, item index, and item. address target; uint256 itemIndex; Item memory item; // Loop through each hook in the payload. for (uint256 i = 0; i < hooks.length; ++i) { // Get the hook address. target = hooks[i].target; // Check that the hook is reNFT-approved to execute on rental stop. if (!STORE.hookOnStop(target)) { revert Errors.Shared_DisabledHook(target); } // Get the rental item index for this hook. itemIndex = hooks[i].itemIndex; //More Code... }
Since the elements in the Hooks
array remain the same the protocol assumes that the same hooks will be approved for both OnStart
and OnStop
transactions.
In a scenario where the hook being used for the rental order is approved for OnStart
but not OnStop
the _removeHooks()
function will keep reverting thereby preventing the function stopRent()
from executing.
This scenario will lead to rentals being open forever, preventing the lender from getting their tokens back.
Create._addHooks()
is executed during rental order creation using a hook
array.hooks
array is approved for OnStart
transactions but not OnStop
transactions.stopRent()
is calledstopRent()
calls _removeHooks()
which runs a loop through the array of hooks
checking if the hook is reNFT-approved to execute on rental stop
.hook
in the array that is not approved for rental stop
(OnStop
) transactions is reached the function reverts.hooks
cannot be changed.stopRent()
becomes DOS preventing the rental order from being closed.Manual Review
The Create._addHooks()
and Stop._removeHooks()
functions should be corrected from reverting on hooks that are not approved to skipping the current iteration in the loop. This change will account for hooks not approved for both OnStart
and OnStop
transactions.
Invalid Validation
#0 - c4-pre-sort
2024-01-21T17:59:01Z
141345 marked the issue as duplicate of #501
#1 - c4-judge
2024-01-28T19:34:08Z
0xean marked the issue as satisfactory