PerpLandperpland

threat model

This page enumerates every attack class we've thought about, what an attacker would do, and the defense(s) that close it. If you can think of a class that isn't on this list, that's the interesting case — please report it.

T-1 · single-block flash-loan pump-and-dump

The original Uniperp attack. Flash-loan ETH → big direct buy → chain openLong calls at manipulated spot → self-liquidate via TWAP mismatch in the same tx.

Blocked by: D7 caps single-block curve advance at 5 ETH, so a 50-ETH pump reverts outright. D1 rejects opens against the manipulated spot if any pump does get through. D4 prevents same-block self-liquidation.

T-2 · multi-block sustained pump

Spread the attack: pre-buy under the D7 cap across many blocks, let TWAP catch up between each, then leveraged-open + dump. The single-block defenses don't catch this directly.

Blocked by: the combined cost. D7 forces the attacker's capital to sit at risk for tens of minutes. D1 + D6 cap each block's contribution. Round-trip slippage and band L-reduction on the eventual dump eat the band-capital edge. Verified empirically: a 30-ETH-scale attack nets ≤ 0.1 ETH P&L — unprofitable once gas is counted.

T-3 · abandoned-position bad-debt farming

Open leveraged positions, extract value via direct sells, never close. Bands hold phantom borrowedETH that nobody repays.

Blocked by: D10 — funding rate inflates effective debt by 50% APR. A lev-5 position with no price movement crosses the 105% health threshold in ~1 year and gets liquidated. Indefinite hold is no longer an exit path. D8 caps absolute exposure at 200 ETH; D9 auto-pauses opens past 5 ETH of bad debt.

T-4 · liquidation sandwich (MEV)

Frontrun a swap that will trigger a liquidation: dump TOKEN to push spot down, let liq sell at the manipulated spot, backrun to buy back cheap. Sandwich profit comes from user surplus.

Blocked by: M-01 — when spot has drifted from TWAP by more than 1500 ticks at scan time, the scan defers. A bot can't force a liquidation at a manipulated price.

T-5 · direct pool manipulation

Bypass the hook and call PoolManager directly: addLiquidity to inject unauthorized LP, removeLiquidity to steal, donate to skew fee accumulators.

Blocked by: beforeAddLiquidity / beforeRemoveLiquidity revert unless sender == hook. beforeDonate is registered and reverts unconditionally (D5).

T-6 · hostile staking contract

Owner sets a malicious staking that consumes all gas in notifyReward, trying to brick liquidations via the 1/64 rule starving the catch handler.

Blocked by: M-02 — staking.notifyReward is called with gas: 100_000. Catch handler always has enough gas.

T-7 · reentrancy

Malicious user contract or hostile staking tries to reenter openLong / close / claim mid-flow.

Blocked by: single nonReentrant lock across all user functions; PoolManager's own unlock guard prevents nested unlock() calls.

T-8 · cooldown asymmetry exploit

The original Uniperp had a close cooldown but no liquidation cooldown, creating an asymmetric in-tx exit via TWAP-triggered self-liquidation.

Blocked by: D4 — liquidation cooldown matches the close cooldown. Symmetric.

known limitations (not closed)

The defenses don't cover everything. Honest disclosure:

  • per-address rate limiting is absent. D7 is global — Sybils share the budget. Real Sybil resistance would need proof-of-personhood or capital lockup.
  • the TWAP is in-pool only. A sufficiently capitalized attacker who can sustain a price for 5+ minutes can move TWAP. Combined with D7 it's expensive but not impossible.
  • slippage default is loose. minHoldingOut = 0 is allowed on openLong, leaving users sandwich-vulnerable unless their frontend sets a sensible default.
  • owner key is a single point of failure. setStaking is one-shot. A compromised deploy is unrecoverable. Production deploys should use a multisig and a well-rehearsed runbook.