Skip to main content
Sigvex

LP Token Inflation Remediation

How to neutralize the first-depositor share-inflation attack with virtual shares or a seeded deposit.

LP Token Inflation Remediation

Overview

Related Detector: LP Token Inflation

The first-depositor attack exploits an empty pool: the attacker mints one share, donates a large amount directly to the pool to inflate the share price, and the next depositor’s shares round down to zero — letting the attacker redeem the whole balance. The remediation is to make the empty-pool share price impossible to inflate, using virtual shares/assets or a permanent seed deposit.

Before (Vulnerable)

function deposit(uint256 assets) external returns (uint256 shares) {
    shares = totalSupply == 0 ? assets : (assets * totalSupply) / totalAssets();
    _mint(msg.sender, shares);   // second depositor can round to 0 after a donation
}

After (Fixed — virtual offset makes inflation ineffective)

uint256 private constant VIRTUAL_SHARES = 1e3;
uint256 private constant VIRTUAL_ASSETS = 1;

function deposit(uint256 assets) external returns (uint256 shares) {
    // Adding a constant virtual offset to both sides bounds the price of a single
    // share, so a donation cannot push a normal deposit to zero shares.
    shares = (assets * (totalSupply + VIRTUAL_SHARES)) / (totalAssets() + VIRTUAL_ASSETS);
    require(shares > 0, "Zero shares");
    _mint(msg.sender, shares);
}

The most robust option is to inherit OpenZeppelin’s ERC-4626, which implements the virtual-shares defense. Alternatively, mint a small amount of dead shares to address(0) at the first deposit, or seed the pool at deployment so it is never empty.

Common Mistakes

  • Adding a require(shares > 0) but leaving the underlying inflatable price, so the second depositor is simply griefed into reverting.
  • Seeding the pool with a deposit that can later be fully withdrawn, re-emptying it.
  • Using too small a virtual offset relative to the asset’s decimals, leaving a residual rounding edge.

References