Reproduced Exploit

ParaSpace — [H-09] UniswapV3 tokens of certain pairs will be wrongly valued

1. Same-decimal branch: sqrt(token0Price 1e18 / token1Price) 2^96 / 1e9. 2. If token1Price > token0Price * 1e18, inner div is 0 → sqrtPriceX96 = 0. 3. Amount math treats position as pure amount0 → severe undervaluation → false liquidation.

Nov 2022Otheruntagged2 min read

Chain

Other

Category

untagged

Date

Nov 2022

Source

AuditVault

EVM Playground

Source-level debugger — step opcodes and Solidity in sync

evm-hack-analyzer

The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.

Loading fork state…

Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 15982-h-09-uniswapv3-tokens-of-certain-pairs-will-be-wrongly-value. Standalone Foundry PoC and full write-up: 15982-h-09-uniswapv3-tokens-of-certain-pairs-will-be-wrongly-value_exp in the evm-hack-registry mirror.


Vulnerability classes: arithmetic/decimal-mismatch · false liquidation

Reproduction: self-contained Foundry PoC with only forge-std — no fork. Full trace: output.txt.

AuditVault taxonomy: lang/solidity · platform/code4rena · severity/high · sector/dex · sector/lending · sector/oracle · genome: decimal-mismatch · variant · token-decimal-normalization


Key info#

ImpactHIGH — extreme price ratios zero sqrtPriceX96; healthy UniV3 LP falsely liquidatable
ProtocolParaSpace
Vulnerable codeUniswapV3OracleWrapper._getOracleData same-decimal sqrtPriceX96 branch
Bug classInteger division truncates before fixed-point scale
FindingCode4rena 2022-11-paraspace · #15982 (H-09) · reporter Trust
Compiler^0.8.24 (PoC)

TL;DR#

  1. Same-decimal branch: sqrt(token0Price * 1e18 / token1Price) * 2^96 / 1e9.
  2. If token1Price > token0Price * 1e18, inner div is 0 → sqrtPriceX96 = 0.
  3. Amount math treats position as pure amount0 → severe undervaluation → false liquidation.

The vulnerable code#

SOLIDITY
oracleData.sqrtPriceX96 = uint160(
    (SqrtLib.sqrt(
        ((oracleData.token0Price * (10 ** 18)) / (oracleData.token1Price)) // @> VULN
    ) * 2 ** 96) / 1e9
);
// FIX: scale (e.g. multiply by 2**96) before the truncating division

Diagrams#

flowchart TD A["token1Price greater than token0Price times 1e18"] --> B["Inner ratio truncates to 0"] B --> C["sqrtPriceX96 is 0"] C --> D["getAmountsForLiquidity all amount0"] D --> E["Healthy LP under-valued"] E --> F["False liquidation"]

Impact#

Users holding UniV3 NFTs on extreme-ratio pairs can be liquidated while economically healthy.

Remediation#

Multiply by 2**96 (or use higher intermediate precision) before the division that can zero.

Sources#


Sources & further analysis#

Reproductions & code

Alerts & third-party analyses

  • Web3Sec X hacked database: search.
  • Rekt leaderboard: search.
  • Solodit incident search: search.

These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.