Skip to content

feat: per-market max bet cap (#745)#890

Open
Awointa wants to merge 1 commit into
Predictify-org:masterfrom
Awointa:feature/max-bet
Open

feat: per-market max bet cap (#745)#890
Awointa wants to merge 1 commit into
Predictify-org:masterfrom
Awointa:feature/max-bet

Conversation

@Awointa

@Awointa Awointa commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

closes #745

 Summary
  
  Implements a dedicated per-market single-bet size cap, allowing admins to
  limit the maximum amount any single bet may stake on a given market
  independently of the global/per-event BetLimits.
  
  ──────────────────────────────────────────────────────────────────────────────
  
  Changes
  
  contracts/predictify-hybrid/src/bets.rs
  
  - Added PER_MARKET_MAX_BET_CAP_KEY — a new persistent storage key
  ("max_bet_cap_mkt") that stores a Map<Symbol, i128> of per-market caps.
  - Added three public helpers:
    - set_market_max_bet_cap(env, market_id, cap) — validates 0 < cap <=
  MAX_BET_AMOUNT and writes the cap.
    - get_market_max_bet_cap(env, market_id) -> Option<i128> — reads the cap,
  returns None when unset.
    - remove_market_max_bet_cap(env, market_id) — removes the cap entry (no-op
  if absent).
  
  - Updated BetValidator::validate_bet_amount_against_limits to enforce the cap
  after the existing min_bet/max_bet checks; exceeding it returns
  Error::BetExceedsCap.
  - Updated validate_bet_parameters doc-comment to reflect the new check.
  
  contracts/predictify-hybrid/src/err.rs
  
  - Added BetExceedsCap = 509 to the Error enum.
  - Added BetExceedsCap to all required match arms: recovery strategy
  (NoRecovery), severity/category (Low / Financial), human-readable message, and
  machine-readable code string ("BET_EXCEEDS_CAP").
  
  contracts/predictify-hybrid/src/lib.rs
  
  - Exposed three new contract entrypoints:
    - set_market_max_bet_cap(env, admin, market_id, cap) — admin-only; cap = 0
   removes the cap; emits bet_limits_updated event and appends an audit-trail
  record.
    - get_market_max_bet_cap(env, market_id) — read-only query.
    - remove_market_max_bet_cap(env, admin, market_id) — admin-only; emits
  bet_limits_updated with max_bet = 0 to signal removal.
  
  - All state-changing entrypoints call require_primary_admin and carry
  require_auth through the admin check.
  
  ──────────────────────────────────────────────────────────────────────────────
  
  How it works
  
  The cap sits as the innermost, most-specific constraint in bet validation:
  
  amount >= min_bet      (InsufficientStake)
  amount <= max_bet      (InvalidInput)
  amount <= per-mkt cap  (BetExceedsCap)   ← new, only when cap is set
  
  When no cap is stored for a market, validation is unchanged. The cap is stored
  separately from BetLimits so it can be updated or removed without touching the
  existing min/max configuration.
  
  ──────────────────────────────────────────────────────────────────────────────
  
  API surface (new entrypoints)
  
  ┌──────────────────────────────────────────────┬───────┬───────────────────┐
 EntrypointAuthReturns  ├──────────────────────────────────────────────┼───────┼───────────────────┤
  │ set_market_max_bet_cap(admin, market_id,     │ admin │ Result<(), Error> │
  │ cap)                                         │       │                   │
  ├──────────────────────────────────────────────┼───────┼───────────────────┤
  │ get_market_max_bet_cap(market_id)            │ none  │ Option<i128>      │
  ├──────────────────────────────────────────────┼───────┼───────────────────┤
  │ remove_market_max_bet_cap(admin, market_id)  │ admin │ Result<(), Error> │
  └──────────────────────────────────────────────┴───────┴───────────────────┘
  
  New error code
  
  ┌──────┬───────────────┬───────────────────────────────────────────────────┐
 CodeNameMeaning  ├──────┼───────────────┼───────────────────────────────────────────────────┤
  │ 509  │ BetExceedsCap │ Bet amount exceeds the per-market maximum bet cap │
  └──────┴───────────────┴───────────────────────────────────────────────────┘
  
  ──────────────────────────────────────────────────────────────────────────────
  
  Testing
  
  The implementation follows the existing BetTestSetup pattern. Tests to
  add/verify:
  
  - Happy path — bet at exactly the cap amount succeeds.
  - Over-cap rejection — bet one stroop above cap returns Error::BetExceedsCap.
  - No cap set — bets up to MAX_BET_AMOUNT are unaffected.
  - Cap removal — after remove_market_max_bet_cap, previously-rejected amount
  succeeds.
  - Cap = 0 on setter — set_market_max_bet_cap(..., 0) removes the cap.
  - Invalid cap — negative or > MAX_BET_AMOUNT values return
  - Admin auth — non-admin caller is rejected on setter/remover.
  - Isolation — cap on market A does not affect market B.
  
  Run with:
  
  cargo test -p predictify-hybrid
  
  ──────────────────────────────────────────────────────────────────────────────
  
  Checklist
  
  - [x] require_auth on every state-changing entrypoint
  - [x] Overflow-safe math (all comparisons on i128, no arithmetic)
  - [x] No unwrap() in production paths
  - [x] New error code in the reserved 509–518 range
  - [x] Audit trail record on set_market_max_bet_cap
  - [x] Event emitted on set/remove for indexer visibility
  - [x] Docs updated for all new public items

- Introduced functions to set, remove, and retrieve the per-market max single-bet cap.
- Updated error handling to include BetExceedsCap for exceeding the cap.
- Enhanced bet validation to check against the per-market cap.
@drips-wave

drips-wave Bot commented Jul 23, 2026

Copy link
Copy Markdown

@Awointa Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

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.

Add per-market max bet cap

1 participant