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: 124/179
Findings: 3
Award: $35.32
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: cloudjunky
Also found by: 0x1f8b, 0x4non, 0x52, 0xDjango, 0xHarry, 0xNazgul, 0xNineDec, 0xf15ers, 0xsanson, 0xsolstars, 8olidity, Bnke0x0, CertoraInc, Chom, Deivitto, Dravee, GalloDaSballo, GimelSec, IllIllI, Jmaxmanblue, JohnSmith, Jujic, Kenshin, Krow10, Lambda, MEP, Noah3o6, RedOneN, Ruhum, StErMi, StyxRave, TomJ, Treasure-Seeker, TrungOre, _Adam, __141345__, arcoun, asutorufos, bardamu, bearonbike, bin2chen, brgltd, bulej93, c3phas, cRat1st0s, carlitox477, cccz, codexploder, cryptonue, cryptphi, cthulhu_cult, dharma09, dipp, djxploit, durianSausage, ellahi, giovannidisiena, hansfriese, horsefacts, hyh, immeas, indijanc, jayjonah8, jayphbee, joestakey, kenzo, kyteg, ladboy233, minhquanym, navinavu, obront, oyc_109, peritoflores, rbserver, reassor, rokinot, rotcivegaf, saian, scaraven, shenwilly, simon135, sseefried, teddav, zzzitron
0.0037 USDC - $0.00
Judge has assessed an item in Issue #868 as Medium risk. The relevant finding follows:
Using .call() instead of .transfer() Currently it is using .transfer to transfer ETH
payable(payAddress).transfer(payAmt);
Using deprecated transfer() on address payable may revert in these cases:
Consider using these
(bool success, ) = payAddress.call{value: payAmt}(""); require(success, "ETH transfer failed");
#0 - dmvt
2022-10-21T13:58:24Z
Duplicate of #343
🌟 Selected for report: TomJ
Also found by: 0x4non, 0x52, 0xDjango, 0xNazgul, 0xf15ers, 0xsanson, 8olidity, Bnke0x0, CertoraInc, Ch_301, Chom, Dravee, GalloDaSballo, GimelSec, JC, Jujic, Kenshin, Kumpa, Lambda, M0ndoHEHE, PaludoX0, RedOneN, Ruhum, Sm4rty, Treasure-Seeker, TrungOre, Twpony, Waze, _Adam, __141345__, apostle0x01, arcoun, benbaessler, bin2chen, brgltd, cccz, cloudjunky, cryptonue, djxploit, ellahi, erictee, hansfriese, i0001, minhquanym, oyc_109, peritoflores, rbserver, reassor, rokinot, rotcivegaf, saian, shenwilly, sseefried
0.1513 USDC - $0.15
https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L236 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L301 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L361
TokenTransferrer is using unsafe transferFrom for ERC721 instead of safeTransferFrom. Necessary checks and onERC721Received hook will be skipped!
Necessary checks include
_data
bytes.If these checks fail, transaction will be reverted. This is done to prevent the loss of NFT because of transferring into a contract that cannot receive ERC721.
But TokenTransferrer is using unsafe transferFrom which doesn't perform these check, so NFT may be transferred into a contract that cannot receive ERC721.
Moreover, onERC721Received hook won't be called causing some external contract that uses Golom NFT marketplace failed to handle these NFT properly. NFT may be locked in the intermediate contract forever as onERC721Received hook is not executed.
nftcontract.transferFrom(msg.sender, o.signer, tokenId);
This line is repeated 3 times. It is transferring ERC721 using unsafe transferFrom.
Manual review
Use safeTransferFrom instead of transferFrom.
#0 - KenzoAgada
2022-08-03T15:04:46Z
Duplicate of #342
🌟 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
Currently it is using .transfer to transfer ETH
payable(payAddress).transfer(payAmt);
Using deprecated transfer()
on address payable may revert in these cases:
Additionally, using higher than 2300 gas might be mandatory for some multisig wallets.
Consider using these
(bool success, ) = payAddress.call{value: payAmt}(""); require(success, "ETH transfer failed");
address signaturesigner = ecrecover(hash, o.v, o.r, o.s); require(signaturesigner == o.signer, 'invalid signature');
ecrecover return address(0) if signnature is invalid.
But it is not checked which means if o.signer == address(0), that order can be executed by anyone.
In fillAsk there are revert descriptions.
require(o.orderType == 0, 'invalid orderType'); (uint256 status, bytes32 hashStruct, uint256 amountRemaining) = validateOrder(o); require(status == 3, 'order not valid'); require(amountRemaining >= amount, 'order already filled');
But in fillBid there aren't
require(o.orderType == 1); (uint256 status, bytes32 hashStruct, uint256 amountRemaining) = validateOrder(o); require(status == 3); require(amountRemaining >= amount);
WETH.transferFrom(o.signer, address(this), o.totalAmt * amount);
In specification, it returns bool to indicate whether transferFrom is success or not.
function transferFrom(address src, address dst, uint wad) public returns (bool)
But you don't use it for check
WETH.transferFrom(o.signer, address(this), o.totalAmt * amount);
You should check the return value to prevent failure cases
if (!WETH.transferFrom(o.signer, address(this), o.totalAmt * amount)) revert TransferFailed();
Currently daily emission is set to be constant. But the nature of business always update this variable, so it should be updatable by the governance.
uint256 constant dailyEmission = 600000 * 10**18;
A setter should be created ti set this variable at runtime.
Currently it is hardcoded in the constructor which cause many problem for the unit test
constructor( address _weth, address _trader, address _token, address _governance ) { weth = ERC20(_weth); trader = _trader; rewardToken = ERC20(_token); _transferOwnership(_governance); // set the new owner startTime = 1659211200; }
1659211200 is also passed now, which means when production this value also has to change, so it is better provide it with a constructor argument
constructor( address _weth, address _trader, address _token, address _governance, uint256 _startTime ) { weth = ERC20(_weth); trader = _trader; rewardToken = ERC20(_token); _transferOwnership(_governance); // set the new owner startTime = _startTime; }