Caviar contest - dipp's results

A fully on-chain NFT AMM that allows you to trade every NFT in a collection.

General Information

Platform: Code4rena

Start Date: 12/12/2022

Pot Size: $36,500 USDC

Total HM: 8

Participants: 103

Period: 7 days

Judge: berndartmueller

Id: 193

League: ETH

Caviar

Findings Distribution

Researcher Performance

Rank: 91/103

Findings: 1

Award: $6.99

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

6.9881 USDC - $6.99

Labels

bug
3 (High Risk)
satisfactory
duplicate-442

External Links

Lines of code

https://github.com/code-423n4/2022-12-caviar/blob/main/src/Pair.sol#L63-L99 https://github.com/code-423n4/2022-12-caviar/blob/main/src/Pair.sol#L417-L428

Vulnerability details

Impact

The addQuote function in Pair.sol calculates the amount of LPTokens received for the amount of baseTokens and fractionalTokens sent. If LPToken's supply > 0 then the min amount of baseTokenShare and fractionaTokenShare is used. When the add function is used to provide baseTokens and fractionalTokens, both amounts must be non-zero. It is possible a user sends a very small amount of 1 token and a large amount of the other (for example, the user has 1e3 fractionalTokens but can send 1e22 baseTokens). In this case, the share calculations for the token with the small amount sent could be 0 which means addQuote would return 0 (the minimum). The result is that the user could receive 0 LPTokens.

The add function allows the user to specify a minimum amount of LPTokens to receive, so a user must intentionally set minLPTokenAmount == 0. This could happen if the user uses the addQuote function to calculate minLPTokenAmount.

Proof of Concept

The test below shows how a user that does not specify a minimum amount of LPTokens could receive 0 LPTokens.

Test code added to Add.t.sol:

    function testItMints0LpTokens() public {
        // arrange
        baseTokenAmount = 1e8;
        fractionalTokenAmount = 1e18;
        deal(address(usd), address(this), baseTokenAmount, true);
        deal(address(p), address(this), fractionalTokenAmount, true);
        uint256 minLpTokenAmount = Math.sqrt(baseTokenAmount * fractionalTokenAmount);
        p.add(baseTokenAmount, fractionalTokenAmount, minLpTokenAmount); // initial add
        uint256 lpTokenSupplyBefore = lpToken.totalSupply();

        baseTokenAmount = 1e10;
        fractionalTokenAmount = 1;
        minLpTokenAmount = p.addQuote(baseTokenAmount, fractionalTokenAmount);
        deal(address(usd), babe, baseTokenAmount, true);
        deal(address(p), babe, fractionalTokenAmount, true);

        // act
        vm.startPrank(babe);
        usd.approve(address(p), type(uint256).max);
        uint256 lpTokenAmount = p.add(baseTokenAmount, fractionalTokenAmount, minLpTokenAmount);
        vm.stopPrank();

        // assert
        assertEq(lpTokenAmount, 0, "0 LPTokens returned from add");
    }

Tools Used

Consider adding a require condition that prevents 0 LPTokens minted in the add function.

#0 - soosh1337

2022-12-20T02:32:12Z

This requires a user to send "a very small amount of 1 token and a large amount of the other", and " intentionally set minLPTokenAmount == 0" and the end result is the user themselves losing funds (LP tokens).

For these reasons - Overinflated Severity.

#1 - Shungy

2022-12-20T06:23:14Z

Conditional on user error (i.e.: not setting proper slippage). Also minting 0 is equally bad to minting 1 wei, so very inflated severity, I think it should be invalidated.

#2 - c4-judge

2022-12-20T14:34:22Z

berndartmueller marked the issue as duplicate of #442

#3 - c4-judge

2023-01-16T11:54:02Z

berndartmueller marked the issue as satisfactory

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