Platform: Code4rena
Start Date: 21/11/2022
Pot Size: $90,500 USDC
Total HM: 18
Participants: 101
Period: 7 days
Judge: Picodes
Total Solo HM: 4
Id: 183
League: ETH
Rank: 89/101
Findings: 1
Award: $39.65
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: gzeon
Also found by: 0xPanda, 0xSmartContract, B2, Deivitto, Diana, JohnSmith, PaludoX0, Rahoz, RaymondFam, ReyAdmirado, Rolezn, Schlagatron, Secureverse, Tomio, __141345__, adriro, ajtra, aphak5010, c3phas, chaduke, codeislight, cryptonue, datapunk, dharma09, halden, karanctf, keccak123, oyc_109, pavankv, sakshamguruji, saneryee, unforgiven
39.6537 USDC - $39.65
Expressions for constant values such as a call to KECCAK256 should use IMMUTABLE rather than constant
PxERC20.sol#L9 PxERC20.sol#L10
In the following example (optimizer = 10000) it's possible to demostrate that I = I + X cost less gas than I += X in state variable.
contract Test_Optimization { uint256 a = 1; function Add () external returns (uint256) { a = a + 1; return a; } } contract Test_Without_Optimization { uint256 a = 1; function Add () external returns (uint256) { a += 1; return a; } }
With this optimization it's possible to save 116 gas
PirexRewards.sol#L361 PxERC20.sol#L85 PxERC20.sol#L90 PxERC20.sol#L119 PxERC20.sol#L124 PxGmxReward.sol#L95
Use unchecked { i++; } or unchecked{ ++i; } when it's not possible to overflow to save gas.
PirexRewards.sol#L163 PirexRewards.sol#L351 PirexRewards.sol#L396
When retrieving data from a memory location, assigning the data to a memory variable causes all fields of the struct/array to be read from memory, resulting in a Gcoldsload (2100 gas) for each field of the struct/array. When reading fields from new memory variables, they cause an extra MLOAD instead of a cheap stack read. Rather than declaring a variable with the memory keyword, it is much cheaper to declare a variable with the storage keyword and cache all fields that need to be read again in a stack variable, because the fields actually read will only result in a Gcoldsload. The only case where the entire struct/array is read into a memory variable is when the entire struct/array is returned by a function, passed to a function that needs memory, or when the array/struct is read from another store array/struc
Prior to 0.8.10 the compiler inserted extra code, including EXTCODESIZE (100 gas), to check for contract existence for external calls. In more recent solidity versions, the compiler will not insert these checks if the external call has a return value
PirexRewards.sol#L438 PirexRewards.sol#L466
If a function modifier such as onlyOwner is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided. The extra opcodes avoided are CALLVALUE(2),DUP1(3),ISZERO(3),PUSH2(3),JUMPI(10),PUSH1(3),DUP1(3),REVERT(0),JUMPDEST(1),POP(2), which costs an average of about 21 gas per call to the function, in addition to the extra deployment cost.
PirexGmx.sol#L272 PirexGmx.sol#L300 PirexGmx.sol#L313 PirexGmx.sol#L862 PirexGmx.sol#L884 PirexGmx.sol#L884 PirexGmx.sol#L909 PirexGmx.sol#L921 PirexGmx.sol#L956 PirexFees.sol#L63 PirexFees.sol#L83
#0 - c4-judge
2022-12-05T11:14:41Z
Picodes marked the issue as grade-b