Platform: Code4rena
Start Date: 26/07/2022
Pot Size: $75,000 USDC
Total HM: 29
Participants: 179
Period: 6 days
Judge: LSDan
Total Solo HM: 6
Id: 148
League: ETH
Rank: 62/179
Findings: 3
Award: $186.43
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: sseefried
Also found by: 0x4non, IllIllI, Jmaxmanblue, JohnSmith, Lambda, arcoun, berndartmueller, cccz, csanuragjain, minhquanym, rbserver, rotcivegaf
The implementation of onERC721Received fails to check the return value being equal to "IERC721Receiver.onERC721Received.selector". If this response is not obtained then transaction should revert but the current implementation does not throw error in that case. This could lead to loss of token
function safeTransferFrom( address _from, address _to, uint256 _tokenId, bytes memory _data ) public { _transferFrom(_from, _to, _tokenId, msg.sender); if (_isContract(_to)) { // Throws if transfer destination is a contract which does not implement 'onERC721Received' try IERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data) returns (bytes4) {} catch ( bytes memory reason ) { if (reason.length == 0) { revert('ERC721: transfer to non ERC721Receiver implementer'); } else { assembly { revert(add(32, reason), mload(reason)) } } } } }
try IERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data) returns (bytes4) {}
Add below line to implementation of onERC721Received
try IERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data) returns (bytes4 retVal) { require(retval == IERC721Receiver.onERC721Received.selector, 'ERC721: non ERC721Receiver'); } catch ....
#0 - KenzoAgada
2022-08-04T02:04:34Z
Duplicate of #577
🌟 Selected for report: horsefacts
Also found by: GalloDaSballo, IllIllI, berndartmueller, csanuragjain, hansfriese, kenzo, minhquanym, rotcivegaf
The _burn function is trying to remove tokens from msg.sender instead of owner. This means the call will fail everytime if called from an approved user. All function which calls _burn which is withdraw and merge will fail
merge and withdraw functions both make use of _burn function
Assume _burn is called by one of approved user
function _burn(uint256 _tokenId) internal { require(_isApprovedOrOwner(msg.sender, _tokenId), 'caller is not owner nor approved'); address owner = ownerOf(_tokenId); // Clear approval approve(address(0), _tokenId); // Remove token _removeTokenFrom(msg.sender, _tokenId); emit Transfer(owner, address(0), _tokenId); }
require(_isApprovedOrOwner(msg.sender, _tokenId), 'caller is not owner nor approved');
_removeTokenFrom(msg.sender, _tokenId);
Notice that this function is asking to remove _tokenId from msg.sender. This is incorrect as msg.sender might not be the owner of this _tokenId and just an approver.
This means the call will failas below statement fails
function _removeTokenFrom(address _from, uint256 _tokenId) internal { // Throws if `_from` is not the current owner assert(idToOwner[_tokenId] == _from); .... }
Kindly change L1234 so that removal is done from owner and not msg.sender
function _burn(uint256 _tokenId) internal { require(_isApprovedOrOwner(msg.sender, _tokenId), 'caller is not owner nor approved'); address owner = ownerOf(_tokenId); // Clear approval approve(address(0), _tokenId); // Remove token _removeTokenFrom(owner, _tokenId); emit Transfer(owner, address(0), _tokenId); }
#0 - KenzoAgada
2022-08-02T06:03:46Z
Duplicate of #858
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0x4non, 0x52, 0xA5DF, 0xDjango, 0xLovesleep, 0xNazgul, 0xNineDec, 0xSmartContract, 0xackermann, 0xc0ffEE, 0xf15ers, 0xmatt, 0xsanson, 0xsolstars, 8olidity, AuditsAreUS, Bahurum, Bnke0x0, CRYP70, CertoraInc, Ch_301, Chom, CryptoMartian, Deivitto, DevABDee, Dravee, ElKu, Franfran, Funen, GalloDaSballo, GimelSec, GiveMeTestEther, Green, JC, Jmaxmanblue, JohnSmith, Jujic, Junnon, Kenshin, Krow10, Kumpa, Lambda, MEP, Maxime, MiloTruck, Mohandes, NoamYakov, Picodes, RedOneN, Rohan16, Rolezn, Ruhum, RustyRabbit, Sm4rty, Soosh, StErMi, StyxRave, Tadashi, TomJ, Treasure-Seeker, TrungOre, Waze, _Adam, __141345__, ajtra, ak1, apostle0x01, arcoun, asutorufos, async, benbaessler, berndartmueller, bin2chen, brgltd, c3phas, cRat1st0s, carlitox477, chatch, codetilda, codexploder, cryptonue, cryptphi, csanuragjain, cthulhu_cult, delfin454000, dipp, dirk_y, djxploit, ellahi, exd0tpy, fatherOfBlocks, giovannidisiena, hansfriese, horsefacts, hyh, idkwhatimdoing, indijanc, jayfromthe13th, jayphbee, joestakey, kenzo, kyteg, lucacez, luckypanda, mics, minhquanym, obront, oyc_109, pedr02b2, rajatbeladiya, rbserver, reassor, robee, rokinot, rotcivegaf, sach1r0, saian, saneryee, sashik_eth, scaraven, shenwilly, simon135, sseefried, supernova, teddav, ych18, zuhaibmohd, zzzitron
35.1687 USDC - $35.17
Contract: GolomTrader.sol
Issue: The validateOrder function will not return 0 value and will instead fail if signature is not valid. This is happening due to below condition:
require(signaturesigner == o.signer, 'invalid signature');
Recommendation: Kindly remove the below line:
require(signaturesigner == o.signer, 'invalid signature');
Issue: The order is cancelled by incrementing the filled cap of an order. This means this order will look like it was filled fully rather than cancelled
Recommendation: Instead of "filled[hashStruct] = o.tokenAmt + 1;" use ++nonces[o.signer]
Issue: Assert should only be used to check internal errors and should never fail unless there is a bug in the contract. The current contract implementation uses assert at multiple places VoteEscrowCore.sol#L493, VoteEscrowCore.sol#L506, VoteEscrowCore.sol#L519 etc
Recommendation: Use require instead of assert