Pre-auditThree days of senior audit time for $1,500, credited in full toward your Zealynx audit.3 audit days, credited toward your auditSee how →
M-06·

Unrestricted LP burn enables price inflation to exploit deposits

Not reportedoptionsleverageblack-scholes
TL;DR

The LPToken contract allows unrestricted burning of LP tokens via burn() and burnFrom().

Severity
MEDIUM
Method
MManual review
CAT.
02Section · Severity

Severity

Impact: High

Likelihood: Low

03Section · Description

Description

The LPToken contract allows unrestricted burning of LP tokens via burn() and burnFrom(). This enables an attack where the first depositor manipulates the LP price by burning nearly all of their LP tokens. This skews the pool state such that any subsequent deposit may mint less or 0 LP tokens, either causing a denial of service (if slippage checks are used) or silent fund loss (if not).

solidity
function _calcAddLiquidity() internal view returns (uint256 netAmount, uint256 pFee, uint256 lpAmount) {
--- SNIPPED ---
if (lpSupply == 0) {
lpAmount = netAmount * tokenPrice;
lpAmount = lpAmount.toDecimals(tokenDecimals + 8, plpDecimals);
} else {
@1> lpAmount = netAmount.mulDiv(tokenPrice * lpSupply, _getPoolValue(false, false) /*18, USD*/);
@2> lpAmount = lpAmount.toDecimals(tokenDecimals + 8, plpDecimals);
}
}
solidity
//> src/utils/tokens/lp/LPToken.sol
function burn(uint256 value) public override(ILPToken, ERC20Burnable) {
ERC20Burnable.burn(value);
}
function burnFrom(address _account, uint256 _amount) public override(ILPToken, ERC20Burnable) {
ERC20Burnable.burnFrom(_account, _amount);
}

Consider the following scenario: 0. Initial states: - ETH Oracle price: 1500e8 (8 decimals, 1500 USD). - USDC Oracle price: 1e8 (8 decimals, 1 USD). - LP token decimals: 18. - 0% fee.

  1. Bob attempts to add 1 ETH liquidity, which is equivalent to 1500 USD.
  2. Alice front-runs Bob's deposit with 1501 USDC, which is equivalent to 1501 USD:
    • LP mint amount: 1501e6 * 1e8 = 1501e14 -- to 18 decimals --> 1501e14 * 1e(18-14) = 1501e18 LPs.
    • PoolValue: 1501e18 ≈ 1501 USD.
  3. Alice burns all but 1 wei of LP tokens, so now 1 LP is worth 1501 USD.
  4. Bob's transaction gets executed:
    • PoolValue: 1501e18 ≈ 1501 USD.
    • LP mint amount: (1e18 * 1500e8) / 1501e18 = 99999999 -- to 18 decimals --> 99999999 / 1e(26-18) = 99999999 / 1e8 = 0 (rounding down).
    • Due to rounding down in lpAmount calculation, it causes the lpAmount to be 0.
  5. Bob also specifies the slippage _minLpAmount. This attack will create a DoS if _minLpAmount is specified. If not, this attack will steal Bob's deposits.
04Section · Recommendation

Recommendation

Restrict burning to protocol roles: Pool contract for removing liquidity or disallowing public burn() and burnFrom() if lpSupply is less than the minimum LP supply.

05Section · Report provenance

Report provenance

Published by Pashov Audit Group, with Carlos (Bloqarl) participating as a contractor. The source report states that its fixes review was not fully completed; no final remediation disposition is recorded for this finding. Read the full report.

M-06