Repository navigation
Add draft state and betting close time to betting market events - #154
Merged
Merged
Conversation
The outcome list locked implicitly, by refusing add_outcome once total_pool was nonzero. Anyone could bet one base unit on a half-built market to freeze it with a single outcome, and the admin's add_outcome and the first bet could land in either order. And place_bet accepted stakes until settle_event ran, so anyone who saw the result before the admin settled could still bet on it. Events now start as Draft. add_outcome works only on a draft, and a new admin handler, open_betting, moves a draft with at least two outcomes to Open, so the question is fixed before any money can arrive. initialize_event takes a betting_closes_at timestamp: bets land only while now < betting_closes_at and settlement only once now >= betting_closes_at, so the two windows never overlap. cancel_event also accepts a draft. Changed in the Anchor v2 and Quasar ports with tests for each rule; two new Kani proofs cover the time windows and a lifecycle model of the guards. The Anchor v1 port is a frozen snapshot and does not change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F8Wo5zNLqZ2NQqSjGD7WpK
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F8Wo5zNLqZ2NQqSjGD7WpK
Resolved against main's Config.fee_bps -> default_fee_bps rename: new events copy config.default_fee_bps into their fee_bps, beside the new betting_closes_at field and the Draft status. Changelogs keep both entries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F8Wo5zNLqZ2NQqSjGD7WpK
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The betting market locked its outcome list implicitly, by refusing
add_outcomeoncetotal_poolwas nonzero. That let anyone freeze a half-built market with a one-minor-unit bet on its only outcome, and the admin's lastadd_outcomeand the first bet could land in either order.place_betalso accepted stakes right up untilsettle_eventran, so anyone who saw the result before the admin settled could still bet on it.Changes (Anchor v2 and Quasar)
Draft.add_outcomeworks only on a draft (EventNotDraft, which replacesBettingAlreadyStarted). A new admin handler,open_betting, moves a draft with at least two outcomes toOpen(NotEnoughOutcomesotherwise).place_beton a draft fails with the existingEventNotOpen.initialize_eventtakesbetting_closes_at, in the orderevent_id, betting_closes_at, description, because Quasar requires fixed-size arguments first. It must be in the future (CloseTimeInPast).place_betrequiresnow < betting_closes_at(BettingClosed) andsettle_eventrequiresnow >= betting_closes_at(BettingStillOpen), so the two windows never overlap. The rule lives in thebetting_is_openandmay_settlehelpers.cancel_eventaccepts a draft as well as an open event.EventStatusgainsDraft = 0and shifts the other values up so they match Anchor's borsh encoding.open_bettingtakes discriminator 9, leaving the existing ones in place.Tests and proofs
open_betting, both edges of the close time, and a close time in the past. The new Anchor tests assert the specific error code, not justis_err().proof_betting_and_settlement_windows_partition_time, andproof_outcomes_fixed_before_money_arrives, which checks a model of the lifecycle guards over every six-call sequence. The second proof fails when the old empty-pool guard is put back in the model.Verification
Checked locally:
cargo check,clippy --testsandfmtare clean for both ports on the merged head.Not run locally: the LiteSVM and quasar-test suites need SBF binaries, and the toolchain download is blocked in the environment these changes were made in. This PR's CI is their first run.
Companion book PR: quicknode/solana-book#165 (merge after this one).
🤖 Generated with Claude Code
https://claude.ai/code/session_01F8Wo5zNLqZ2NQqSjGD7WpK