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: 93/179
Findings: 4
Award: $61.01
🌟 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 #497 as Medium risk. The relevant finding follows:
#0 - dmvt
2022-10-21T14:43:14Z
Duplicate of #343
🌟 Selected for report: AuditsAreUS
Also found by: 0xSky, CertoraInc, GimelSec, GiveMeTestEther, Green, Lambda, Ruhum, RustyRabbit, Treasure-Seeker, Twpony, arcoun, bin2chen, cccz, codexploder, cryptonue, dipp, horsefacts, jayphbee, joestakey, minhquanym, obront, peritoflores, rbserver, reassor, rotcivegaf, scaraven, ych18
4.5163 USDC - $4.52
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L217
User may lose funds and the lost funds will be stucked in the GolomTrader
contract forever.
User may unexpectedly send ether greater than o.totalAmt * amount + p.paymentAmt
GolomTrader.sol#L217
require(msg.value >= o.totalAmt * amount + p.paymentAmt, 'mgmtm');
when calling fillAsk
, but the remaining msg.value - o.totalAmt * amount + p.paymentAmt
ether didn't give back to user. And the GolomTrader
contract didn't implement a method to recovery user's funds.
Give back use's remaining funds at end of fillAsk
execution
... distributor.addFee([o.signer, o.exchange.paymentAddress], ((o.totalAmt * 50) / 10000) * amount); ---> payable(msg.sender).transfer(msg.value - o.totalAmt * amount + p.paymentAmt); emit OrderFilled(o.signer, msg.sender, 0, hashStruct, o.totalAmt * amount);
OR
require(msg.value == o.totalAmt * amount + p.paymentAmt, 'mgmtm');
#0 - KenzoAgada
2022-08-04T02:52:28Z
Duplicate of #75
🌟 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
ecrecover
not check the recovered address is 0.https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L176-L177
address signaturesigner = ecrecover(hash, o.v, o.r, o.s); require(signaturesigner == o.signer, 'invalid signature');
The best practice is always check if the recovered address is 0 or not.
safeTransferFrom
instead of transferFrom
.https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L236
if (o.isERC721) { require(amount == 1, 'only 1 erc721 at 1 time'); ERC721(o.collection).transferFrom(o.signer, receiver, o.tokenId); } else { ERC1155(o.collection).safeTransferFrom(o.signer, receiver, o.tokenId, amount, ''); }
In the fillAsk
function, the receiver
parameter is specified by caller. There is a chance that the caller may accidently pass a contract address without implementing a method to transfer the NFT which will lead to the NFT be stucked into the contract forever.
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L47-L70
struct Order { ... } struct Payment { uint256 paymentAmt; address paymentAddress; }
Order
type hash is calculated with:
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L132
keccak256( 'order(address collection,uint256 tokenId,address signer,uint256 orderType,uint256 totalAmt,payment exchange,payment prePayment,bool isERC721,uint256 tokenAmt,uint256 refererrAmt,bytes32 root,address reservedAddress,uint256 nonce,uint256 deadline)payment(uint256 paymentAmt,address paymentAddress)' ),
The 'ordershould be capitalized in accordance with the
Orderstrcut declaration above. The
payment` type hash calculation has the same issue.
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L116
keccak256('payment(uint256 paymentAmt,address paymentAddress)'),
The payment
should be capitalized either.
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#definition-of-encodetype
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L101-L110
EIP712_DOMAIN_TYPEHASH = keccak256( abi.encode( keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), keccak256(bytes('GOLOM.IO')), keccak256(bytes('1')), chainId, address(this) ) ); }
EIP712_DOMAIN_TYPEHASH
should be named EIP712_DOMAIN_SEPERATOR
as per the EIP712 standard.
EIP712_DOMAIN_TYPEHASH is keccak256 hash of 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'
🌟 Selected for report: JohnSmith
Also found by: 0x1f8b, 0xA5DF, 0xDjango, 0xKitsune, 0xLovesleep, 0xNazgul, 0xSmartContract, 0xmatt, 0xsam, Aymen0909, Bnke0x0, CRYP70, Chandr, Chinmay, CodingNameKiki, Deivitto, Dravee, ElKu, Fitraldys, Funen, GalloDaSballo, Green, IllIllI, JC, Jmaxmanblue, Junnon, Kaiziron, Kenshin, Krow10, Maxime, Migue, MiloTruck, Noah3o6, NoamYakov, Randyyy, RedOneN, ReyAdmirado, Rohan16, Rolezn, Ruhum, Sm4rty, StyxRave, TomJ, Tomio, _Adam, __141345__, ajtra, ak1, apostle0x01, asutorufos, async, benbaessler, brgltd, c3phas, cRat1st0s, carlitox477, delfin454000, djxploit, durianSausage, ellahi, erictee, fatherOfBlocks, gerdusx, gogo, hyh, jayfromthe13th, jayphbee, joestakey, kaden, kenzo, kyteg, ladboy233, lucacez, m_Rassska, mics, minhquanym, oyc_109, pfapostol, rbserver, reassor, rfa, robee, rokinot, sach1r0, saian, samruna, sashik_eth, simon135, supernova, tofunmi, zuhaibmohd
21.3211 USDC - $21.32
nonReentrant
modifier.https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L312 https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L323
function cancelOrder(Order calldata o) public nonReentrant function incrementNonce() external nonReentrant
There's no need to add the nonReentrant
modifier, because there's no untrusted external call in the two functions. This will save one sload
and sstore
.
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L189-L193
if (filled[hashStruct] >= o.tokenAmt) { // handles erc1155 return (2, hashStruct, 0); } return (3, hashStruct, o.tokenAmt - filled[hashStruct]);
the filled[hashStruct]
is read from storage twice. cache the value will save one sload gas.
uint256 tokenToEmit = (dailyEmission * (rewardToken.totalSupply() - rewardToken.balanceOf(address(ve)))) / rewardToken.totalSupply(); uint256 stakerReward = (tokenToEmit * rewardToken.balanceOf(address(ve))) / rewardToken.totalSupply();
rewardToken.totalSupply() is called 3 times. Cache the value will save two staticall gas usage.
RewardDistributor.sol::addFee
can be declared as payable to receive fee from GolomTrader
contract.fillAsk
is a hot path. It will collect fees and send to RewardDistributor
contract by payEther
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L242
// pay fees of 50 basis points to the distributor payEther(((o.totalAmt * 50) / 10000) * amount, address(distributor));
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L269
distributor.addFee([o.signer, o.exchange.paymentAddress], ((o.totalAmt * 50) / 10000) * amount);
We can eliminate the payEther
call in L242 instead sending the fee in addFee
by declare it as payable and remove the fee
parameter.
distributor.addFee{value: ((o.totalAmt * 50) / 10000) * amount}([o.signer, o.exchange.paymentAddress]);
By doing this, the fallback
and receive
function can also be deleted in RewardDistributor
contract, because they are no longer used to receive ether from GolomTrader
contract.
The issue also applies to _settleBalances
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L375-L403
rewardToken
and weth
can be decalared as immutable.ERC20 public rewardToken; ERC20 public weth;
rewardToken
and weth
are only initialized in constructor
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/rewards/RewardDistributor.sol#L74-L84
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;
Declaring them as immutable
will save gas.
This codebase is based on solidity 0.8.11, using custome error can both save deployment gas and runtime gas.