Platform: Code4rena
Start Date: 14/09/2022
Pot Size: $50,000 USDC
Total HM: 25
Participants: 110
Period: 5 days
Judge: hickuphh3
Total Solo HM: 9
Id: 162
League: ETH
Rank: 65/110
Findings: 1
Award: $52.83
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: pfapostol
Also found by: 0x040, 0x1f8b, 0x4non, 0xNazgul, 0xSmartContract, 0xc0ffEE, 0xkatana, Aymen0909, Bnke0x0, Deivitto, Diana, JAGADESH, KIntern_NA, Lambda, MiloTruck, R2, RaymondFam, Respx, ReyAdmirado, Rohan16, RoiEvenHaim, Rolezn, Ruhum, Saintcode_, Samatak, Sm4rty, SnowMan, Tomio, Tomo, WilliamAmbrozic, _Adam, __141345__, ajtra, ak1, async, c3phas, ch0bu, cryptostellar5, d3e4, delfin454000, dharma09, djxploit, durianSausage, eierina, erictee, fatherOfBlocks, gianganhnguyen, gogo, ignacio, imare, jag, jonatascm, leosathya, lukris02, malinariy, oyc_109, pashov, pauliax, peanuts, peiw, prasantgupta52, robee, rokinot, rotcivegaf, rvierdiiev, seyni, simon135, slowmoses, sryysryy, tnevler, zishansami
52.8286 USDC - $52.83
epochEnd
in indexEpochs
mapping in the factory contract, when it is not being used in the contract logic at all and when it is already being publicly stored and used in Vault contract in epochs
mapping.This will save more than 20000 gas per call to deployMoreAssets()
in VaultFactory contract
Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/VaultFactory.sol#L275
src/VaultFactory.sol 275: indexEpochs[_marketVault.index].push(_marketVault.epochEnd);
createNewMarket()
to setController()
function in VaultFactory.sol and save gas on each call to createNewMarket
Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/VaultFactory.sol#L187-L190
src/VaultFactory.sol 187: if( 188: IController(controller).getVaultFactory() != address(this) 189: ) 190: revert AddressFactoryNotInController();
++i/--i
costs less gas than post-increment i++/i--
Saves 6 gas per loop in a for loop
Total instances of this issue: 1
instance #1 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Vault.sol#L443
src/Vault.sol 443: for (uint256 i = 0; i < epochsLength(); i++) {
++i/i++
should be placed in unchecked blocks to save gas as it is impossible for them to overflow in for and while loopsUnchecked keyword is available in solidity version 0.8.0
or higher and can be applied to iterator variables to save gas.
Saves more than 30 gas
per loop.
Total instances of this issue: 1
instance #1 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Vault.sol#L443
src/Vault.sol 443: for (uint256 i = 0; i < epochsLength(); i++) {
x += y
costs more gas than x = x + y
for state variablesTotal instances of this issue: 1
instance #1 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/VaultFactory.sol#L195
src/VaultFactory.sol 195: marketIndex += 1;
if (<x> == true) ==> if (<x>) if (<x> == false) => if (!<x>)
Total instances of this issue: 6
instance #1 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Controller.sol#L93-L94
src/Controller.sol 93: if(vault.idExists(epochEnd) == false) 94: revert EpochNotExist();
instance #2 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Controller.sol#L211-L212
src/Controller.sol 211: if(insrVault.idExists(epochEnd) == false || riskVault.idExists(epochEnd) == false) 212: revert EpochNotExist();
instance #3 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Vault.sol#L96-L97
src/Vault.sol 96: if((block.timestamp < id) && idDepegged[id] == false) 97: revert EpochNotFinished();
instance #4 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Vault.sol#L215-L218
src/Vault.sol 215: if( 216: msg.sender != owner && 217: isApprovedForAll(owner, receiver) == false) 218: revert OwnerDidNotAuthorize(msg.sender, owner);
instance #5 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Vault.sol#L314-L315
src/Vault.sol 314: if(idExists[epochEnd] == true) 315: revert MarketEpochExists();
instance #6 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/rewards/RewardsFactory.sol#L96-L97
src/rewards/RewardsFactory.sol 96: if(Vault(_insrToken).idExists(_epochEnd) == false || Vault(_riskToken).idExists(_epochEnd) == false) 97: revert EpochDoesNotExist();
Solidity version 0.8.0 or higher has internal overflow/underflow checks, so using SafeMath adds overhead
Total instances of this issue: 2
instance #1 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/rewards/StakingRewards.sol#L4
src/rewards/StakingRewards.sol 4:import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol";
instance #2 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/rewards/StakingRewards.sol#L29
src/rewards/StakingRewards.sol 29: using SafeMath for uint256;
payable
to functions which are only meant to be called by specific actors like onlyAdmin
, onlyFactory
and onlyController
will save gas costMarking functions payable removes additional checks for whether a payment was provided, hence reducing gas cost
Total instances of this issue: 17
instance #1 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Vault.sol#L277
src/Vault.sol 277: function changeTreasury(address _treasury) public onlyFactory {
instance #2 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Vault.sol#L287
src/Vault.sol 287: function changeTimewindow(uint256 _timewindow) public onlyFactory {
instance #3 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Vault.sol#L295
src/Vault.sol 295: function changeController(address _controller) public onlyFactory {
instance #4 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Vault.sol#L307-L310
src/Vault.sol 307: function createAssets(uint256 epochBegin, uint256 epochEnd, uint256 _withdrawalFee) 308: public 309: onlyFactory 310: {
instance #5 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Vault.sol#L336-L340
src/Vault.sol 336: function endEpoch(uint256 id, bool depeg) 337: public 338: onlyController 339: marketExists(id) 340: {
instance #6 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Vault.sol#L350
src/Vault.sol 350: function setClaimTVL(uint256 id, uint256 claimTVL) public onlyController {
instance #7 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Vault.sol#L360-L364
src/Vault.sol 360: function sendTokens(uint256 id, address _counterparty) 361: public 362: onlyController 363: marketExists(id) 364: {
instance #8 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/VaultFactory.sol#L178-L186
src/VaultFactory.sol 178: function createNewMarket( 179: uint256 _withdrawalFee, 180: address _token, 181: int256 _strikePrice, 182: uint256 epochBegin, 183: uint256 epochEnd, 184: address _oracle, 185: string memory _name 186: ) public onlyAdmin returns (address insr, address rsk) {
instance #9 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/VaultFactory.sol#L248-L253
src/VaultFactory.sol 248: function deployMoreAssets( 249: uint256 index, 250: uint256 epochBegin, 251: uint256 epochEnd, 252: uint256 _withdrawalFee 253: ) public onlyAdmin {
instance #10 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/VaultFactory.sol#L295
src/VaultFactory.sol 295: function setController(address _controller) public onlyAdmin {
instance #11 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/VaultFactory.sol#L308-L311
src/VaultFactory.sol 308: function changeTreasury(address _treasury, uint256 _marketIndex) 309: public 310: onlyAdmin 311: {
instance #12 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/VaultFactory.sol#L327-L330
src/VaultFactory.sol 327: function changeTimewindow(uint256 _marketIndex, uint256 _timewindow) 328: public 329: onlyAdmin 330: {
instance #13 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/VaultFactory.sol#L345-L348
src/VaultFactory.sol 345: function changeController(uint256 _marketIndex, address _controller) 346: public 347: onlyAdmin 348: {
instance #14 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/VaultFactory.sol#L366
src/VaultFactory.sol 366: function changeOracle(address _token, address _oracle) public onlyAdmin {
instance #15 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/rewards/StakingRewards.sol#L213-L216
src/rewards/StakingRewards.sol 213: function recoverERC20(address tokenAddress, uint256 tokenAmount) 214: external 215: onlyOwner 216: {
instance #16 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/rewards/StakingRewards.sol#L225
src/rewards/StakingRewards.sol 225: function setRewardsDuration(uint256 _rewardsDuration) external onlyOwner {
instance #17 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/rewards/RewardsFactory.sol#L83-L87
src/rewards/RewardsFactory.sol 83: function createStakingRewards(uint256 _marketIndex, uint256 _epochEnd, uint256 _rewardDuration, uint256 _rewardRate) 84: external 85: onlyAdmin 86: returns (address insr, address risk) 87: {
Since the default value is already zero, overwriting is not required.
Saves 8 gas
per instance.
Total instances of this issue: 2
instance #1 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Vault.sol#L443
src/Vault.sol 443: for (uint256 i = 0; i < epochsLength(); i++) {
instance #2 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/rewards/StakingRewards.sol#L36
src/rewards/StakingRewards.sol 36: uint256 public periodFinish = 0;
Gas usage becomes higher with uint/int smaller than 256 bits because EVM operates on 32 bytes and uses additional operations to reduce the size from 32 bytes to the target size.
Total instances of this issue: 6
instance #1 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Controller.sol#L291-L297
src/Controller.sol 291: ( 292: uint80 roundID, 293: int256 price, 294: , 295: uint256 timeStamp, 296: uint80 answeredInRound 297: ) = priceFeed.latestRoundData();
instance #2 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/oracles/PegOracle.sol#L13
src/oracles/PegOracle.sol 13: uint8 public decimals;
instance #3 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/oracles/PegOracle.sol#L46-L56
src/oracles/PegOracle.sol 46: function latestRoundData() 47: public 48: view 49: returns ( 50: uint80 roundID, 51: int256 nowPrice, 52: uint256 startedAt, 53: uint256 timeStamp, 54: uint80 answeredInRound 55: ) 56: {
instance #4 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/oracles/PegOracle.sol#L57-L63
src/oracles/PegOracle.sol 57: ( 58: uint80 roundID1, 59: int256 price1, 60: uint256 startedAt1, 61: uint256 timeStamp1, 62: uint80 answeredInRound1 63: ) = priceFeed1.latestRoundData();
instance #5 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/oracles/PegOracle.sol#L90-L96
src/oracles/PegOracle.sol 90: ( 91: uint80 roundID1, 92: int256 price1, 93: , 94: uint256 timeStamp1, 95: uint80 answeredInRound1 96: ) = priceFeed1.latestRoundData();
instance #6 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/oracles/PegOracle.sol#L113-L119
src/oracles/PegOracle.sol 113: ( 114: uint80 roundID2, 115: int256 price2, 116: , 117: uint256 timeStamp2, 118: uint80 answeredInRound2 119: ) = priceFeed2.latestRoundData();
Custom errors are available from solidity version 0.8.4.
Total instances of this issue: 19
instance #1 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/oracles/PegOracle.sol#L23
src/oracles/PegOracle.sol 23: require(_oracle1 != address(0), "oracle1 cannot be the zero address");
instance #2 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/oracles/PegOracle.sol#L24
src/oracles/PegOracle.sol 24: require(_oracle2 != address(0), "oracle2 cannot be the zero address");
instance #3 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/oracles/PegOracle.sol#L25
src/oracles/PegOracle.sol 25: require(_oracle1 != _oracle2, "Cannot be same Oracle");
instance #4 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/oracles/PegOracle.sol#L28-L31
src/oracles/PegOracle.sol 28: require( 29: (priceFeed1.decimals() == priceFeed2.decimals()), 30: "Decimals must be the same" 31: );
instance #5 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/oracles/PegOracle.sol#L98
src/oracles/PegOracle.sol 98: require(price1 > 0, "Chainlink price <= 0");
instance #6 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/oracles/PegOracle.sol#L99-L102
src/oracles/PegOracle.sol 99: require( 100: answeredInRound1 >= roundID1, 101: "RoundID from Oracle is outdated!" 102: );
instance #7 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/oracles/PegOracle.sol#L103
src/oracles/PegOracle.sol 103: require(timeStamp1 != 0, "Timestamp == 0 !");
instance #8 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/oracles/PegOracle.sol#L121
src/oracles/PegOracle.sol 121: require(price2 > 0, "Chainlink price <= 0");
instance #9 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/oracles/PegOracle.sol#L122-L125
src/oracles/PegOracle.sol 122: require( 123: answeredInRound2 >= roundID2, 124: "RoundID from Oracle is outdated!" 125: );
instance #10 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/oracles/PegOracle.sol#L126
src/oracles/PegOracle.sol 126: require(timeStamp2 != 0, "Timestamp == 0 !");
instance #11 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/SemiFungibleVault.sol#L91
src/SemiFungibleVault.sol 91: require((shares = previewDeposit(id, assets)) != 0, "ZERO_SHARES");
instance #12 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/SemiFungibleVault.sol#L116-L119
src/SemiFungibleVault.sol 116: require( 117: msg.sender == owner || isApprovedForAll(owner, receiver), 118: "Only owner can withdraw, or owner has approved receiver for all" 119: );
instance #13 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Vault.sol#L165
src/Vault.sol 165: require((shares = previewDeposit(id, assets)) != 0, "ZeroValue");
instance #14 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/Vault.sol#L187
src/Vault.sol 187: require(msg.value > 0, "ZeroValue");
instance #15 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/rewards/StakingRewards.sol#L96
src/rewards/StakingRewards.sol 96: require(amount != 0, "Cannot stake 0");
instance #16 Link: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/rewards/StakingRewards.sol#L119
src/rewards/StakingRewards.sol 119: require(amount > 0, "Cannot withdraw 0");
instance #17 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/rewards/StakingRewards.sol#L202-L205
src/rewards/StakingRewards.sol 202: require( 203: rewardRate <= balance.div(rewardsDuration), 204: "Provided reward too high" 205: );
instance #18 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/rewards/StakingRewards.sol#L217-L220
src/rewards/StakingRewards.sol 217: require( 218: tokenAddress != address(stakingToken), 219: "Cannot withdraw the staking token" 220: );
instance #19 Permalink: https://github.com/code-423n4/2022-09-y2k-finance/blob/main/src/rewards/StakingRewards.sol#L226-L229
src/rewards/StakingRewards.sol 226: require( 227: block.timestamp > periodFinish, 228: "Previous rewards period must be complete before changing the duration for the new period" 229: );