Skip to content

BM-3017: Add market-price buffer to requestor auto-pricing#2018

Open
Wollac wants to merge 4 commits into
mainfrom
wollac/feat/market-price-buffer
Open

BM-3017: Add market-price buffer to requestor auto-pricing#2018
Wollac wants to merge 4 commits into
mainfrom
wollac/feat/market-price-buffer

Conversation

@Wollac
Copy link
Copy Markdown
Contributor

@Wollac Wollac commented May 26, 2026

When a request is auto-priced (no explicit max_price), the gas part of maxPrice already gets a 2x cushion, but the proof part — min(p99, 2·p50) × cycles from the indexer — gets none. That's just a snapshot of recent fills, so if the per-cycle market drifts up between submitting and a prover actually locking, the request can sit there unlocked until it expires. Every comparable "set a max, let someone fill it" system keeps some headroom here (ethers does 2x on gas, 1inch Fusion ~2.3% on the swap); we had zero on the proof side.

This adds a configurable buffer on the market-derived max price, default +15%.

Heads-up, this is the default path, not opt-in. ClientBuilder::build() always attaches a price provider (deployment indexer, or a built-in market-pricing fallback), so any auto-priced request without an explicit price now authorizes ~15% more than before. That's the intent — it's what lets requests lock through price drift — but worth flagging for spend expectations on the CLI default and order-generators without a --max-price flag.

A few choices worth calling out:

  • Market price only. Not applied to an explicit --max-price (taken verbatim, like today), the configured max_price_per_cycle (that's a deliberate ceiling — pushing it past what you said you'd pay is wrong), or the static fallback (already ~p99). The market estimate is the only piece that actually drifts.
  • 15% rather than 10%. Per-cycle proof prices swing more than ETH gas in % terms and a request can sit minutes before lock, so a bit more than the usual liquid-market cushion.
  • Lives on OfferLayerConfig, next to max_price_per_cycle. It's a pricing-strategy knob, not an Offer field, so it stays off OfferParams.

Gas buffering, min price, timeouts and collateral are untouched.

Tests: unit tests for the buffer math, and the price-provider e2e asserts the default buffer makes maxPrice exactly 115/100 of the un-buffered price.

…pricing

When a request is auto-priced without an explicit max_price, the gas portion of
maxPrice already carries heavy headroom (2x the gas estimate), but the proof-cycle
portion (min(p99, 2*p50) * cycles) had no cushion against the per-cycle market
drifting upward between request submission and prover lock-in. If the market moves
up, the request can sit unlocked until it expires.

Add a market_price_buffer_multiplier_percentage knob (default 115 = +15%) applied
only to the market-derived proof price. Explicit max_price, the configured
max_price_per_cycle ceiling, the static default, and the gas portion are all left
untouched.

Configurable client-wide via OfferLayerConfig and per-request via OfferParams,
which also exposes a --market-price-buffer-multiplier-percentage CLI flag.
@github-actions github-actions Bot changed the title Add market-price buffer to requestor auto-pricing BM-3017: Add market-price buffer to requestor auto-pricing May 26, 2026
@linear
Copy link
Copy Markdown

linear Bot commented May 26, 2026

BM-3017

@Wollac Wollac marked this pull request as ready for review May 27, 2026 11:17
Comment on lines +479 to +480
// Reconstructing an existing on-chain offer must not re-apply the buffer.
market_price_buffer_multiplier_percentage: None,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't really live on the OfferParams as it is intended to map cleanly to Offer on the contract.

The convention we have for stuff like this is to put it in the Config struct, e.g. OfferLayerConfig

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed in 54c6ea2

Wollac added 2 commits May 27, 2026 17:50
…fig only

OfferParams is a partial mirror of the on-chain Offer, so a pricing-strategy knob
doesn't belong there (PR review). Drop the per-request field and resolve the buffer
from OfferLayerConfig alone, alongside max_price_per_cycle.
Follow-up to the market-price buffer feature:
- Make `market_price_buffer_multiplier_percentage` a plain `u16` (default 115)
  instead of `Option<u64>`, dropping the unreachable `None` arm and the
  read-site `unwrap_or(100)` that disagreed with the 115 default.
- Use `saturating_mul` in `buffered_market_max`, matching the crate-wide
  percentage-scaling convention (e.g. apply_secondary_fulfillment_discount).
- Make the price-provider e2e assertion deterministic: zero the gas estimates
  on both builds so maxPrice is exactly the proof portion, isolating the buffer
  from gas-price noise that previously dominated and could flip the comparison.
- Fix with_price_provider docs (uses p50/p99, not p10; note the always-on
  market-pricing fallback).
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