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: 47/101
Findings: 2
Award: $93.14
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xSmartContract
Also found by: 0xAgro, 0xNazgul, 0xPanda, 0xbepresent, 0xfuje, Awesome, B2, Bnke0x0, Deivitto, Diana, Funen, Jeiwan, JohnSmith, Josiah, R2, RaymondFam, Rolezn, Sathish9098, Waze, adriro, aphak5010, brgltd, btk, carrotsmuggler, ch0bu, chaduke, codeislight, codexploder, cryptostellar5, csanuragjain, danyams, datapunk, delfin454000, deliriusz, eierina, erictee, fatherOfBlocks, gz627, gzeon, hansfriese, hihen, jadezti, joestakey, keccak123, martin, nameruse, oyc_109, pedr02b2, perseverancesuccess, rbserver, rotcivegaf, rvierdiiev, sakshamguruji, shark, simon135, subtle77, unforgiven, xiaoming90, yixxas
53.4851 USDC - $53.49
In the transfer function https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PxERC20.sol#L80-L91 ,
there should be a check like amount< balanceOf[msg.sender]
which would revert with an appropriate error string so that
in cases where the user mistakenly gives a higher value to amount
then he is prompted with a appropriate error.
While it doesn’t save any gas because the compiler knows that developers often make this mistake, it’s still best to use the right tool for the task at hand. There is a difference between constant variables and immutable variables, and they should each be used in their appropriate contexts. constants should be used for literal values written into the code, and immutable variables should be used for expressions, or values calculated in, or passed into the constructor.
Instances: https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PxERC20.sol#L9 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PxERC20.sol#L10
Public functions that are not called within the contract should be labelled as external instead to maintain readability throughout the codebase.
Instances: https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PxERC20.sol#L80 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PxERC20.sol#L109 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/AutoPxGmx.sol#L315 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/AutoPxGmx.sol#L339 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/AutoPxGlp.sol#L177 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/AutoPxGlp.sol#L151
As a good coding practice , the internal functions should be named beginning with an underscore.
Instances: https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/AutoPxGlp.sol#L462 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/AutoPxGlp.sol#L474 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/AutoPxGlp.sol#L487 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/AutoPxGlp.sol#L501 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/AutoPxGmx.sol#L222
There are instances throughout the code base where areas such as function lack comments which makes code readability more tough . Instances: https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexRewards.sol#L19 This struct lacks comments about its constituents https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/AutoPxGmx.sol#L315 This withdraw function lacks comments about the parameters of the function. https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexGmx.sol#L68-L75 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/AutoPxGmx.sol#L15-L31
Lack of zero address check on functions like transfer functions can be dangerous as , if the to
address is mistakenly set to a 0 address ,
it might lead to loss of funds as the funds would be transferred to the 0-address.
Instances: https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PxERC20.sol#L80 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PxERC20.sol#L110 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PxERC20.sol#L111
Index event fields make the field more quickly accessible to off-chain tools that parse events. However, note that each index field costs extra gas during emission, so it’s not necessarily best to index the maximum allowed per event (three fields). Each event should use three indexed fields if there are three or more fields, and gas usage is not particularly of concern for the events in question. If there are fewer than three fields, all of the fields should be indexed.
Instances: https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexFees.sol#L34 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexFees.sol#L35 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexFees.sol#L37 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/PxGmxReward.sol#L21 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/PxGmxReward.sol#L22 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/PxGmxReward.sol#L28 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/PxGmxReward.sol#L29 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexRewards.sol#L49 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexRewards.sol#L50 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexRewards.sol#L56 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexRewards.sol#L63 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexRewards.sol#L33 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/AutoPxGmx.sol#L39-L44 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/AutoPxGlp.sol#L35-L40 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexGmx.sol#L86 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexGmx.sol#L95 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexGmx.sol#L125 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexGmx.sol#L133 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexGmx.sol#L140-L143
In the _globalAccrue function https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/PxGmxReward.sol#L49rewards is calculated by uint256 rewards = globalState.rewards + (block.timestamp - globalState.lastUpdate) * globalState.lastSupply;
whereas in _userAccrue function https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/PxGmxReward.sol#L68 it is calculated as uint256 rewards = u.rewards + u.lastBalance * (block.timestamp - u.lastUpdate);
They should be made consistent with each other(The order in which the formula is put)
The function here https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexFees.sol#L83 lets the owner set the
treasury fee percent , but this function lacks the check to see if the owner mistakenly sets the fee to 0.
Cause if he/she sets the fee to 0 then no fees/rewards would be sent to the treasury disrupting the flow of the logic.
Add a check something like require(fee != 0 )
In the function here https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/AutoPxGmx.sol#L326 it sets the allowance
to the variable named allowed , but does not check if the allowance is sufficient for the transfer to go through , a user should know why his transaction reverted via a require statement or revert statement.
Add a check like allowance[owner][msg.sender] >= shares
This will also prevent a abrupt revert on https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/AutoPxGmx.sol#L329
#0 - c4-judge
2022-12-04T20:42:47Z
Picodes marked the issue as grade-b
🌟 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
There is a check at https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexRewards.sol#L385 which checks
globalRewards != 0 && userRewards != 0
, we know that globalRewards is always greater than or equal to userRewards and therefore
we can simplify this check to just userRewards != 0
Here https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexRewards.sol#L163-L166 we are iterating through all the
reward tokens to see if the reward token we want to add is already present in the array , in the worst case it will iterate through the whole
array , what we can do instead is , is in the ProducerToken struct at https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexRewards.sol#L19 add a mapping like isRewardToken , which sets a reward token to true if the reward token
is listed/added to the rewardTokens array and then we can reduce the check from a for loop to just if(isRewardToken)
Using the addition operator instead of plus-equals saves 113 gas
Instances: https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PxERC20.sol#L90 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PxERC20.sol#L119 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PxERC20.sol#L124 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PxERC20.sol#L85 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/PxGmxReward.sol#L95 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexRewards.sol#L361
Saves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot. Finally, if both fields are accessed in the same function, can save ~42 gas per access due to not having to recalculate the key’s keccak256 hash (Gkeccak256 - 30 gas) and that calculation’s associated stack operations.
Instances: Mappings at https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexRewards.sol#L23 and https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexRewards.sol#L31 can be considered for merge.
When fetching data from a storage location, assigning the data to a memory variable causes all fields of the struct/array to be read from storage, which incurs a Gcoldsload (2100 gas) for each field of the struct/array. If the fields are read from the new memory variable, they incur an additional MLOAD rather than a cheap stack read. Instead of declaring the variable with the memory keyword, declaring the variable with the storage keyword and caching any fields that need to be re-read in stack variables, will be much cheaper, only incurring the Gcoldsload for the fields actually read. The only time it makes sense to read the whole struct/array into a memory variable, is if the full struct/array is being returned by the function, is being passed to a function that requires memory, or if the array/struct is being read from another memory array/struct.
Instances: https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexRewards.sol#L160 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexRewards.sol#L216 https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/PirexRewards.sol#L386
#0 - Picodes
2022-12-05T14:02:55Z
ITERATING OVER THE REWARDS ARRAY COSTS HIGH GAS -> I doubt this would be efficient as this function is not supposed to called frequently
#1 - c4-judge
2022-12-05T14:03:03Z
Picodes marked the issue as grade-b
#2 - drahrealm
2022-12-09T06:46:47Z
Most findings already exist on earlier confirmed findings
#3 - c4-sponsor
2022-12-09T06:46:52Z
drahrealm marked the issue as sponsor disputed