Trader Joe v2 contest - immeas's results

One-stop-shop decentralized trading on Avalanche.

General Information

Platform: Code4rena

Start Date: 14/10/2022

Pot Size: $100,000 USDC

Total HM: 12

Participants: 75

Period: 9 days

Judge: GalloDaSballo

Total Solo HM: 1

Id: 171

League: ETH

Trader Joe

Findings Distribution

Researcher Performance

Rank: 13/75

Findings: 1

Award: $1,251.26

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: Trust

Also found by: immeas, shung

Labels

bug
2 (Med Risk)
satisfactory
duplicate-430

Awards

1251.2571 USDC - $1,251.26

External Links

Lines of code

https://github.com/code-423n4/2022-10-traderjoe/blob/main/src/libraries/FeeHelper.sol#L55-L75

Vulnerability details

Impact

After an event of high volatility a liquidity provider can do dust trades to keep volatilityAccumulated from decreasing thus maxing out fees gained even if no "real" trades are done. Given low gas prices this might be advantageous.

In the event that this happens, it will not only cause unnaturally high fees for traders but might also affect trust in the protocol.

Proof of Concept

Test in LBPair.Fees.t.sol

    function testKeepFeeMaxByManipulatingVolatility() public {
        // distribution to make it easy to increase volatility for testing
        uint256[] memory _ids = new uint256[](9999);
        for(uint256 i; i<9999;i++) {
            _ids[i] = ID_ONE - 4999 + i;
        }

        uint256[] memory _distributionX = new uint256[](9999);
        for(uint256 i; i<5000;i++) {
            _distributionX[i+4999] = 2e14;
        }

        uint256[] memory _distributionY = new uint256[](9999);
        for(uint256 i; i<5000;i++) {
            _distributionY[i] = 2e14;
        }

        token6D.mint(address(pair),500e18);
        token18D.mint(address(pair),500e18);
        pair.mint(_ids, _distributionX, _distributionY, ALICE);

        // force up volatility for sake of testing
        token6D.mint(address(pair),30e18);
        pair.swap(true,DEV);
        FeeHelper.FeeParameters memory fees;
        fees = pair.feeParameters();
        assertEq(fees.volatilityAccumulated,1777638); // max

        // liquidity provider can keep volatility up
        for(uint256 i = 0 ; i<100 ; i++) {
            vm.warp(DEFAULT_FILTER_PERIOD-5); // enough to make sure it gest included
            token18D.mint(address(pair),2); // trade dust
            pair.swap(false,ALICE);

            vm.prank(DEV);
            factory.forceDecay(pair); // doesn't help, only affects volatilityReference

            fees = pair.feeParameters();
            assertEq(fees.volatilityAccumulated,1777638,"fee stays max"); // still max as indexRef never resets
        }
    }

Granted, this test is just a PoC because the numbers and setup is very artificial. But it proves a point that a LP, or anyone else for that matter, can manipulate the volatility calculation under certain circumstances. Other than trading at an unnaturaly high fee there's nothing the market can do to prevent it.

The max fee comes from indexRef in fee params being kept the old value before the volatility since each small trade is done before the filter period.

Tools Used

vscode, forge

This might just be an artifact of how the variable fee model and an acceptable risk, which I think is fair.

Completely mitigating this requires an overhaul of both the implementation and design of the volatility counter. Like introducing a parameter that is proportional to the amount traded. Since the circumstances for this to happen are quite special and unlikely I don't think this is needed.

However, if you want to do something about it, I would suggest adding a "safety" mechanism, similar to forceDecay(), forceResetIndex() that writes indexRef to activeId. This would give the owners the ability to manipulate both parameters that goes into the volatility calculation and stop any missuse.

#0 - Shungy

2022-10-24T09:00:44Z

I believe the finding to be technically valid.

I found it hard to ascertain the severity of this issue, hence I will not comment on that.

#1 - GalloDaSballo

2022-10-26T18:15:58Z

#2 - c4-judge

2022-11-23T18:40:02Z

GalloDaSballo marked the issue as not a duplicate

#3 - c4-judge

2022-11-23T18:40:15Z

GalloDaSballo marked the issue as duplicate of #430

#4 - Simon-Busch

2022-12-05T06:45:54Z

Marked this issue as satisfactory as requested by @GalloDaSballo

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