Platform: Code4rena
Start Date: 07/04/2022
Pot Size: $100,000 USDC
Total HM: 20
Participants: 62
Period: 7 days
Judge: LSDan
Total Solo HM: 11
Id: 107
League: ETH
Rank: 31/62
Findings: 2
Award: $250.88
π Selected for report: 0
π Solo Findings: 0
π Selected for report: Dravee
Also found by: 0x1f8b, 0xDjango, 0xkatana, AuditsAreUS, Cityscape, Foundation, Funen, Hawkeye, IllIllI, JC, JMukesh, Jujic, Kthere, PPrieditis, Picodes, Ruhum, TerrierLover, TrungOre, WatchPug, berndartmueller, catchup, cccz, cmichel, delfin454000, dy, ellahi, hickuphh3, horsefacts, hubble, hyh, ilan, jayjonah8, kebabsec, kenta, minhquanym, pauliax, rayn, reassor, rfa, robee, samruna
168.4282 USDC - $168.43
2022-04-jpegd
1 follow the πππππ ππ π ππππ πππππππππππ ππππππ«π§ in deposit and claimAll. The function deposit and claimAll donβt follow the check effects interaction pattern.
https://github.com/code-423n4/2022-04-jpegd/blob/main/contracts/farming/LPFarming.sol#L214 https://github.com/code-423n4/2022-04-jpegd/blob/main/contracts/farming/LPFarming.sol#L356-L357
Update user.amount before transferFrom and userRewards[msg.sender] in claimAll.
2 use safeTransfer and safeTransferFrom in JPEGStaking.sol. SafeERC20Upgradeable is imported for IERC20Upgradeable. However, it is not used. You must use it in stake and unstake.
https://github.com/code-423n4/2022-04-jpegd/blob/main/contracts/staking/JPEGStaking.sol#L34 https://github.com/code-423n4/2022-04-jpegd/blob/main/contracts/staking/JPEGStaking.sol#L52
jpeg.safeTransferFrom(msg.sender, address(this), _amount); jpeg.safeTransfer(msg.sender, _amount);
3 use call to transfer ETH. the following line uses transfer to send ETH. However, call is recommended to send ETH. You need also check the return value of call if the transfer is successful is or not.
if (collateralAsset == ETH) { (bool success, ) = msg.sender.call{value: amount}(""); require(success, βTransfer failedβ); }
4 import safeERC20 and use safeTransferFrom instead of transferFrom in repurchase. In the following line, transferFrom is used. You can replace it with safeTransferFrom to transfer ERC20 token.
https://github.com/code-423n4/2022-04-jpegd/blob/main/contracts/vaults/NFTVault.sol#L899
using safeERC20 for IStableCoin; stablecoin.safeTransferFrom(msg.sender, position.liquidator, debtAmount + penalty);
5 Lock pragmas to specific compiler version. Contracts should be deployed with the same compiler version and flags that they have been tested with thoroughly. Locking the pragma helps to ensure that contracts do not accidentally get deployed using, for example, an outdated compiler version that might introduce bugs that affect the contract system negatively.
For example,
pragma solidity 0.8.0;
π Selected for report: Dravee
Also found by: 0v3rf10w, 0x1f8b, 0xDjango, 0xNazgul, 0xkatana, Cityscape, Cr4ckM3, FSchmoede, Foundation, Funen, Hawkeye, IllIllI, JMukesh, Meta0xNull, PPrieditis, Picodes, TerrierLover, Tomio, WatchPug, berndartmueller, catchup, delfin454000, dirk_y, ellahi, hickuphh3, ilan, kebabsec, kenta, nahnah, rayn, rfa, robee, rokinot, saian, securerodd, slywaters, sorrynotsorry
82.4497 USDC - $82.45
2022-04-jpegd gas optimization
1 delete cache for pool in deposit. The cached pool is used only one time in deposit, so you can delete it and save a little bit of gas cost.
https://github.com/code-423n4/2022-04-jpegd/blob/main/contracts/farming/LPFarming.sol#L220
deposit() gas will be from Avg 112668 to 112664 with this change according to the hardhat gas reporter.
2 Use unchecked for user.amount -= _amount. The underflow for this calculation is already checked in require statement, so you can use unchecked to save gas.
https://github.com/code-423n4/2022-04-jpegd/blob/main/contracts/farming/LPFarming.sol#L248
unchecked { user.amount -= _amount; }
withdraw() gas will be from Avg 85044 to 84891 with this change according to the hardhat gas reporter.
3 delete cache for pool in withdraw. The cached pool is used only one time in withdraw, so you can delete it and save a little bit of gas cost.
https://github.com/code-423n4/2022-04-jpegd/blob/main/contracts/farming/LPFarming.sol#L220
withdraw() gas will be from Avg 85044 to 85042 with this change according to the hardhat gas reporter.
4 use initial value for i und unchecked for increment in the loop.
https://github.com/code-423n4/2022-04-jpegd/blob/main/contracts/farming/LPFarming.sol#L281 https://github.com/code-423n4/2022-04-jpegd/blob/main/contracts/farming/LPFarming.sol#L348
For example,
for (uint256 pid; pid < length;) { // something executed unchecked { ++pid; } }
For example set() gas will be from Avg 41715 to 41611 with this change according to the hardhat gas reporter.
5 use unchecked for collateralAmount -= amount in FungibleAssetVaultForDAO. Underflow will never happen because require statement checked if collateralAmount is greater or equal than amount.
unchecked { collateralAmount -= amount; }
6 code duplication. The functions closePosition, liquidate, repurchase and claimExpiredInsuranceNFT have code duplication to delete position. Create an new internal function to save gas cost for deployment.
positionOwner[_nftIndex] = address(0); delete positions[_nftIndex]; positionIndexes.remove(_nftIndex);
https://github.com/code-423n4/2022-04-jpegd/blob/main/contracts/vaults/NFTVault.sol#L808-L810 https://github.com/code-423n4/2022-04-jpegd/blob/main/contracts/vaults/NFTVault.sol#L865-L867 https://github.com/code-423n4/2022-04-jpegd/blob/main/contracts/vaults/NFTVault.sol#L906-L908 https://github.com/code-423n4/2022-04-jpegd/blob/main/contracts/vaults/NFTVault.sol#L934-L936
For example,
function deletePosition(uint256 _nftIndex) internal {
positionOwner[_nftIndex] = address(0);
delete positions[_nftIndex];
positionIndexes.remove(_nftIndex);
}