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: 108/179
Findings: 2
Award: $56.49
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 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
zero-address check is best practice that prevent a transfer to zero-address! Instance :
function setVoter(address _voter) external { require(msg.sender == voter); voter = _voter; }
the function lack of zero-address checking, once voter
changed to zero-address voter
cannot be retrieved back, and voter is a important role. It also recommended to use 2 step instead to mitigated that voter
changed to address we don't want to.
token = _token;
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; }
RewardDistribution::changeTrader() https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L285-L288
function changeTrader(address _trader) external onlyOwner { traderEnableDate = block.timestamp + 1 days; pendingTrader = _trader; }
GolomTrader.sol GolomTrader::constructor() https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L92
GolomToken.sol GolomToken::setMinter() https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/governance/GolomToken.sol#L58-L61
Mitigation: check for address(0)
require(_minter != address(0),"zero-address")
some state change doesn't emit event, emiting an event important for off chain monitoring.
Instance: GolomToken.sol
GolomTrader.sol
RewardDistributor.sol
VoteEscrowCore.sol
VoteEscrowDelegation.sol
GolomTrader.sol
can be inaccurate.this calculation occure often in GolomTrader.sol:
(o.totalAmt * 50) / 10000
this calculation can be inaccurate if o.totalAmt
is low enought, it's happens because uint have no decimals and will rounding down that number, that make the distributor
doesn't take a accurate reward . since it need totalAmt
to be low the impact not too big so i report it in QA Report.
Mitigation:
totalAmt
can be multiplied by much larger number and when it need to be use it can be devide by that number
example:
///original require( o.totalAmt >= o.exchange.paymentAmt + o.prePayment.paymentAmt + o.refererrAmt + (o.totalAmt * 50) / 10000, 'amt not matching' ); ///mitigated uint largeNum = 10000; //can be much larger and defined as constant require( o.totalAmt * largeNum >= o.exchange.paymentAmt * largeNum + o.prePayment.paymentAmt * largeNum+ o.refererrAmt * largeNum + (o.totalAmt * largeNum * 50) / 10000, 'amt not matching' );
🌟 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
constructor
can be marked as immutable
Instance : RewardDistributor.sol https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L68-L69
constant
Instance: RewardDistributor.sol RewardDistributor::startTime (can be declared outside constructor since it a constant value) https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L84
GolomTrader.sol GolomTrader::WETH https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L45
public
mark that never called in the contract can be marked as external
insteadInstance: RewardDistributor.sol :
GolomTrader.sol :
VoteEnscrowDelegation.sol
hardhat/console.sol
can be removed from import since it isn't needed except in testinghardhat/console.sol
can be very costly to deploy it better to remove it since it isn't needed in actual implementation.
Instance: RewardDistributor.sol https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L9
constant
that have initial value 0
can be left by default instead of passing it with 0
, and avoid using array.length
for loop.because the instance almost same i decide to report it in one tittle:
0
, it isn't needed to pass it with 0
value (which will cost gas).array.length
cost gas for every loop, try to avoid it, pass it to a local variable before loop for one time operation.example :
uint length = array.length; for (uint i, i < length, ++i) {}
Instance: VoteEscrowDelegation.sol https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowDelegation.sol#L50
50: uint256 public MIN_VOTING_POWER_REQUIRED = 0; 171: for (uint256 index = 0; index < delegated.length; index++) { 181: for (uint256 index = 0; index < delegatednft.length; index++) {
VoteEscrowCore.sol https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowCore.sol#L745
745: for (uint256 i = 0; i < 255; ++i) { 1044: for (uint256 i = 0; i < 128; ++i) {
RewardDistributor.sol https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L143
143: for (uint256 index = 0; index < epochs.length; index++) { 157: for (uint256 index = 0; index < epochs.length; index++) { 180: for (uint256 tindex = 0; tindex < tokenids.length; tindex++) { 183: for (uint256 index = 0; index < epochs.length; index++) { 226: for (uint256 index = 0; index < epoch; index++) { 258: for (uint256 index = 0; index < epoch; index++) { 273: for (uint256 index = 0; index < epoch; index++) {
GolomTrader.sol https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L415
415: for (uint256 i = 0; i < proof.length; i++) {
Instance: VoteEscrowDelegation.sol IVoteEscrow https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowDelegation.sol#L12-L18