Skip to content

feat: treat maxBidPrice == 0 as no effective cap - #366

Merged
zhongeric merged 1 commit into
Uniswap:feat/add-max-bid-price-validation-hookfrom
pamungkaski:ki/max-bid-price-zero-means-no-cap
Aug 24, 2026
Merged

zhongeric merged 1 commit into
Uniswap:feat/add-max-bid-price-validation-hookfrom
pamungkaski:ki/max-bid-price-zero-means-no-cap

Conversation

@pamungkaski

Copy link
Copy Markdown

Stacked on #365 — targets feat/add-max-bid-price-validation-hook, so the diff here is just this change.

The degenerate case

MaxBidPriceValidationHook(0) is a brick as written. CCA requires every bid to price strictly above the clearing price:

// ContinuousClearingAuction.sol
if (_maxPriceQ96 <= _checkpoint.clearingPrice) revert BidMustBeAboveClearingPrice();

and the clearing price starts at a floor of at least ConstantsLib.MIN_FLOOR_PRICE (2**32 + 1), rising from there. So every bid that could otherwise be placed has maxPrice > 0 and reverts with MaxBidPriceExceeded. A bid at maxPrice == 0 passes the hook and then fails on BidMustBeAboveClearingPrice. The result is an auction that can never accept a bid.

The proposal

Since nobody would deploy that deliberately, spend the degenerate value on the more useful meaning:

  • Document maxBidPrice == 0 as "no effective cap" in IMaxBidPriceValidationHook, so it's part of the interface contract rather than one implementation's quirk.
  • Guard the reference implementation with if (maxBidPrice != 0 && maxPrice > maxBidPrice).

For this hook it changes nothing anyone would deploy: every reachable cap is >= MIN_FLOOR_PRICE, and behavior at those values is identical. What it buys is a natural "unset" for integrators building the hook from config — today a missing/zero value yields an auction that silently accepts no bids, which is a bad failure mode for a value that's easy to leave at its default.

Tests

The BTT tree gains a when maxBidPrice is 0 branch, and the existing revert case is scoped under when maxBidPrice is not 0:

├── validate
│   ├── when maxBidPrice is 0
│   │   └── it does not revert
│   └── when maxBidPrice is not 0
│       ├── when maxPrice GT maxBidPrice
│       │   └── it reverts with {MaxBidPriceExceeded}
│       └── when maxPrice LTE maxBidPrice
│           ├── ...

Note test_WhenMaxPriceGTMaxBidPrice previously fuzzed _maxBidPrice from 0, so it would have caught this change — its lower bound moves to 1, and the zero case is asserted explicitly instead.

7/7 pass at 2500 fuzz runs. Nothing outside these three files references the hook.

Happy to drop this if you'd rather keep 0 meaning a literal cap — the interface note is the part I think is worth having either way, since the current behavior at 0 is surprising enough to deserve a line of natspec.

`MaxBidPriceValidationHook(0)` is a brick today. CCA requires every bid to
price strictly above the clearing price, which starts at a floor of at
least `ConstantsLib.MIN_FLOOR_PRICE` (2**32 + 1), so every bid that could
otherwise be placed has `maxPrice > 0` and reverts with
`MaxBidPriceExceeded`. A bid at `maxPrice == 0` clears the hook and then
fails on `BidMustBeAboveClearingPrice`. No bid can ever be placed.

Since nobody would deploy that deliberately, spend the degenerate value
on the more useful meaning: document 0 as "no effective cap" in
`IMaxBidPriceValidationHook`, and guard the reference implementation with
`maxBidPrice != 0`. This changes nothing for any cap anyone would
actually set, and gives integrators that build the hook from config a
natural "unset" value instead of an auction that silently accepts no bids.

The interface note is the contract; the guard is one implementation of it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@pamungkaski
pamungkaski requested a review from a team as a code owner August 24, 2026 18:17
@zhongeric

Copy link
Copy Markdown
Contributor

thank you!

@zhongeric
zhongeric merged commit 58a6314 into Uniswap:feat/add-max-bid-price-validation-hook Aug 24, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants