Redacted Cartel contest - hansfriese'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: 28/101

Findings: 3

Award: $207.69

QA:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: cccz

Also found by: Englave, Jeiwan, aphak5010, hansfriese, immeas, rbserver, xiaoming90

Labels

bug
2 (Med Risk)
partial-50
duplicate-91

Awards

82.2514 USDC - $82.25

External Links

Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L242

Vulnerability details

Impact

A malicious user might call AutoPxGmx.compound() with a higher fee than poolFee.

As a result, there would be a fund loss for the users because they paid more than expected for the swap router.

Proof of Concept

As we can see here, Uniswap V3 introduces multiple pools for each token pair.

In the AutoPxGmx.sol, all functions like withdraw(), redeem() and beforeDeposit() use the poolFee set by admin.

But compound() itself is a public function and users can call this function for the incentive.

Users can set the fee as a parameter and the below situation would be possible.

  • Admin set poolFee = 0.3% and all functions mentioned above will use this fee percent.
  • A malicious user calls compound() with fee = 1%.
  • Then the pool of fee = 1% might exist here, the swap router will take 1% as a fee.
  • As a result, the users get fewer gmx than expected.

Tools Used

Manual Review

I think we should remove the fee param from compound() function and use poolFee by default.

#0 - c4-judge

2022-12-03T18:18:54Z

Picodes marked the issue as duplicate of #391

#1 - c4-judge

2022-12-03T18:25:03Z

Picodes marked the issue as duplicate of #179

#2 - c4-judge

2022-12-05T10:47:46Z

Picodes marked the issue as duplicate of #91

#3 - c4-judge

2023-01-01T10:44:03Z

Picodes marked the issue as satisfactory

#4 - Picodes

2023-01-01T11:04:08Z

Partial credit as this issue does not highlight the main risk which is the use of a highly illiquid pool

#5 - c4-judge

2023-01-01T11:04:12Z

Picodes marked the issue as partial-50

Findings Information

🌟 Selected for report: xiaoming90

Also found by: 0x52, 8olidity, aphak5010, bin2chen, cccz, hansfriese, hihen, joestakey, ladboy233, rvierdiiev, unforgiven

Labels

bug
2 (Med Risk)
satisfactory
duplicate-182

Awards

71.9536 USDC - $71.95

External Links

Lines of code

https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGmx.sol#L152 https://github.com/code-423n4/2022-11-redactedcartel/blob/03b71a8d395c02324cb9fdaf92401357da5b19d1/src/vaults/AutoPxGlp.sol#L130

Vulnerability details

Impact

In AutoPxGmx.sol and AudotPxGlp.sol, it doesn't approve properly when platform is changed.

As a result, PirexGmx contract can't transfer gmx or gmxBaseReward from these contracts and the main logic won't work as expected.

Proof of Concept

As we can see here and here, it approves the platform in the constructor.

But in the AutoPxGmx.setPlatform() and AudotPxGlp.setPlatform(), it doesn't approve again for the updated platform.

As a result, AutoPxGmx.depositGmx() and AudotPxGlp.depositGlp() wouldn't work properly and always revert.

    // Convert sender GMX into pxGMX and get the post-fee amount (i.e. assets)
    (, uint256 assets, ) = PirexGmx(platform).depositGmx(
        amount,
        address(this)
    );
    // Approve as needed here since it can be a new whitelisted token (unless it's the baseReward)
    if (erc20Token != gmxBaseReward) {
        erc20Token.safeApprove(platform, tokenAmount);
    }

    (, uint256 assets, ) = PirexGmx(platform).depositGlp(
        token,
        tokenAmount,
        minUsdg,
        minGlp,
        address(this)
    );

Tools Used

Manual Review

We should approve the new platform again after it's changed.

#0 - c4-judge

2022-12-03T22:13:49Z

Picodes marked the issue as duplicate of #182

#1 - c4-judge

2023-01-01T10:43:54Z

Picodes marked the issue as satisfactory

[L-01] Wrong comment

    // Approve the Uniswap V3 router to manage our base reward (inbound swap token)

It should be removed as this contract doesn't use the swap router.

[L-02] Wrong parameter for beforeDeposit()

    if (totalAssets() != 0) beforeDeposit(receiver, assets, shares);

    // Check for rounding error since we round down in previewDeposit.
    require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES");

It calls beforeDeposit() before shares is calculated so shares will be 0 always.

Although beforeDeposit() doesn't use the parameters now, it's recommened to pass correct values. (Or we can just use 0 for all).

    if (totalAssets() != 0) beforeDeposit(receiver, assets, shares);

    assets = previewMint(shares); // No need to check for rounding error, previewMint rounds up.

It's almost the same as the above case and assets is used before calculated.

[N-01] Typo

    @return rewardAmounts    ERC20[]  Reward token amounts

Change ERC20[] to uint256[].

#0 - c4-judge

2022-12-04T20:52:11Z

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