Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PanopticFactory uses spot price when deploying new pools, resulting in liquidity manipulation when minting #537

Open
c4-bot-7 opened this issue Apr 22, 2024 · 8 comments
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue M-01 primary issue Highest quality submission among a set of duplicates 🤖_30_group AI based duplicate group recommendation satisfactory satisfies C4 submission criteria; eligible for awards selected for report This submission will be included/highlighted in the audit report sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue

Comments

@c4-bot-7
Copy link
Contributor

Lines of code

https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/PanopticFactory.sol#L341-L374

Vulnerability details

Impact

When deployNewPool is called it uses the spot price of the pool, which can be manipulated through a flashloan and thus could return a highly inaccurate result.

The price is used when deciding how much liquidity should be minted for each token, so this can result in an unbalanced pool.

In other parts of the code, this is not an issue as there are oracles that prevent price manipulations, but in case there aren't any checks to avoid so.

Proof of Concept

The spot price is used to calculate the range liquidity for each token:

@>	(uint160 currentSqrtPriceX96, , , , , , ) = v3Pool.slot0();

	// For full range: L = Δx * sqrt(P) = Δy / sqrt(P)
	// We start with fixed token amounts and apply this equation to calculate the liquidity
	// Note that for pools with a tickSpacing that is not a power of 2 or greater than 8 (887272 % ts != 0),
	// a position at the maximum and minimum allowable ticks will be wide, but not necessarily full-range.
	// In this case, the `fullRangeLiquidity` will always be an underestimate in respect to the token amounts required to mint.
	uint128 fullRangeLiquidity;
	unchecked {
	    // Since we know one of the tokens is WETH, we simply add 0.1 ETH + worth in tokens
	    if (token0 == WETH) {
	        fullRangeLiquidity = uint128(
@>	            Math.mulDiv96RoundingUp(FULL_RANGE_LIQUIDITY_AMOUNT_WETH, currentSqrtPriceX96)
	        );
	    } else if (token1 == WETH) {
	        fullRangeLiquidity = uint128(
	            Math.mulDivRoundingUp(
	                FULL_RANGE_LIQUIDITY_AMOUNT_WETH,
	                Constants.FP96,
@>	                currentSqrtPriceX96
	            )
	        );
	    } else {
	        // Find the resulting liquidity for providing 1e6 of both tokens
	        uint128 liquidity0 = uint128(
@>	            Math.mulDiv96RoundingUp(FULL_RANGE_LIQUIDITY_AMOUNT_TOKEN, currentSqrtPriceX96)
	        );
	        uint128 liquidity1 = uint128(
	            Math.mulDivRoundingUp(
	                FULL_RANGE_LIQUIDITY_AMOUNT_TOKEN,
	                Constants.FP96,
@>	                currentSqrtPriceX96
	            )
	        );

	        // Pick the greater of the liquidities - i.e the more "expensive" option
	        // This ensures that the liquidity added is sufficiently large
	        fullRangeLiquidity = liquidity0 > liquidity1 ? liquidity0 : liquidity1;
	    }
	}

https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/PanopticFactory.sol#L341-L374

But unlike other parts of the code, the PanopticFactory doesn't have any checks against the price (it doesn't use any oracles nor the TWAP), so each token liquidity is manipulable through flash loans.

Tools Used

Manual review

Recommended Mitigation Steps

Consider using the TWAP price instead of the spot price.

Assessed type

Uniswap

@c4-bot-7 c4-bot-7 added 3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working labels Apr 22, 2024
c4-bot-8 added a commit that referenced this issue Apr 22, 2024
@c4-bot-13 c4-bot-13 added the 🤖_30_group AI based duplicate group recommendation label Apr 22, 2024
@c4-judge
Copy link
Contributor

Picodes marked the issue as primary issue

@c4-judge c4-judge added the primary issue Highest quality submission among a set of duplicates label Apr 23, 2024
@dyedm1 dyedm1 added the sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue label Apr 26, 2024
@dyedm1
Copy link

dyedm1 commented Apr 26, 2024

True, but I don't see negative consequences for this? This function is just a way to add some full-range liquidity to the pool so the entire range can be swapped across, and depending on the tokens we can add very small/large amounts of liquidity anyway (mentioned in the readme: Depending on the token, the amount of funds required for the initial factory deployment may be high or unrealistic)

@Picodes
Copy link

Picodes commented May 1, 2024

@dyedm1 assuming the deployer has infinite approvals, can't we imagine a scenario where, by manipulating the spot pool price, it ends up depositing way too many token1 and getting sandwiched leading to a significant loss?

Said differently the risk is that currently the deployer has no control over the amount of token1 he will donate and this amount can be manipulated by an attacker.

@c4-judge
Copy link
Contributor

c4-judge commented May 1, 2024

Picodes marked the issue as satisfactory

@c4-judge c4-judge added satisfactory satisfies C4 submission criteria; eligible for awards 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value downgraded by judge Judge downgraded the risk level of this issue and removed 3 (High Risk) Assets can be stolen/lost/compromised directly labels May 1, 2024
@c4-judge
Copy link
Contributor

c4-judge commented May 1, 2024

Picodes changed the severity to 2 (Med Risk)

@Picodes
Copy link

Picodes commented May 1, 2024

This is at most Medium to me considering pool deployers are advanced users and you need to deploy a pool where the manipulation cost is low which should remain exceptional.

@c4-judge
Copy link
Contributor

c4-judge commented May 1, 2024

Picodes marked the issue as selected for report

@c4-judge c4-judge added the selected for report This submission will be included/highlighted in the audit report label May 1, 2024
@dyedm1
Copy link

dyedm1 commented May 6, 2024

Yeah I agree this might be less than ideal if you have infinite approvals. Our UI doesn't do infinite approvals to the factory, but some wallets allow users to edit the approval amount before signing the transaction, so it might be prudent to add slippage checks here (to make the process idiot-proof).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue M-01 primary issue Highest quality submission among a set of duplicates 🤖_30_group AI based duplicate group recommendation satisfactory satisfies C4 submission criteria; eligible for awards selected for report This submission will be included/highlighted in the audit report sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue
Projects
None yet
Development

No branches or pull requests

6 participants