Skip to content

Build Not yet confirmed elsewhere1 publisher 2 min read Published

A one-wei deposit let an attacker withdraw 14,838 DAI from a Polygon Uniswap V4 vault

An attacker with one share unit withdrew about 14,838 DAI from a Polygon Uniswap V4 vault on October 9, Panda Security found. The zero-liquidity fallback paid out the whole balance, so every fallback needs the main path's proportional-payout check.

The Engineer · Build desk

Send a correction

Illustration accompanying A one-wei deposit let an attacker withdraw 14,838 DAI from a Polygon Uniswap V4 vault
Generated illustration
One share burned; USDC reached the attacker's EOA Figures from the exploit's on-chain Withdrawn and Repositioned events, and the USDC reaching the attacker, per Panda Security's review

Key figures: approximately 14,813.55 USDC reached the attacker's EOA after swaps, repayment of temporary liquidity and execution costs; the Withdrawn event shows 1 share burned; the Repositioned event recorded new liquidity of 0.

One share burned; USDC reached the attacker's EOA
FigureValueNoteClaim
Reached attacker's EOA after swaps and costs, approx.14,813.55 USDC15
Shares burned1 share14
New liquidity0 liquidity10

What happened

  • The Repositioned event recorded a new range of 276324 to 276327 and newLiquidity of 0, so the vault held its tokens with no position behind them.
  • The Withdrawn event shows one share burned, a daiOut of 14838466608989135865711 and a usdcOut of 0.
  • After swaps, repayment of the temporary liquidity and execution costs, about 14,813.55 USDC reached the attacker's externally owned account.

Why it matters

  • Who has to decide decision Audit scope has to cover branches that look inert. Panda Security says this one sat inside what looked like a harmless fallback and was neither reentrancy nor an arithmetic trick.
  • Who's exposed exposure Any vault state reachable through a public function is reachable by someone who can move the pool price. Here reposition() opened as soon as a swap pushed the tick out of range.
  • What it costs cost The loss was set by the vault's balance, not the attacker's stake. One wei of DAI bought a withdrawal limited only by what the vault held.

The bug is a missing share fraction. On the normal path, _withdraw() sizes the payout as liquidity times shareAmount, divided by currentTotalShares [8]. On the zero-liquidity path it skips that and transfers the vault's full DAI and USDC balances to the recipient. The branch uses shareAmount only in the event it emits [7].

Panda Security's review, published on DEV Community, says the code treats two different states as one. According to the review, the code takes a state in which no capital is deployed as liquidity to mean "the current redeemer owns every idle asset", and the review names that assumption the root cause [9].

The state is reachable through ordinary calls. _reposition() removes the old position, leaves the withdrawn assets in the vault, and opens a new position only if the computed newLiquidity is above zero [2]. In this transaction the new range was 276324 to 276327, three ticks wide [17], and newLiquidity came out as 0 [10]. About 14,838 DAI sat at the vault address with no position behind it [3].

For callers other than the minter, the guard on reposition() is the current tick. The call reverts with PositionInRange unless the tick is outside the active range [4]. The attacker moved the tick with a large swap funded by temporary liquidity [5]. The review wrote that "an externally influenced strategy operation could place the vault into a state that its withdrawal accounting did not handle safely" [11].

The share checks did not slow any of this. They revert on a zero amount and on a caller holding fewer shares than requested [13]. One share unit satisfied both. The Deposited event shows daiAmount of 1, and with DAI at 18 decimals that is one wei [12].

The two headline figures measure different things. The vault paid out roughly 14,838.47 DAI, and about 14,813.55 USDC reached the attacker's EOA after swaps, repayment of temporary liquidity and execution costs [15]. Treating one DAI as one USDC, the gap is about 24.92 [18]. The review excerpt does not split that gap by cost.

In our view the invariant belongs to the function, not the branch. Whichever path runs, a redeemer should receive no more than shareAmount over total shares of what the vault holds. A fallback that moves tokens is a payout path, and it gets the same test as the main one, including a test that forces liquidity to zero. The zero-liquidity state comes out of a public call that any out-of-range tick opens, so that test is cheap to write.

What to watch

  • Whether the vault's operator or Panda Security publishes a fix or post-mortem. The review excerpt does not describe one.
  • Whether other Uniswap V4 vaults with a public reposition() path carry a fallback that sweeps the whole token balance to the redeemer.

Clarity's read

What the record supports and how the coverage leans. The claims behind it follow.

Reality

Evidence72
Adoption
Not scored
Hype gap0
Incentives
Not scored
Confidence65
Why these scores

Claim ledger

Ranked by verification strength, evidence, and original report placement.

  1. [1]

    Panda Security's review found the attacker acquired one share unit, manipulated the pool so reposition() produced zero liquidity, then called withdraw(), after which the vault emptied its DAI and USDC balances into the attacker's contract.

    Reported Supported Source: Panda Security review, published on DEV Community2 sources— create a free account to open themView cited source
  2. [2]

    The internal _reposition() function removes the old position, leaves the withdrawn assets in the vault, and calculates liquidity for a new position, which is opened only if newLiquidity is greater than zero; liquidity is then set to newLiquidity.

    Reported Supported Source: Panda Security review, published on DEV Community2 sources— create a free account to open themView cited source
  3. [3]

    The old position had already been removed, leaving roughly 14,838 DAI at the vault address, and no replacement position was created.

    Reported Supported Source: Panda Security review, published on DEV Community2 sources— create a free account to open themView cited source

Get this ledger inside ChatGPT. Ask about any of our stories and the answer brings its figure, each claim’s verdict and the sources. Free, no account.

Add to ChatGPTAdd to Claude

Sources

1 independent publisher whose own reporting we read for this story.

  1. dev.to

    1 article · October 15, 2026

    How One Wei of Shares Drained 14,838 DAI: A Uniswap V4 Vault Exploit

Share your take

Let Clarity write the post for you.

Signed-in readers get a short post drafted on this story in the register they choose — narrative, analytical, or a direct position — editable to the last word before it goes anywhere. The share buttons at the top of this story work without an account.

Topics and entities

Follow any of these and your For You feed starts watching them — no settings page required.

Loading related stories