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: 26/179
Findings: 4
Award: $469.74
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: CertoraInc
Also found by: 0xA5DF, 0xsanson, Bahurum, GalloDaSballo, MEP, TrungOre, carlitox477, cryptphi, kenzo
280.8379 USDC - $280.84
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowDelegation.sol#L210 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowDelegation.sol#L242
Given it is called by _transferFrom function and removeDelegation is external, this function would never be call and _transferFrom will always revert, contract deployment woul be a waste of time
Just replace line 210 for ````function removeDelegation(uint256 tokenId) public``
#0 - zeroexdead
2022-08-15T16:44:33Z
Duplicate of #377
🌟 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 #553 as Medium risk. The relevant finding follows:
01 - payEther use transfer instead of call Replace line 154 for
payable(payAddress).call{value: payAmt}("") Reason
#0 - dmvt
2022-10-21T16:26:01Z
Duplicate of #343
🌟 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
167.5763 USDC - $167.58
Interface ERC1155 confuse code reader with openzeppelin contracts, change it to IERC1155_Golem
Using safeTransferFrom is a better practise than using transferFrom. Reasons
Interface ERC20 confuse code reader with openzeppelin contracts, change it to IERCWETH_Golem
In interface ERC20, change it variable names to openzeppelin standards to facilitate understandment for devs.
In GolemTrader.spect.ts replace line 95 for
golomToken = (await (await GolomTokenArtifacts).deploy(await governance.getAddress())) as GolomTokenTypes;
To set the correct governance, otherwise the test will not work correctly
In GolemTrader.spect.ts, in test for function #fillAsk add a before each statement to set the rewardDistributor as minter, otherwise some will fail
Take into account 05 - Testing GolemTrader mistake: wrong golomToken initialization and add next lines at test start for function #fillAsk:
beforeEach(async()=>{ await golomToken.connect(governance).mintGenesisReward(rewardDistributor.address) await golomToken.connect(governance).setMinter(rewardDistributor.address) await golomToken.connect(governance).executeSetMinter() })
It is usually recommended not to hardcode variables. Send the address a parameter and initialize WETH in the constructor
constructor(address _governance,address _weth) { WETH = ERC20(_weth); //The other code keeps the same /* ... /* }
Change it name to _hashPayment to respect private/internal function naming convention
Change it name to _payEther to respect private/internal function naming convention
The protocol can benefit from setting the distributor fee to zero in for it promotion, or increase it if the project is super succesful. However the contract fix this fee so this can not happen.
Idea:
For better code understandment, change next variable names
Change it visibility to external
Should change it name to SECS_IN_DAY to respect constant variable naming convention
Change it name to IERC20_Golem just for not confusing with openzeppelin contracts
Change variable names to openzeppelin standards to better understandment for new devs
This will be better during testing. Consider making startTime storage value a constant or send it by parameter (this second options seems better)
This function isn't called by any other function in the contract.
It initialization is hardcoded, it is a better practise to send it value by parameter. New suggested constructor:
constructor( address _weth, address _trader, address _token, address _governance, uint256 _startTime ) { require(_startTime>=block.timestamp) startTime = _startTime; weth = ERC20(_weth); trader = _trader; rewardToken = ERC20(_token); _transferOwnership(_governance); // set the new owner }
Change it to minVotingPowerRequired notation to lower cammel to follow variable naming convention
It will be set by default to zero. Is it meant to be like this?
Although this does not seem to affect the code, it is a bad practise. Should change variable names for better code style:
This code has a hardcoded commented api key in hardhat.config.ts
I suggest to erase it from and start putting your key in a .env file
Giving that its visibility is public view function, this function can be queried by anyone. However, when it is given a wrongly signed order, the function is reverted instead of return a 0 status
In GolemTrader.specs.ts add:
describe('#validateOrder', ()=>{ it('Should return status 0 for an order with a wrong signature',async ()=>{ //Current status: the transaction is reverted. Solution: try catch code //Correcting this function implies correcting cancelOrder by addin a require(status!=0) after calling validateOrder let exchangeAmount = ethers.utils.parseEther('1'); // cut for the exchanges let prePaymentAmt = ethers.utils.parseEther('0.25'); // royalty cut let totalAmt = ethers.utils.parseEther('1'); let tokenId = await testErc721.current(); let wrongSigner = governance as any const order = { collection: testErc721.address, tokenId: tokenId, signer: await maker.getAddress(), orderType: 0, totalAmt: totalAmt, exchange: { paymentAmt: exchangeAmount, paymentAddress: await exchange.getAddress() }, prePayment: { paymentAmt: prePaymentAmt, paymentAddress: await prepay.getAddress() }, isERC721: true, tokenAmt: 1, refererrAmt: 0, root: '0x0000000000000000000000000000000000000000000000000000000000000000', reservedAddress: constants.AddressZero, nonce: 0, deadline: Date.now() + 100000, r: '', s: '', v: 0, }; let signature = (await wrongSigner._signTypedData(domain, types, order)).substring(2); //let signature = (await maker._signTypedData(domain, types, order)).substring(2); order.r = '0x' + signature.substring(0, 64); order.s = '0x' + signature.substring(64, 128); order.v = parseInt(signature.substring(128, 130), 16); await expect(golomTrader.validateOrder(order), 'Function reverted').to.not.be.reverted const result=await golomTrader.validateOrder(order) expect((result[0] as BigNumber).eq(0),"Return value different from zero").to.be.true }) })
require(signaturesigner == o.signer, 'invalid signature');
from validateOrder function(, bytes32 hashStruct, ) = validateOrder(o);
and replace it for(uint256 status, bytes32 hashStruct, ) = validateOrder(o); require(status != 0, 'invalid signature');
Is is important to point out that this issue can scale to medium or even high if there are off-chain dependant function or external contract which functionality relays on this function
DelegateChanged or/and DelegateVotesChanged should be emitted given the semantics. The lack of emission may affect off chain applications. For instance, a dependant subgraph
🌟 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
Replace line 154 for
payable(payAddress).call{value: payAmt}("")
After transfering the token and before doing the payment add
uint256 distributorFee=(o.totalAmt * 50) / 10000
. Then replace every (o.totalAmt * 50) / 10000
occurancy by this new variable to save gas. Previous gas spent
390095/393890/393346, now 38977/393572/393025
It default value will be zero
Create the constant MAX_SUPPLY = 1000000000 * 10**18 to save gas at deployment and in function addFee
At function start, add uint256 _rewardToken= rewardToken.totalSupply()
to do just one call to the external contract, and change every other occurancy of rewardToken.totalSupply() in this function for this new variable (this saves gas)
At the begining of second if statmente add a declaration uint256 _rewarTokenBalanceOfVe = rewardToken.balanceOf(address(ve))
and replace every other occurancy of rewardToken.balanceOf(address(ve))
for this new variable to avoid accessing to external contract (sooner or later to storage) 2 times and save gas
This avoid an operation making to math operations after line uint256 previousEpochFee = epochTotalFee[epoch];
replace
rewardTrader[epoch] = ((tokenToEmit - stakerReward) * 67) / 100; rewardExchange[epoch] = ((tokenToEmit - stakerReward) * 33) / 100;
For:
totalRewards = tokenToEmit - stakerReward; rewardTrader[epoch] = (totalRewards * 67) / 100; rewardExchange[epoch] = (totalRewards * 33) / 100;
It default value is zero, there is no need to spend gas in initializing it
It default value is zero, there is no need to spend gas in initializing it
At second if statment start put epoch storage variable in a memory variable called uint256 _epoch = epoch
Consider that doing this also implies change this line for:
_epoch = _epoch + 1 epoch = _epoch
Just add an _epoch initialization uint256 _epoch = epoch
and replace epoch occurancie in the loop, reducing multiple storage access saving gas.
Their defaults values are already zero.
Their defaults values are already zero.
This could be a serious issue if off chain aps depends on it. However, if it isn't needed it can be eliminated and save gas at deployment