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: 100/116
Findings: 2
Award: $5.79
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: JCN
Also found by: 0xDING99YA, 0xpiken, ABAIKUNANBAEV, AkshaySrivastav, Audinarey, Aymen0909, DanielArmstrong, J4X, Krace, KupiaSec, Qkite, Ward, evmboi32, fnanni, hash, juancito, kaden, krikolkk, ravikiranweb3, rbserver, rvierdiiev, serial-coder, trachev, zach, zzzitron
3.987 USDC - $3.99
https://github.com/re-nft/smart-contracts/blob/3ddd32455a849c3c6dc3c3aad7a33a6c9b44c291/src/packages/Signer.sol#L162 https://github.com/re-nft/smart-contracts/blob/3ddd32455a849c3c6dc3c3aad7a33a6c9b44c291/src/packages/Signer.sol#L218
In Signer.sol
, there are some functions where constructor of EIP-712 typehash is not made properly when generating hash. This makes the signature verification process not work as expected resulting in functions reverts due to generation of different signatures and non-compliance to EIP-712
First, it's _deviateRentalOrderHash()
that constructs the typehash like this:
function _deriveRentalOrderHash( RentalOrder memory order ) internal view returns (bytes32) { // Create arrays for items and hooks. bytes32[] memory itemHashes = new bytes32[](order.items.length); bytes32[] memory hookHashes = new bytes32[](order.hooks.length); // Iterate over each item. for (uint256 i = 0; i < order.items.length; ++i) { // Hash the item. itemHashes[i] = _deriveItemHash(order.items[i]); } // Iterate over each hook. for (uint256 i = 0; i < order.hooks.length; ++i) { // Hash the hook. hookHashes[i] = _deriveHookHash(order.hooks[i]); } return keccak256( abi.encode( _RENTAL_ORDER_TYPEHASH, order.seaportOrderHash, keccak256(abi.encodePacked(itemHashes)), keccak256(abi.encodePacked(hookHashes)), order.orderType, order.lender, order.renter, order.startTimestamp, order.endTimestamp ) ); }
However, the rentalOrderTypeString
is declared like that:
bytes memory rentalOrderTypeString = abi.encodePacked( "RentalOrder(bytes32 seaportOrderHash,Item[] items,Hook[] hooks,uint8 orderType,address lender,address renter,address rentalWallet,uint256 startTimestamp,uint256 endTimestamp)" );
The problem is that the rentalWallet
param is missing in this case.
This problem is also present _deriveOrderMetadataHash()
function where orderType
and emittedExtraData
params are missing:
function _deriveOrderMetadataHash( OrderMetadata memory metadata ) internal view returns (bytes32) { // Create array for hooks. bytes32[] memory hookHashes = new bytes32[](metadata.hooks.length); // Iterate over each hook. for (uint256 i = 0; i < metadata.hooks.length; ++i) { // Hash the hook hookHashes[i] = _deriveHookHash(metadata.hooks[i]); } // Derive and return the metadata hash as specified by EIP-712. return keccak256( abi.encode( _ORDER_METADATA_TYPEHASH, metadata.rentDuration, keccak256(abi.encodePacked(hookHashes)) ) ); }
orderMetadataTypeString
:
bytes memory orderMetadataTypeString = abi.encodePacked( "OrderMetadata(uint8 orderType,uint256 rentDuration,Hook[] hooks,bytes emittedExtraData)" );
Manual review.
keccak256( abi.encode( _RENTAL_ORDER_TYPEHASH, order.seaportOrderHash, keccak256(abi.encodePacked(itemHashes)), keccak256(abi.encodePacked(hookHashes)), order.orderType, order.lender, order.renter, + order.rentalWallet, order.startTimestamp, order.endTimestamp ) );
keccak256( abi.encode( _ORDER_METADATA_TYPEHASH, + metadata.orderType, metadata.rentDuration, keccak256(abi.encodePacked(hookHashes)), + metadata.emittedExtraData ));
Other
#0 - c4-pre-sort
2024-01-21T17:51:09Z
141345 marked the issue as duplicate of #239
#1 - c4-judge
2024-01-28T21:05:56Z
0xean marked the issue as satisfactory
#2 - c4-judge
2024-01-30T11:32:24Z
0xean marked the issue as not a duplicate
#3 - c4-judge
2024-01-30T11:33:00Z
0xean marked the issue as duplicate of #385
#4 - c4-judge
2024-01-30T11:33:03Z
0xean marked the issue as partial-25
#5 - c4-judge
2024-01-30T14:24:45Z
0xean changed the severity to 3 (High Risk)
🌟 Selected for report: BI_security
Also found by: 0xPsuedoPandit, 0xpiken, ABAIKUNANBAEV, Beepidibop, CipherSleuths, EV_om, Giorgio, Hajime, J4X, KingNFT, KupiaSec, NentoR, SBSecurity, SpicyMeatball, Tendency, Ward, ZdravkoHr, boringslav, deepplus, hals, hash, haxatron, jasonxiale, juancito, pkqs90, plasmablocks, ravikiranweb3, rokinot, rvierdiiev, trachev, zaevlad, zzebra83
1.8029 USDC - $1.80
https://github.com/re-nft/smart-contracts/blob/3ddd32455a849c3c6dc3c3aad7a33a6c9b44c291/src/packages/Signer.sol#L385 https://github.com/re-nft/smart-contracts/blob/3ddd32455a849c3c6dc3c3aad7a33a6c9b44c291/src/packages/Signer.sol#L363
In Signer.sol
, when creating typehashes in _deriveRentalTypehashes()
, orderType
parameter is assigned to an incorrect type in itemTypeString
, rentalOrderTypeString
and orderMetadataTypeString
. This will make the contract non-compliant to EIP-712 and the functions that use EIP-712 signatures will effectively revert.
In _deriveRentalTypehashes()
, itemTypeString
is created this way:
bytes memory itemTypeString = abi.encodePacked( "Item(uint8 itemType,uint8 settleTo,address token,uint256 amount,uint256 identifier)" );
However, itemType
and settleTo
are of type Item
and SettleTo
and not uint8
.
For example, rentalPayloadTypeString
is created correctly:
bytes memory rentPayloadTypeString = abi.encodePacked( "RentPayload(OrderFulfillment fulfillment,OrderMetadata metadata,uint256 expiration,address intendedFulfiller)" );
It uses OrderFullfillment
type for fulfillment
param instead of uint8
, unlike in the previous example.
The next strings are orderMetadataTypeString
and rentalOrderTypeString
where also uint8
type used instead of custom types for orderType
parameter:
bytes memory rentalOrderTypeString = abi.encodePacked( "RentalOrder(bytes32 seaportOrderHash,Item[] items,Hook[] hooks,uint8 orderType,address lender,address renter,address rentalWallet,uint256 startTimestamp,uint256 endTimestamp)" );
bytes memory orderMetadataTypeString = abi.encodePacked( "OrderMetadata(uint8 orderType,uint256 rentDuration,Hook[] hooks,bytes emittedExtraData)" );
Manual review.
bytes memory rentalOrderTypeString = abi.encodePacked( - "RentalOrder(bytes32 seaportOrderHash,Item[] items,Hook[] hooks,uint8 orderType,address lender,address renter,address rentalWallet,uint256 startTimestamp,uint256 endTimestamp)" + "RentalOrder(bytes32 seaportOrderHash,Item[] items,Hook[] hooks,OrderType orderType,address lender,address renter,address rentalWallet,uint256 startTimestamp,uint256 endTimestamp)" );
bytes memory orderMetadataTypeString = abi.encodePacked( - "OrderMetadata(uint8 orderType,uint256 rentDuration,Hook[] hooks,bytes emittedExtraData)" ); + "OrderMetadata(OrderType orderType,uint256 rentDuration,Hook[] hooks,bytes emittedExtraData)" );
bytes memory itemTypeString = abi.encodePacked( - "Item(uint8 itemType,uint8 settleTo,address token,uint256 amount,uint256 identifier)" ); + "Item(ItemType itemType,SettleTo settleTo,address token,uint256 amount,uint256 identifier)" );
Other
#0 - c4-pre-sort
2024-01-21T17:51:07Z
141345 marked the issue as duplicate of #239
#1 - c4-judge
2024-01-28T21:05:55Z
0xean marked the issue as satisfactory