Skip to content

fix: support capital-preserving opposite-side bets - #122

Open
MJ-RWA wants to merge 1 commit into
SPulse-Org:mainfrom
MJ-RWA:fix/opposite-side-betting
Open

fix: support capital-preserving opposite-side bets#122
MJ-RWA wants to merge 1 commit into
SPulse-Org:mainfrom
MJ-RWA:fix/opposite-side-betting

Conversation

@MJ-RWA

@MJ-RWA MJ-RWA commented Aug 18, 2026

Copy link
Copy Markdown

Summary

Fixes the OppositeSideBet limitation that permanently locks users to the side of a prediction market they initially selected.

The implementation extends the existing position model to support opposite-side position changes while preserving the contract's existing economic and accounting invariants.

Problem

Previously, place_bet rejected any attempt to bet on the opposite side of an existing position:

if e.is_yes != is_yes {
    return Err(MarketError::OppositeSideBet);
}

This prevented users from correcting mistakes, rebalancing exposure, or switching sides before market resolution.

Simply removing this validation would be unsafe because the existing payout model assumes each user has a single-sided position.

Solution

This change introduces side-aware position tracking and treats opposite-side operations as capital-preserving position switches.

Key changes

  • Extended BetEntry to track exposure on both sides.
  • Removed the unconditional opposite-side position restriction.
  • Added capital-preserving side-switching behavior.
  • Updated market-side totals when positions change.
  • Updated claim handling for side-specific positions.
  • Updated cancellation/refund handling to prevent duplicate refunds.
  • Preserved existing same-side betting and payout behavior.
  • Added validation around position and accounting transitions.

Economic Safety

The implementation preserves the following invariants:

  • Side switching does not create additional user capital.
  • A user's existing exposure is not counted on both sides simultaneously during a switch.
  • Market total_yes and total_no remain synchronized with active positions.
  • A position cannot be claimed more than once.
  • A deposit cannot be refunded more than once.
  • Existing winning/losing payout behavior remains intact.
  • Cancellation refunds remain consistent with the existing fee and gross-deposit model.

Testing

Added/updated coverage for:

  • YES-only positions.
  • NO-only positions.
  • Repeated same-side bets.
  • YES → NO switching.
  • NO → YES switching.
  • Repeated position switching.
  • Resolution after a position switch.
  • Cancellation after a position switch.
  • Claim protection.
  • Refund protection.
  • Market total/accounting invariants.
  • Relevant edge cases.

Verification

The implementation was validated using the repository's applicable:

  • unit/integration tests;
  • formatting checks;
  • linting/clippy checks;
  • compilation/build checks;
  • repository-specific quality checks.

The final Git diff was also reviewed to ensure the changes remain limited to the scope of this issue.

Scope

This PR is intentionally focused on resolving the irreversible one-sided position limitation. It does not introduce unrelated trading, order-book, leverage, or position-management functionality.

Closes: #59

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.

[MEDIUM] OppositeSideBet permanently locks a user to one side of a market — no hedging, no rebalancing

1 participant