Platform: Code4rena
Start Date: 14/06/2022
Pot Size: $50,000 USDC
Total HM: 19
Participants: 99
Period: 5 days
Judge: HardlyDifficult
Total Solo HM: 4
Id: 136
League: ETH
Rank: 28/99
Findings: 5
Award: $291.78
๐ Selected for report: 0
๐ Solo Findings: 0
๐ Selected for report: hyh
Also found by: 0x29A, 0xNineDec, 0xf15ers, 0xkowloon, GreyArt, IllIllI, KIntern, Kenshin, Lambda, WatchPug, Wayne, berndartmueller, byterocket, cccz, codexploder, horsefacts, kenzo, obront, obtarian, oyc_109, peritoflores, rajatbeladiya, rfa, saian, unforgiven, zer0dot
11.084 USDC - $11.08
Admins are unable to recover any ETH locked in the contract
The function rescueETH#InfinityStaker.sol
is incorrectly implemented. It is using msg.value
instead of the balance of the contract
/// @dev Admin function to rescue any ETH accidentally sent to the contract function rescueETH(address destination) external payable onlyOwner { (bool sent, ) = destination.call{value: msg.value}(''); @audit not working require(sent, 'Failed to send Ether'); }
Replace msg.value
for address(this).balance
to recover ETH.
#0 - nneverlander
2022-06-22T13:00:34Z
Duplicate
#1 - nneverlander
2022-07-05T11:42:12Z
#2 - HardlyDifficult
2022-07-09T16:54:28Z
๐ Selected for report: WatchPug
Also found by: BowTiedWardens, GreyArt, Ruhum, berndartmueller, cccz, csanuragjain, defsec, joestakey, m9800, peritoflores, reassor, shenwilly, throttle, zer0dot
21.1924 USDC - $21.19
Admins can attack users by frontrunning them
In the function setProtocolFee#InfinityExchange.sol
function setProtocolFee(uint16 _protocolFeeBps) external onlyOwner { PROTOCOL_FEE_BPS = _protocolFeeBps;@audit medium emit NewProtocolFee(_protocolFeeBps); }
Admins can front-run user by setting PROTOCOL_FEE_BPS
to 10000 which is 100%. At the time of transfer protocolFee =amount
and remaimingAmount=0
Add a maximum reasonable limit for the fee (for example 5 or 10%)
https://github.com/code-423n4/2021-05-nftx-findings/issues/51
https://github.com/code-423n4/2021-06-gro-findings/issues/78
#0 - HardlyDifficult
2022-07-11T00:05:47Z
๐ Selected for report: shenwilly
Also found by: 0x29A, BowTiedWardens, VAD37, berndartmueller, peritoflores
136.753 USDC - $136.75
https://github.com/code-423n4/2022-06-infinity/blob/765376fa238bbccd8b1e2e12897c91098c7e5ac6/contracts/core/InfinityExchange.sol#L1260-L1263 https://github.com/code-423n4/2022-06-infinity/blob/765376fa238bbccd8b1e2e12897c91098c7e5ac6/contracts/core/InfinityExchange.sol#L231-L237
Users can lose their fund by attack from the admins
In the function updateWethTranferGas#InfinityExchange.sol
there is no limit for setting WETH_TRANSFER_GAS_UNITS
. As this is a kind of fee paid by from the buyers to the contract
By definition of the variable
/// @dev Gas cost for auto sniped orders are paid by the buyers and refunded to this contract in the form of WETH uint32 public WETH_TRANSFER_GAS_UNITS = 50000;
The function is
/// @dev updates the gas units required for WETH transfers function updateWethTranferGas(uint32 _wethTransferGasUnits) external onlyOwner { WETH_TRANSFER_GAS_UNITS = _wethTransferGasUnits; emit NewWethTransferGasUnits(_wethTransferGasUnits);@audit medium }
And at the _execMatchOneToOneOrders#InfinityExchange.sol
uint256 gasCost = (startGasPerOrder - gasleft() + wethTransferGasUnits) * tx.gasprice; // if the execution currency is weth, we can send the protocol fee and gas cost in one transfer to save gas // else we need to send the protocol fee separately in the execution currency if (buy.execParams[1] == weth) { IERC20(weth).safeTransferFrom(buy.signer, address(this), protocolFee + gasCost); } else { IERC20(buy.execParams[1]).safeTransferFrom(buy.signer, address(this), protocolFee); IERC20(weth).safeTransferFrom(buy.signer, address(this), gasCost); }
gasCost will be extremely high and buyer will paid this to the contract IERC20(weth).safeTransferFrom(buy.signer, address(this), protocolFee + gasCost);
Add a maximum reasonable WETH_TRANSFER_GAS_UNITS.
#0 - nneverlander
2022-06-22T17:48:03Z
Duplicate
#1 - HardlyDifficult
2022-07-11T22:49:27Z
๐ Selected for report: joestakey
Also found by: 0x1f8b, 0x29A, 0x52, 0xDjango, 0xNazgul, 0xNineDec, 0xf15ers, 0xkowloon, 0xmint, 8olidity, BowTiedWardens, Chom, Cityscape, Czar102, ElKu, FSchmoede, Funen, GimelSec, GreyArt, IllIllI, KIntern, Kaiziron, Kenshin, Lambda, MadWookie, MiloTruck, PPrieditis, Picodes, Ruhum, Sm4rty, StErMi, TerrierLover, TomJ, Treasure-Seeker, VAD37, WatchPug, Wayne, _Adam, a12jmx, abhinavmir, antonttc, apostle0x01, asutorufos, berndartmueller, cccz, cloudjunky, codexploder, cryptphi, csanuragjain, defsec, delfin454000, fatherOfBlocks, georgypetrov, hake, hansfriese, horsefacts, hyh, k, kenta, nxrblsrpr, oyc_109, peritoflores, rajatbeladiya, reassor, rfa, robee, sach1r0, saian, samruna, shenwilly, simon135, sorrynotsorry, sseefried, throttle, unforgiven, wagmi, zzzitron
49.0062 USDC - $49.01
In the function updatePenalties#InfinityExchange.sol
function updatePenalties( uint16 threeMonthPenalty, uint16 sixMonthPenalty, uint16 twelveMonthPenalty ) external onlyOwner { THREE_MONTH_PENALTY = threeMonthPenalty; SIX_MONTH_PENALTY = sixMonthPenalty; TWELVE_MONTH_PENALTY = twelveMonthPenalty;
}
There are not limits and also as this is a critical function lack of event emission is crucial as user need to be aware of penalties at the time of call rageQuit
Add a maximum reasonable for penalties and emit an event
#0 - nneverlander
2022-06-22T17:44:39Z
Duplicate
#1 - HardlyDifficult
2022-07-10T21:25:25Z
Fair consideration. Lowering risk and converting this into a QA report for the warden.
๐ Selected for report: IllIllI
Also found by: 0v3rf10w, 0x1f8b, 0x29A, 0xAsm0d3us, 0xDjango, 0xKitsune, 0xNazgul, 0xf15ers, 0xkatana, 0xkowloon, BowTiedWardens, Chom, ElKu, FSchmoede, Funen, GimelSec, Kaiziron, Kenshin, Lambda, MadWookie, MiloTruck, PPrieditis, Picodes, PwnedNoMore, StErMi, Tadashi, TerrierLover, TomJ, Tomio, Wayne, Waze, _Adam, antonttc, apostle0x01, asutorufos, c3phas, codexploder, defsec, delfin454000, fatherOfBlocks, hake, hansfriese, hyh, joestakey, k, kenta, oyc_109, peritoflores, reassor, rfa, robee, sach1r0, simon135, slywaters, zer0dot
73.7543 USDC - $73.75
This is tautology
require(totalStaked >= 0, 'nothing staked to rage quit');
I believe that you mean != 0, however this is not affecting the logic so I believe you could just remove it saving gas
The keyword delete refunds you with 15,000 gas. Consider using it for example in this function
function _clearUserStakedAmounts(address user) internal { // clear amounts userstakedAmounts[user][Duration.NONE].amount = 0;@audit gas "use delete instead of = assign zero in storage" userstakedAmounts[user][Duration.THREE_MONTHS].amount = 0; userstakedAmounts[user][Duration.SIX_MONTHS].amount = 0; userstakedAmounts[user][Duration.TWELVE_MONTHS].amount = 0; // clear timestamps userstakedAmounts[user][Duration.NONE].timestamp = 0; userstakedAmounts[user][Duration.THREE_MONTHS].timestamp = 0; userstakedAmounts[user][Duration.SIX_MONTHS].timestamp = 0; userstakedAmounts[user][Duration.TWELVE_MONTHS].timestamp = 0; }
The following variables could be constants .
uint256 PRECISION = 10**4;
bytes32 ORDER_HASH = 0x7bcfb5a29031e6b8d34ca1a14dd0a1f5cb11b20f755bb2a31ee3c4b143477e4a;
bytes32 ORDER_ITEM_HASH = 0xf73f37e9f570369ceaab59cef16249ae1c0ad1afd592d656afac0be6f63b87e0;
bytes32 TOKEN_INFO_HASH = 0x88f0bd19d14f8b5d22c0605a15d9fffc285ebc8c86fb21139456d305982906f1;
Infinity token is a predefined address that you would not change
This is maybe a contradictory idea but when you know the implementation of your token you can save gas if you use transfer/transferFrom
instead of safeTransfer/safeTransferFrom
.
You can consider removing the library in lines like that.
IERC20(INFINITY_TOKEN).safeTransferFrom(msg.sender, address(this), amount);@audit gas check if neccessary
Maybe you comment explaining why you use transfer. I believe that this would save lot of gas.
The function changeDuration#InfinityStaker.sol
is using nonReentrant modifier but only modifies internal variables without making any external call.
bool _isPriceValid = false;
In for loops avoid initializing i
or j
to zero
Also in the following lines the initialization is unnecessary
In the function advanceEpoch#InifityToken.sol
you are calling twice getMaxEpochs()
which is an external contract call. Consider catching in a variable instead.
#0 - nneverlander
2022-06-22T14:59:14Z
Thanks