Redacted Cartel contest - datapunk's results

Boosted GMX assets from your favorite liquid token wrapper, Pirex - brought to you by Redacted Cartel.

General Information

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

Redacted Cartel

Findings Distribution

Researcher Performance

Rank: 27/101

Findings: 3

Award: $224.74

QA:
grade-b
Gas:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: Jeiwan

Also found by: 0xbepresent, Koolex, __141345__, cryptoDave, cryptonue, datapunk, pashov, unforgiven

Labels

bug
2 (Med Risk)
downgraded by judge
satisfactory
duplicate-271

Awards

131.6023 USDC - $131.60

External Links

Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexRewards.sol#L179 https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexRewards.sol#L387

Vulnerability details

Impact

Any unclaimed rewardTokens will be unclaimable once a rewardToken has been removed from producerTokens[producerToken].rewardTokens list.

Proof of Concept

The owner can call removeRewardToken to remove any rewardToken from a producerToken. However, if the rewardToken still has unclaimed rewards, as evidenced by producerTokens[producerToken].rewardStates, these rewards will be unclaimable.

The claim function, once identified the producerToken, loops through rewardTokens list and claims rewards as marked in rewardStates[rewardToken]. However, if a rewardToken has been removed, even if rewardStates[rewardToken] is non-zero, it would not be claimable.

Tools Used

manual

Check require(rewardStates[rewardTokens[removalIndex]] == 0) before removing the unwanted rewardToken.

#0 - c4-judge

2022-12-03T20:43:39Z

Picodes marked the issue as duplicate of #255

#1 - c4-judge

2022-12-05T10:38:57Z

Picodes marked the issue as duplicate of #255

#2 - c4-judge

2023-01-01T10:39:59Z

Picodes marked the issue as duplicate of #271

#3 - c4-judge

2023-01-01T11:11:10Z

Picodes changed the severity to 2 (Med Risk)

#4 - c4-judge

2023-01-01T11:11:12Z

Picodes marked the issue as satisfactory

L1. Depending on how many rewardTokens, the owner of PirexRewards will add to producerTokens[producerToken].rewardTokens, looping through the array may result in OOG.

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexRewards.sol#L163

L2. Avoid event spamming from userAccrue in PirexRewards.sol

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/PirexRewards.sol#L281 userAccrue generates UserAccrue event, regardless whether or not there are any changes. bracketing the updating logic and emit inside of the following condition

if (block.timestamp != u.lastUpdate || balance != u.lastBalance) { ... }

Similar issues exist in PxGmxReward.sol for _globalAccue and _userAccrue https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PxGmxReward.sol#L49 https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/PxGmxReward.sol#L68

L3. event ClaimRewards may emit rewards values that are inconsistent with the actual rewards.

This is due to the recalculation in place for rewardAmounts. ClaimRewards should emit rewardAmounts values in place the gmxBaseRewards, etc.

L4. PxGmxReward is not inheriting from ERC20, yet it is accessing ERC20 functions.

AutoPxGlp inherits from both PxGmxReward and PirexERC4626, which in turn from ERC20. Therefore, things do work. However it is best practice to make code more explicity by inheriting from ERC20.

L5. withdraw and redeem functions in AutoPxGmx can reuse the functions defined in PirexERC4626 by calling PirexERC4626.withdraw and PirexERC4626.redeem

L6. solidity always rounds down

Fees can be calculated more accurately with rounding up as needed. For example,

feeAmount = (assets * fees[f]) / FEE_DENOMINATOR; can be changed to feeAmount = (assets * fees[f] + FEE_DENOMINATOR / 2) / FEE_DENOMINATOR;

#0 - c4-judge

2022-12-05T09:51:48Z

Picodes marked the issue as grade-b

Awards

39.6537 USDC - $39.65

Labels

bug
G (Gas Optimization)
grade-b
sponsor disputed
edited-by-warden
G-07

External Links

G1. previewWithdraw and previewRedeem in AutoPxGlp.sol can be made external to save gas, since they are not called internally.

G2. harvest() can be made more gas efficient if it keeps track of lastCallTime and returns immediately if lastCallTime is the same as current block.timeStamp

G3. totalAssets() and asset.balanceOf(address(this)) does the same thing, so create one local variable to save one SLOAD https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L288

#0 - c4-judge

2022-12-05T14:24:38Z

Picodes marked the issue as grade-b

#1 - drahrealm

2022-12-09T05:44:16Z

With the latest changes to the codebase (not reflected in the frozen codebase for audit here), some of the tips here are no longer beneficial, while others are considered minor relative to the added code complexity (aside from the fact that the target chains of the protocol is Arbitrum and Avalanche)

#2 - c4-sponsor

2022-12-09T05:44:23Z

drahrealm marked the issue as sponsor disputed

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter