# User can pause all auctions by overflow in mid-price average

Bug Deep Dive #12 · 8 December 2025

Bug Deep Dives · [The Contest Academy](https://0xsimao.com/the-contest-academy) · 0xSimao

---

| Title | User can pause all auctions by overflow in mid-price average |
| Reward | $3318, Unique |
| Contest | Dango Dex - 15 Sep 2025 on Sherlock |
| Author | Ziusz |
| Context | Math Overflow |

Unchecked addition of `best_bid_price` and `best_ask_price` when saving the mid price can pause the auction for every trader. An attacker places one very high-price ask and one low-price bid so that both best prices exist; then $\text{mid} = \frac{\text{bid} + \text{ask}}{2}$ overflows, the auction submessage fails, and `PAUSED` is set to true.\
In `cron.rs:630` the mid price is computed by adding both prices and halving:

```rust
fn clear_orders_of_pair(...) -> anyhow::Result<()> {
    // [...]
    let mid_price = match (best_bid_price, best_ask_price) {
        // @audit Can overflow Udec128_24 when ask is near max and bid > 0
        (Some(bid), Some(ask)) => Some(bid.checked_add(ask)?.checked_mul(HALF)?),
        (Some(bid), None) => Some(bid),
        (None, Some(ask)) => Some(ask),
        (None, None) => None,
    };
    // [...]
}  ])
}
```

Adding two `Price` (`Udec128_24`) numbers can overflow when the ask is near the maximum and the bid is positive. The error bubbles up, the auction submessage fails, and the reply handler pauses trading in `cron.rs:65`:

```rust
pub fn reply(ctx: SudoCtx, msg: ReplyMsg, res: SubMsgResult) -> StdResult<Response> {
    match msg {
        ReplyMsg::AfterAuction {} => {
            // [...]
            // @audit Any error sets PAUSED to true globally
            PAUSED.save(ctx.storage, &true)?;
            Response::new().add_event(Paused { error: Some(error) })
        },
    }
}
```

**Note:** one condition is essential — the pair must not have passive pool reserves yet, so no passive orders cap the prices and the best bid and ask come only from user orders. Say so in the report, or it may be invalidated.

**Attack Path**

1\. Attacker sends a GTC SELL (ask) with extreme price (A) close to Price max (Udec128_24).\
2\. Attacker sends a GTC BUY (bid) with small price (e.g., 1) and quote >= min_order_size (e.g., \$10).\
3\. No match happens (1 < A), so at end of block, the contract saves resting book.\
4\. It computes `mid_price = Some(bid.checked_add(ask)?.checked_mul(HALF)?)`.\
5\. `bid + ask` overflows `Udec128_24`, so the submessage errors and the reply handler sets `PAUSED = true`.

**Alpha:** always check every equation for overflow, underflow, downcasting and rounding.

**Conclusion**

This finding would earn you **\$3318**, and you get to it by having "check every maths operation for correct behaviour" on your checklist. Also spend enough time pinning down the exact conditions and impact, so the report does not get invalidated.

[**Full Report**](https://audits.sherlock.xyz/contests/1066/report)\
**Codebase**

---

Newer: [Price cannot be represented when a high-value base asset is quoted in a high-decimal asset](https://0xsimao.com/the-contest-academy/bug-deep-dive-13) · Older: [XYK reflect_curve omits swap fee in order sizing, leaking LP fees](https://0xsimao.com/the-contest-academy/bug-deep-dive-11)
