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: 18/101
Findings: 2
Award: $771.68
🌟 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
732.0322 USDC - $732.03
GA1. https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L300
It is important to check the fee range to make sure it is no more than FEE_DONOMINATOR, otherwise line 222 will not make sense - one need to make sure it is no more than 100%. Also check f' value to make sure is within
Fees`.
GA2. https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L367
it is better to check for the last case GlpManager
as well and treat other c
value as an error. That is the purpose of enum.
if (c == Contracts.GlpManager) { gmxVault = IVault(contractAddress); return; } revert WrongContractParameter(c);
QA3: https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L71-L72
Maybe change the two variables to rewardTrackerStakedGlp
and rewardTrackerStakedGmx
.
QA4: https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexFees.sol#L20 Use FEE_PERCENT_DENOMINATOR = 10000 might give a better precision
QA5: PirexRewards.sol and PirexRewards.sol share four functions: globalAccure()
, userAccruee()
, harvet()
, and claim
, refactoring into a library or
tinheriting from a base class will be helpful
QA6: https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L953 the documentation should be ``called by the owner at the new contract".
QA7: https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L234
The _calculateRewards`()
function differentiate four cases of reward types by the two boolean variables isBasedReward
and useGmx
. It might better to introduce the following enum type
enum RewardTypes {gmxBasedRewards, glpBasedRewards, gmxEsGmxRewards, glpEsGmxRewards} function _calculateRewards(RewardTypes rt){ }
QA8: https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PxGmx.sol#L19
The PirexGmx
contract has a burn()
function that has an empty body, which overides the behavior of that of the base contract PxERC20
. As a result, PxGmx cannot be burned. It this is the intention of the design, then it is better to document it and use a revert statement in the burn implemetation to make it explicit.
QA9: https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L292
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L921
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L940
The allowance set at line L292 for gmx
to stakedGmx
needs to be reset to zero when migrating to a new contract.
QA10. https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L792-L806 This part can be revised to the following to prevent the discrepancy, a concern raised in the documentation
require(baseRewards == gmxBasedRewards + glpBaseRewards); require(esGmxRewards == gmxEsGmxRewards + glpEsGmxRewards); rewardsAmounts[0] = gmxBaseRewards; rewardsAmounts[1] = glpBaseRewards; rewardsAmounts[2] = gmxEsGmxRewards; rewardsAmounts[3] = glpEsGmxRewards;
GA11:
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L20
Contract PirexGmx
needs to inherit interface IProducer
.
contract PirexGmx is IProducer, ReentrancyGuard, Owned, Pausable {
GA12: https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexRewards.sol#L27
Better to mention PirexGmx
as the current producer, it takes a while to figure this out.
#0 - c4-judge
2022-12-05T09:58:45Z
Picodes marked the issue as grade-a
🌟 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
G1.
https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L940
Cache state variable migratedTo
since it is accessed twice in the function.
G2. https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PxGmxReward.sol#L54 https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PxGmxReward.sol#L68
Cache block.timestamp
.
G3. https://code4rena.com/contests/2022-11-redacted-cartel-contest Check whether it is necessary to change the state variables (instead of changing them nevertheless) can save gas:
if(lastSupply != totalSupply){ globalState.lastSupply = totalSupply.safeCastTo224(); } if(blocktime != lastUpdate){ globalState.lastUpdate = blocktime // blocktime is a cache of block.timestamp globalState.rewards = globalState.rewards +(blocktime - lastUpdate) * lastSupply; }
G4. https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexRewards.sol#L293-L295 Checking wether it is really necessary to change the state vairables can save gas.
if(blocktime != lastUpdate){ u.lastUpdate = blocktime; // blocktime caches block.timestamp u.rewards = u.rewards + lastBlance * (blocktime - lastUpdate); } if(lastBalance != balance){ u.lastBalance = balance.safeCastTo224(); } `` G5. https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexGmx.sol#L863 Change the argument ``string memory _delegationSpace`` to ``bytes32`` can save gas since no transformation is needed.
function setDelegationSpace(
bytes32 _delegationSpace,
bool shouldClear
) external onlyOwner {
if (shouldClear) {
// Clear the delegation for the current delegation space
clearVoteDelegate();
}
delegationSpace = _delegationSpace
emit SetDelegationSpace(_delegationSpace, shouldClear); }
#0 - c4-judge
2022-12-05T14:29:49Z
Picodes marked the issue as grade-b
#1 - c4-sponsor
2022-12-09T05:40:22Z
drahrealm marked the issue as sponsor confirmed