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: 9/179
Findings: 12
Award: $2,198.77
π Selected for report: 2
π Solo Findings: 0
π 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
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/rewards/RewardDistributor.sol#L300
RewardDistributor.addVoteEscrow
has a serious mistake. The contract owner cannot add any vote escrow contract.
Initially, address(ve)
and address(pendingVoteEscrow)
are address(0). So the if condition is always true. Thus, the owner cannot add any vote escrow contract.
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/rewards/RewardDistributor.sol#L300
function addVoteEscrow(address _voteEscrow) external onlyOwner { if (address(ve) == address(0)) { ve = VE(pendingVoteEscrow); } else { voteEscrowEnableDate = block.timestamp + 1 days; pendingVoteEscrow = _voteEscrow; } }
None
Fix addVoteEscrow
function addVoteEscrow(address _voteEscrow) external onlyOwner { if (address(ve) == address(0)) { ve = VE(_voteEscrow); } else { voteEscrowEnableDate = block.timestamp + 1 days; pendingVoteEscrow = _voteEscrow; } }
#0 - KenzoAgada
2022-08-02T09:24:47Z
Duplicate of #611
π Selected for report: GimelSec
Also found by: 0x52, 0xA5DF, 0xSky, 0xsanson, Bahurum, CertoraInc, GalloDaSballo, JohnSmith, Lambda, MEP, Twpony, arcoun, berndartmueller, cryptphi, hansfriese, kenzo, kyteg, panprog, rajatbeladiya, scaraven, simon135, zzzitron
34.8003 USDC - $34.80
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L101 https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L82-L86
When a user call VoteEscrowDelegation.delegate
to make a delegation, it calls VoteEscrowDelegation._writeCheckpoint
to update the checkpoint of toTokenId
. However, if nCheckpoints
is 0, _writeCheckpoint
always reverts. Whatβs worse, nCheckpoints
would be zero before any delegation has been made. In conclusion, users cannot make any delegation.
When a user call VoteEscrowDelegation.delegate
to make a delegation, it calls VoteEscrowDelegation._writeCheckpoint
to update the checkpoint of toTokenId
.
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L82-L86
function delegate(uint256 tokenId, uint256 toTokenId) external { require(ownerOf(tokenId) == msg.sender, 'VEDelegation: Not allowed'); require(this.balanceOfNFT(tokenId) >= MIN_VOTING_POWER_REQUIRED, 'VEDelegation: Need more voting power'); delegates[tokenId] = toTokenId; uint256 nCheckpoints = numCheckpoints[toTokenId]; if (nCheckpoints > 0) { Checkpoint storage checkpoint = checkpoints[toTokenId][nCheckpoints - 1]; checkpoint.delegatedTokenIds.push(tokenId); _writeCheckpoint(toTokenId, nCheckpoints, checkpoint.delegatedTokenIds); } else { uint256[] memory array = new uint256[](1); array[0] = tokenId; _writeCheckpoint(toTokenId, nCheckpoints, array); } emit DelegateChanged(tokenId, toTokenId, msg.sender); }
if nCheckpoints
is 0, _writeCheckpoint
always reverts.
Because checkpoints[toTokenId][nCheckpoints - 1]
will trigger underflow in Solidity 0.8.11
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L101
function _writeCheckpoint( uint256 toTokenId, uint256 nCheckpoints, uint256[] memory _delegatedTokenIds ) internal { require(_delegatedTokenIds.length < 500, 'VVDelegation: Cannot stake more'); Checkpoint memory oldCheckpoint = checkpoints[toTokenId][nCheckpoints - 1]; β¦ }
None
Fix _writeCheckpoint
function _writeCheckpoint( uint256 toTokenId, uint256 nCheckpoints, uint256[] memory _delegatedTokenIds ) internal { require(_delegatedTokenIds.length < 500, 'VVDelegation: Cannot stake more'); if (nCheckpoints > 0 && oldCheckpoint.fromBlock == block.number) { Checkpoint memory oldCheckpoint = checkpoints[toTokenId][nCheckpoints - 1]; oldCheckpoint.delegatedTokenIds = _delegatedTokenIds; } else { checkpoints[toTokenId][nCheckpoints] = Checkpoint(block.number, _delegatedTokenIds); numCheckpoints[toTokenId] = nCheckpoints + 1; } }
#0 - zeroexdead
2022-09-03T19:22:14Z
26.7695 USDC - $26.77
While delegating voting power to a new delegatee, if any current delegatee exists, it should be cleared to ensure no NFT can be used to vote twice. The current implementation does not do this and allows attackers to delegate multiple times and multiply their voting power.
Current implementation of VoteEscrowDelegation.delegate
does not check if any delegatee exists and clear it before assigning a new delegatee.
function delegate(uint256 tokenId, uint256 toTokenId) external { require(ownerOf(tokenId) == msg.sender, 'VEDelegation: Not allowed'); require(this.balanceOfNFT(tokenId) >= MIN_VOTING_POWER_REQUIRED, 'VEDelegation: Need more voting power'); delegates[tokenId] = toTokenId; uint256 nCheckpoints = numCheckpoints[toTokenId]; if (nCheckpoints > 0) { Checkpoint storage checkpoint = checkpoints[toTokenId][nCheckpoints - 1]; checkpoint.delegatedTokenIds.push(tokenId); _writeCheckpoint(toTokenId, nCheckpoints, checkpoint.delegatedTokenIds); } else { uint256[] memory array = new uint256[](1); array[0] = tokenId; _writeCheckpoint(toTokenId, nCheckpoints, array); } emit DelegateChanged(tokenId, toTokenId, msg.sender); }
Manual audit
Check and clear any existing delegations
function delegate(uint256 tokenId, uint256 toTokenId) external { require(ownerOf(tokenId) == msg.sender, 'VEDelegation: Not allowed'); require(this.balanceOfNFT(tokenId) >= MIN_VOTING_POWER_REQUIRED, 'VEDelegation: Need more voting power'); if (delegates[tokenId] != 0) { removeDelegation(tokenId); } delegates[tokenId] = toTokenId; uint256 nCheckpoints = numCheckpoints[toTokenId]; β¦ }
#0 - KenzoAgada
2022-08-02T12:00:05Z
Duplicate of #169
131.6127 USDC - $131.61
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/rewards/RewardDistributor.sol#L98
RewardDistributor.sol addFee
stops all operations after minting limit of reward token in met, future ETH transferred to RewardDistributor by GolomTrader will be stuck.
When addFee
rewardToken.totalSupply() > 1000000000 * 10**18
, it will return directly:
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/rewards/RewardDistributor.sol#L100-L103
if (rewardToken.totalSupply() > 1000000000 * 10**18) { // if supply is greater then a billion dont mint anything, dont add trades return; }
Then weth.deposit
will not be called:
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/rewards/RewardDistributor.sol#L124-L130
if (previousEpochFee > 0) { if (epoch == 1){ epochTotalFee[0] = address(this).balance; // staking and trading rewards start at epoch 1, for epoch 0 all contract ETH balance is converted to staker rewards rewards. weth.deposit{value: address(this).balance}(); }else{ weth.deposit{value: previousEpochFee}(); }
It weth.deposit
doesn't be called, any ETH in RewardDistributor (which is transferred by addFee
, or accidentally send ETH in receive()
) will be stuck.
None
It should call weth.deposit
first before returning.
#0 - 0xsaruman
2022-08-19T18:15:36Z
93.2805 USDC - $93.28
VoteEscrowDelegation.removeDelegation
attempts to update checkpoints
for the wrong NFT, and fails to remove delegation correctly. This will result in incorrect/unexpected delegation relationships between tokens after transfer.
Delegation in VoteEscrowDelegation
is implemented by maintaining two structures. The first is delegates
, which keeps track of delegator NFT->delegatee NFT
mappings. The second is checkpoints.delegatedTokenIds
, which is responsible for recording delegatee NFT->delegator NFT
list.
/// @notice Delegate of the specific token mapping(uint256 => uint256) public delegates; β¦ /// @notice A checkpoint for marking number of votes from a given block struct Checkpoint { uint256 fromBlock; uint256[] delegatedTokenIds; } /// @notice A record of votes checkpoints for each tokenId, by index mapping(uint256 => mapping(uint256 => Checkpoint)) public checkpoints;
Correct way to remove delegation of NFT X is to clear delegates[X]
and remove X from checkpoint[delegates[X]].delegatedTokenIDs
. However, the current way removeDelegation
does this is by removing X
from checkpoint[X].delegatedTokenIDs
, which does not make sense.
function removeDelegation(uint256 tokenId) external { require(ownerOf(tokenId) == msg.sender, 'VEDelegation: Not allowed'); uint256 nCheckpoints = numCheckpoints[tokenId]; Checkpoint storage checkpoint = checkpoints[tokenId][nCheckpoints - 1]; removeElement(checkpoint.delegatedTokenIds, tokenId); _writeCheckpoint(tokenId, nCheckpoints, checkpoint.delegatedTokenIds); }
This incorrect implementation will result in delegations to never be removed from delegatee.
Manual audit
Do bookkeeping correctly as shown in snippet below
function removeDelegation(uint256 tokenId) external { require(ownerOf(tokenId) == msg.sender, 'VEDelegation: Not allowed'); uint256 delegatee = delegates[tokenId]; if (delegatee != 0) { delegates[tokenId] = 0; uint256 nCheckpoints = numCheckpoints[delegatee]; Checkpoint storage checkpoint = checkpoints[delegatee][nCheckpoints - 1]; removeElement(checkpoint.delegatedTokenIds, tokenId); _writeCheckpoint(delegatee, nCheckpoints, checkpoint.delegatedTokenIds); } }
#0 - KenzoAgada
2022-08-02T08:23:25Z
Duplicate of #751
π 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
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L151-L156
Transfer ETH by using transfer()
may cause this transaction to fail.
In EIP-1884:
In many cases, a recipient of ether
from a CALL
will want to issue a LOG
. The LOG
operation costs 375
plus 375
per topic. If the LOG
also wants to do an SLOAD
, this change may make some such transfers fail.
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L151-L156
function payEther(uint256 payAmt, address payAddress) internal { if (payAmt > 0) { // if royalty has to be paid payable(payAddress).transfer(payAmt); // royalty transfer to royaltyaddress } }
None
Use call{value: amount}()
instead of transfer
:
(bool success, ) = payable(msg.sender).call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted");
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol#L60
Note that call
may suffer from reentrancy attack, it should follow Checks-Effects-Interactions.
#0 - KenzoAgada
2022-08-03T14:23:28Z
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/main/contracts/core/GolomTrader.sol#L301 https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L361
nftcontract.transferfrom
doesn't check whether users will handle ERC721 received. If a user is a contract but doesnβt handle ERC721 received, the ERC721 token will be frozen when receiving ERC721 tokens. Thus, using nftcontract.safetransferfrom
instead of nftcontract.transferfrom
for ERC721 can avoid such problems.
It doesnβt check whether the receiver has implemented the onERC721Received
function. If a user doesn't handle ERC721 received, the ERC721 token will be frozen.
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L301
function fillBid( Order calldata o, uint256 amount, address referrer, Payment calldata p ) public nonReentrant { β¦ if (o.isERC721) { require(amount == 1, 'only 1 erc721 at 1 time'); ERC721 nftcontract = ERC721(o.collection); nftcontract.transferFrom(msg.sender, o.signer, o.tokenId); } else { ERC1155 nftcontract = ERC1155(o.collection); nftcontract.safeTransferFrom(msg.sender, o.signer, o.tokenId, amount, ''); } emit OrderFilled(msg.sender, o.signer, 1, hashStruct, o.totalAmt * amount); _settleBalances(o, amount, referrer, p); }
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L361
function fillCriteriaBid( Order calldata o, uint256 amount, uint256 tokenId, bytes32[] calldata proof, address referrer, Payment calldata p ) public nonReentrant { β¦ if (o.isERC721) { require(amount == 1, 'only 1 erc721 at 1 time'); ERC721 nftcontract = ERC721(o.collection); nftcontract.transferFrom(msg.sender, o.signer, tokenId); } else { ERC1155 nftcontract = ERC1155(o.collection); nftcontract.safeTransferFrom(msg.sender, o.signer, tokenId, amount, ''); } emit OrderFilled(msg.sender, o.signer, 2, hashStruct, o.totalAmt * amount); _settleBalances(o, amount, referrer, p); }
None
Use safeTransferFrom
rather than transferFrom
when transferring ERC721 tokens to users.
#0 - KenzoAgada
2022-08-03T15:22:38Z
Duplicate of #342
978.6038 USDC - $978.60
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L312-L317
Users are unable to call cancelOrder
successfully to cancel order if users set o.tokenAmt to uint256.max.
function cancelOrder(Order calldata o) public nonReentrant { require(o.signer == msg.sender); (, bytes32 hashStruct, ) = validateOrder(o); filled[hashStruct] = o.tokenAmt + 1; emit OrderCancelled(hashStruct); }
The cancelOrder
uses o.tokenAmt + 1
to cancel orders, it may cause integer overflow.
None
Use o.tokenAmt
rather than o.tokenAmt + 1
:
function cancelOrder(Order calldata o) public nonReentrant { require(o.signer == msg.sender); (, bytes32 hashStruct, ) = validateOrder(o); filled[hashStruct] = o.tokenAmt; emit OrderCancelled(hashStruct); }
#0 - dmvt
2022-10-18T10:14:08Z
@0xsaruman Can you elaborate as to why you marked this invalid?
#1 - dmvt
2022-10-21T13:01:53Z
Duplicate of #176
π Selected for report: zzzitron
Also found by: GimelSec, GiveMeTestEther, berndartmueller, sseefried
285.3609 USDC - $285.36
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L444-L451 https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L454-L457
GolomTrader
has a timelock on setting a reward distributor. However, the timelock can be bypassed by a tricky method. And RewardDistributor
has the same problem.
The timelock on setting a reward distributor can be bypassed in the following steps:
address(distributor) == address(0)
is true.
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L444-L451function setDistributor(address _distributor) external onlyOwner { if (address(distributor) == address(0)) { distributor = Distributor(_distributor); } else { pendingDistributor = _distributor; distributorEnableDate = block.timestamp + 1 days; } }
setDistributor
again. Then the timelock will be set.executeSetDistributor
to bypass the timelock. Since pendingDistributor
hasnβt been set, distributor
will be address(0) again after calling executeSetDistributor
. (And distributorEnableDate <= block.timestamp
is true, because distributorEnableDate
has not been set.)
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L454-L457function executeSetDistributor() external onlyOwner { require(distributorEnableDate <= block.timestamp, 'not allowed'); distributor = Distributor(pendingDistributor); }
distributor
is address(0), the owner can immediately set a new distributor.
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L444-L451function setDistributor(address _distributor) external onlyOwner { if (address(distributor) == address(0)) { distributor = Distributor(_distributor); } else { pendingDistributor = _distributor; distributorEnableDate = block.timestamp + 1 days; } }
RewardDistributor
has the same issue when setting a vote escrow contract.
None
GolomToken
has the correct implementation of timelock mechanism. GolomTrader
and RewardDistributor
can follow its implementation.
#0 - 0xsaruman
2022-08-22T11:40:10Z
π Selected for report: GimelSec
Also found by: GalloDaSballo, kebabsec, kenzo
515.2349 USDC - $515.23
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L242 https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L211
VoteEscrowDelegation._transferFrom
should be successfully executed if msg.sender
is the current owner, an authorized operator, or the approved address. removeDelegation
is called in _transferFrom
. removeDelegation
only accepts the token owner. Thus, _transferFrom
can only be executed by the token owner.
removeDelegation
is called in _transferFrom
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L242
function _transferFrom( address _from, address _to, uint256 _tokenId, address _sender ) internal override { require(attachments[_tokenId] == 0 && !voted[_tokenId], 'attached'); // remove the delegation this.removeDelegation(_tokenId); // Check requirements require(_isApprovedOrOwner(_sender, _tokenId)); β¦ }
However, removeDelegation
only accept the token owner
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L211
function removeDelegation(uint256 tokenId) external { require(ownerOf(tokenId) == msg.sender, 'VEDelegation: Not allowed'); uint256 nCheckpoints = numCheckpoints[tokenId]; Checkpoint storage checkpoint = checkpoints[tokenId][nCheckpoints - 1]; removeElement(checkpoint.delegatedTokenIds, tokenId); _writeCheckpoint(tokenId, nCheckpoints, checkpoint.delegatedTokenIds); }
None
Fix the permission control in removeDelegation
#0 - zeroexdead
2022-09-03T19:01:14Z
Changed the external
function to public
. Users address will be passed as msg.sender
now. https://github.com/golom-protocol/contracts/commit/10ec920765a5ee2afc2fe269d32ea9138d1156b6
π 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
If a user sends more ETH than the user has to, the contract just accepts it. The user will lose more ETH accidentally.
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L217
// attached ETH value should be greater than total value of one NFT * total number of NFTs + any extra payment to be given require(msg.value >= o.totalAmt * amount + p.paymentAmt, 'mgmtm');
None
Use ==
rather than >=
:
require(msg.value == o.totalAmt * amount + p.paymentAmt, 'mgmtm');
Or refund the money.
#0 - KenzoAgada
2022-08-04T02:50:34Z
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
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L459-L461
The protocol receives ETH by defining receive()
and fallback()
functions. Users will lose ETH when he/she accidentally sends ETH to the protocol.
https://github.com/code-423n4/2022-07-golom/blob/main/contracts/core/GolomTrader.sol#L459-L461
fallback() external payable {} receive() external payable {}
None
receive() external payable { require(msg.sender == address(WETH)); }
#0 - 0xsaruman
2022-08-22T11:36:00Z
#1 - dmvt
2022-10-14T15:29:16Z
Lack of a recovery function is low risk. Downgrading to QA.