Platform: Code4rena
Start Date: 20/05/2022
Pot Size: $1,000,000 USDC
Total HM: 4
Participants: 59
Period: 14 days
Judge: leastwood
Id: 128
League: ETH
Rank: 20/59
Findings: 2
Award: $2,457.05
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Spearbit
Also found by: 0xsanson, Chom, IllIllI, OriDabush, Saw-mon_and_Natalie, broccoli, cccz, cmichel, csanuragjain, foobar, hack3r-0m, hickuphh3, hubble, hyh, ilan, kebabsec, mayo, oyc_109, peritoflores, rfa, scaraven, sces60107, shung, sorrynotsorry, tintin, twojoy, zkhorse, zzzitron
2022.1005 USDC - $2,022.10
bool roundUp
in docstringIn AmountDeriver._applyFraction
All parameters are documented properly except for bool roundUp
which does not have an explanation in the function documentation.
Add the parameter to the doc string;
* @param roundUp A boolean indicating whether the resultant amount * should be rounded up or down.
TokenTransferrer
contract is missing contract documentationThe contact TokenTransferrer should have general contract documentation above the contract code, similar to all other contracts in the protocol, in such format:
/** * @title TokenTransferrer * @author * @notice */
ERC712
transfers should use safeTransferFrom
instead of transferFrom
Currently, the ERC721Interface
contains only transferFrom
. Hence, for many ERC721
tokens which have safeTransferFrom
as well, the non safe function will get called. By openzeppeling ERC721 standard the safe transfer is safer:
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked.
I suggest the ERC721Interface
should use the safeTransferFrom
, and then, for example, in TokenTransferrer._performERC721Transfer
the safer transfer method will get executed
route
in else
statementIn ReferenceBasicOrderFulfiller._validateAndFulfillBasicOrder, there are many if-else
statements which check the route
. the last else
assumes the routh is the last one left. This is problematic as the route can be not an expected value and any value will enter the else
.
Instead, I recommend to use else if
for all values, and finish with an else ... revert InvalidRoute()
.
For example:
ItemType receivedItemType; if ( route == BasicOrderRouteType.ETH_TO_ERC721 || route == BasicOrderRouteType.ETH_TO_ERC1155 ) { receivedItemType = ItemType.NATIVE; } else if ( route == BasicOrderRouteType.ERC20_TO_ERC721 || route == BasicOrderRouteType.ERC20_TO_ERC1155 ) { receivedItemType = ItemType.ERC20; } else if (route == BasicOrderRouteType.ERC721_TO_ERC20) { receivedItemType = ItemType.ERC721; } else { receivedItemType = ItemType.ERC1155; }
should be
ItemType receivedItemType; if ( route == BasicOrderRouteType.ETH_TO_ERC721 || route == BasicOrderRouteType.ETH_TO_ERC1155 ) { receivedItemType = ItemType.NATIVE; } else if ( route == BasicOrderRouteType.ERC20_TO_ERC721 || route == BasicOrderRouteType.ERC20_TO_ERC1155 ) { receivedItemType = ItemType.ERC20; } else if (route == BasicOrderRouteType.ERC721_TO_ERC20) { receivedItemType = ItemType.ERC721; } else if (routh == BasicOrderRouteType.ERC1155_TO_ERC20) { receivedItemType = ItemType.ERC1155; } else { revert ... }
#0 - HardlyDifficult
2022-06-26T16:56:53Z
Missing documentation for bool roundUp in docstring TokenTransferrer contract is missing contract documentation
Yes, ideally the documentation coverage would be complete - but these are very much nice to have improvements.
ERC712 transfers should use safeTransferFrom instead of transferFrom
Using safeTransferFrom is a common best practice to recommend. In this project it was intentionally avoided -- see the sponsor comment here https://github.com/code-423n4/2022-05-opensea-seaport-findings/issues/173#issuecomment-1147729846 and https://github.com/code-423n4/2022-05-opensea-seaport-findings/issues/19#issuecomment-1136460377
Should not assume the last route in else statement
The sentiment here is valid, but the current code does cover all the scenarios. If they were to make the recommended change it would be more difficult to validate it with 100% code coverage unless a mock was used to push through inputs that otherwise would not occur.
🌟 Selected for report: Dravee
Also found by: 0x1f8b, 0x29A, 0xalpharush, Chom, Czar102, Hawkeye, IllIllI, MaratCerby, MiloTruck, NoamYakov, OriDabush, RoiEvenHaim, Spearbit, Tadashi, TerrierLover, TomJ, asutorufos, cccz, cmichel, csanuragjain, defsec, delfin454000, djxploit, ellahi, foobar, gzeon, hake, hickuphh3, ignacio, ilan, joestakey, kaden, mayo, ming, oyc_109, peritoflores, rfa, sach1r0, sashik_eth, shung, sirhashalot, twojoy, zer0dot, zkhorse
434.9484 USDC - $434.95
If a variable is not initialized it is automatically set to the default value (0 for uint, false for bool, address(0) for address...). Explicitly initializing it with its default value is an anti-pattern and wastes gas.
Example Instance:
uint256 extraCeiling = 0;
-> uint256 extraCeiling;
In AmountDeriver._locateCurrentAmount
This pattern is used everywhere in the protocol.
Calling storage/memory variable which does not change, every loop iteration, is wrong and wastes gas. In most places this is taken care of, however not everywhere.
For example, OrderCombiner.sol#L247:
// Retrieve array of offer items for the order in question. OfferItem[] memory offer = advancedOrder.parameters.offer; // Iterate over each offer item on the order. for (uint256 j = 0; j < offer.length; ++j) { // Retrieve the offer item. OfferItem memory offerItem = offer[j];
instead, cache the length:
// Retrieve array of offer items for the order in question. OfferItem[] memory offer = advancedOrder.parameters.offer; uint256 totalOffers = offer.length // Iterate over each offer item on the order. for (uint256 j = 0; j < totalOffers; ++j) { // Retrieve the offer item. OfferItem memory offerItem = offer[j];
Other Instances Include (but not limited to):