Redacted Cartel contest - B2'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: 42/101

Findings: 2

Award: $93.14

QA:
grade-b
Gas:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Missing zero address check in constructor

Missing checks for zero-addresses may lead to infunctional protocol, if the variable addresses are updated incorrectly.

PxERC20(_pirexRewards, "Pirex GMX", "pxGMX", 18)

File: /src/PxGmx.sol (line 10)

require() should be used instead of assert()

assert(feeAmount + postFeeAmount == assets);

File: src/PirexGmx.sol (line 225)

Upgradeable contract is missing a __gap[50] storage variable to allow for new storage variables in later versions

While some contracts may not currently be sub-classed, adding the variable now protects against forgetting to add it in the future.

contract AutoPxGmx is ReentrancyGuard, Owned, PirexERC4626 {

File: src/vaults/AutoPxGmx.sol (line 14)

contract AutoPxGlp is PirexERC4626, PxGmxReward, ReentrancyGuard {

File: src/vaults/AutoPxGlp.sol (line 14)

Other instances of this issue are:

Use of block.timestamp

Block timestamps have historically been used for a variety of applications, such as entropy for random numbers, locking funds for periods of time, and various state-changing conditional statements that are time-dependent. Miners have the ability to adjust timestamps slightly, which can prove to be dangerous if block timestamps are used incorrectly in smart contracts.

(block.timestamp - globalState.lastUpdate) *

File: src/vaults/PxGmxReward.sol (line 54)](https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/PxGmxReward.sol#L54)

globalState.lastUpdate = block.timestamp.safeCastTo32();

File: src/vaults/PxGmxReward.sol (line 54)](https://github.com/code-423n4/2022-11-redactedcartel/blob/main/src/vaults/PxGmxReward.sol#L57)

Other instances of this issue are:

INITIALIZE functions can be front run

This function can be called by everyone. So an attacker may watch yhe mempool for this function and may frontrun it by supplying more gas. This may result in unintended behaviour

function initialize() public initializer {

File: src/PirexRewards.sol (line 85)

Event is missing indexed fields

Each event should use three indexed fields if there are three or more fields.

event SetTreasuryFeePercent(uint8 _treasuryFeePercent); event DistributeFees( ERC20 indexed token, uint256 distribution, uint256 treasuryDistribution, uint256 contributorsDistribution

File: src/PirexFees.sol (line 36-40)

event GlobalAccrue(uint256 lastUpdate, uint256 lastSupply, uint256 rewards);

File: src/vaults/PxGmxReward.sol (line 21)

Other instances of this issue are:

NatSpec is incomplete

/// @audit Missing: `@return` /** @notice Override transfer method to allow for pre-transfer internal hook @param to address Account receiving apxGLP @param amount uint256 Amount of apxGLP */ function transfer(address to, uint256 amount)

File: src/vaults/PirexERC4626.sol (line 233-238)

/// @audit Missing: '@param` /** @notice Override the withdrawal method to make sure compound is called before withdrawing */ function withdraw(

File: src/vaults/AutoPxGlp.sol (line 433-436)

Other instances of this issue are:

File is missing NatSpec

// SPDX-License-Identifier: MIT

File: src/interfaces/IAutoPxGlp.sol (line 0)

// SPDX-License-Identifier: MIT

File: src/interfaces/IProducer.sol (line 0)

// SPDX-License-Identifier: MIT

File: src/interfaces/IPirexRewards.sol (line 0)

Set garbage value in mapping for deleting that

If there is a mapping data structure present inside struct, then deleting the struct doesn't delete the mapping. Instead one should use lock to lock that data structure from further use.

delete producerTokens[producerToken].rewardRecipients[msg.sender][

File: src/PirexRewards.sol (line 139)

delete producerTokens[producerToken].rewardRecipients[lpContract][

File: src/PirexRewards.sol (line 470)

Inconsistent solidity pragma

The source files have different solidity compiler ranges referenced. This leads to potential security flaws between deployed contracts depending on the compiler version chosen for any particular file. It also greatly increases the cost of maintenance as different compiler versions have different semantics and behavior.

File: src/interfaces/IPirexRewards.sol (line 2) uses pragma solidity >=0.8.0; whereas rest of the contracts uses pragma solidity 0.8.17;

#0 - c4-judge

2022-12-05T08:52:13Z

Picodes marked the issue as grade-b

Awards

39.6537 USDC - $39.65

Labels

bug
G (Gas Optimization)
grade-b
G-27

External Links

Unused named returns

Using both named returns and a return statement isn’t necessary. Removing one of those can improve code clarity:

return (userState.lastUpdate, userState.lastBalance, userState.rewards);

File: src/PirexRewards.sol (line 220)

Multiple address mappings can be combined into a single mapping of address to a struct, where appropriate.

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

22 mapping(address => UserState) userStates; 24 mapping(address => mapping(ERC20 => address)) rewardRecipients;
23 mapping(ERC20 => uint256) rewardStates; 31 mapping(ERC20 => ProducerToken) public producerTokens;

internal functions only called once can be inlined to save gas

Not inlining costs 20 to 40 gas because of two extra JUMP instructions and additional stack operations needed for function calls.

function _globalAccrue() internal {

File: src/vaults/PxGmxReward.sol (line 49)

function _userAccrue(address user) internal {

File: src/vaults/PxGmxReward.sol (line 68)

Other instances of this issue are

<x> += <y> costs more gas than <x> = <x> + <y> for state variables

rewardState += rewardAmount;

File: src/vaults/PxGmxReward.sol (line 95)

Don't emit block.timestamp

emit GlobalAccrue(block.timestamp, totalSupply, rewards);

File: src/vaults/PxGmxReward.sol (line 61)

emit UserAccrue(user, block.timestamp, balance, rewards);

File: src/vaults/PxGmxReward.sol (line 83)

FUNCTIONS GUARANTEED TO REVERT WHEN CALLED BY NORMAL USERS CAN BE MARKED PAYABLE

If a function modifier such as onlyOwneris used, the function will revert if a normal user tries to pay the function. Marking the function as payablewill 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.

function setVoteDelegate(address voteDelegate) external onlyOwner {

File: src/PirexGmx.sol (line 884)

function initiateMigration(address newContract)

File: src/PirexGmx.sol (line 921)

Other instances of this issue are

#0 - c4-judge

2022-12-05T11:11:04Z

Picodes marked the issue as grade-b

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