Platform: Code4rena
Start Date: 05/09/2023
Pot Size: $50,000 USDC
Total HM: 2
Participants: 16
Period: 6 days
Judge: GalloDaSballo
Total Solo HM: 2
Id: 284
League: ETH
Rank: 7/16
Findings: 1
Award: $311.51
🌟 Selected for report: 0
🚀 Solo Findings: 0
311.5065 USDC - $311.51
In the delegate*
function of DelegateRegistry
, when enable
is true and loadedFrom != Storage.DELEGATION_EMPTY != Storage.DELEGATION_REVOKED
, which means that the location already has a delegation, the DelegateAll
event will be triggered again, causing inconvenience to the listeners and waste user's gas.
function delegateAll(address to, bytes32 rights, bool enable) external payable override returns (bytes32 hash) { hash = Hashes.allHash(msg.sender, rights, to); bytes32 location = Hashes.location(hash); address loadedFrom = _loadFrom(location); if (enable) { if (loadedFrom == Storage.DELEGATION_EMPTY) { _pushDelegationHashes(msg.sender, to, hash); _writeDelegationAddresses(location, msg.sender, to, address(0)); if (rights != "") _writeDelegation(location, Storage.POSITIONS_RIGHTS, rights); } else if (loadedFrom == Storage.DELEGATION_REVOKED) { _updateFrom(location, msg.sender); } } else if (loadedFrom == msg.sender) { _updateFrom(location, Storage.DELEGATION_REVOKED); } emit DelegateAll(msg.sender, to, rights, enable); }
checkAndPullByType
, there is no authorization check for ERC721 and 1155 tokens like there is for ERC20.ERC20 checks the allowance before transferring, while ERC721 and 1155 do not check.
if (IERC20(underlyingContract).allowance(msg.sender, address(this)) < underlyingAmount) { revert Errors.InsufficientAllowanceOrInvalidToken(); }
I actually think that this check for ERC20 can be eliminated, because if the allowance is insufficient, it will also revert during the transfer. This check is somewhat redundant and wastes gas.
previewOrder
function is called with unacceptable minimumReceived
and maximumSpent
arraysAccording to Seaport's documentation, for previewOrder
, if the parameters do not meet the requirements, it should return an order with penalties rather than directly reverting.
An optimal Seaport app should return an order with penalties when its
previewOrder
function is called with unacceptableminimumReceived
andmaximumSpent
arrays, so that the caller can learn what the Seaport app expects.
if (!(minimumReceived.length == 1 && maximumSpent.length == 1)) revert CreateOffererErrors.NoBatchWrapping(); if (minimumReceived[0].itemType != ItemType.ERC721 || minimumReceived[0].token != address(this) || minimumReceived[0].amount != 1) { revert CreateOffererErrors.MinimumReceivedInvalid(minimumReceived[0]); } if (maximumSpent[0].itemType != ItemType.ERC721 && maximumSpent[0].itemType != ItemType.ERC20 && maximumSpent[0].itemType != ItemType.ERC1155) { revert CreateOffererErrors.MaximumSpentInvalid(maximumSpent[0]); }
transferFrom
in CreateOfferer miss onlySeaport
modifiergenerateOrder
and ratifyOrder
both have onlySeaport
modifier, as one necessary step in seaport's stage, transferFrom
miss onlySeaport
modifier.
#0 - GalloDaSballo
2023-09-24T17:50:04Z
Repeating the execution of the same delegate should revert instead of triggering the event repeatedly R
In checkAndPullByType, there is no authorization check for ERC721 and 1155 tokens like there is for ERC20. I
App should return an order with penalties when its previewOrder function is called with unacceptable minimumReceived and maximumSpent arrays L
transferFrom in CreateOfferer miss onlySeaport modifier Invalid
1L 1R
2L 1R from dups
3L 2R
#1 - c4-judge
2023-10-02T09:15:46Z
GalloDaSballo marked the issue as grade-b
#2 - c4-judge
2023-10-02T11:55:38Z
GalloDaSballo marked the issue as grade-a
#3 - GalloDaSballo
2023-10-02T11:55:49Z
TODO: Re-calculate after post-judging QA
#4 - 0xfoobar
2023-10-03T23:30:53Z
"Repeating the execution of the same delegate should revert instead of triggering the event repeatedly" -> disagree here, cleaner to have it be a no-op than revert. more easily composable
"In checkAndPullByType, there is no authorization check for ERC721 and 1155 tokens like there is for ERC20." -> the method calls in these functions are actually used to distinguish asset types - allowance() method is unique on ERC20, ownerOf(uint256) is unique on ERC721, safeTransferFrom(*args) is unique on ERC1155. so good-faith asset contracts can't be confused for one another and exploited that way
"App should return an order with penalties when its previewOrder function is called with unacceptable minimumReceived and maximumSpent arrays" -> we're going for simplicity here, no orders with penalties are desired, just straightforward fulfillment
"transferFrom in CreateOfferer miss onlySeaport modifier" -> transferFrom is called by the conduit not Seaport itself so this would break things
#5 - c4-sponsor
2023-10-03T23:31:16Z
0xfoobar (sponsor) disputed