From d2ef0860a1b287979937cb3d78a452efe74d4a43 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 8 Sep 2026 17:01:10 +0000 Subject: [PATCH 1/2] Rename betting-market Config.fee_bps to default_fee_bps The config's fee is only a default copied into each new event's fee_bps at creation (initialize_event); settlement charges the event's copy. The old name suggested the config field was the fee being charged, which it never is once an event exists. Renamed the field and the initialize_config argument in the anchor, anchor-v1, and quasar builds; account layouts and instruction data encodings are unchanged. Truth fixes found auditing alongside the rename: - quasar/README.md port notes claimed a 'side' field this program does not have (copy-over from the perpetual-futures notes); now names the actual enum, EventStatus. - 'on-chain' -> 'onchain' per the style guide. Rebuilt on current main (rather than rebased) because the branch predated the create_event -> initialize_event rename and the Quasar 0.1.0 migration. Verified with cargo check on all three program libs and test suites; the integration suites need SBF binaries that cannot be built in this sandbox (toolchain downloads are blocked by network policy). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01X78wMd7r7ZMMM4AwbbnpAD --- finance/betting-market/anchor-v1/CHANGELOG.md | 9 +++++++++ finance/betting-market/anchor-v1/README.md | 9 +++++---- .../src/instructions/initialize_config.rs | 6 +++--- .../src/instructions/initialize_event.rs | 2 +- .../anchor-v1/programs/betting-market/src/lib.rs | 7 ++++--- .../programs/betting-market/src/state/config.rs | 6 ++++-- .../programs/betting-market/src/state/event.rs | 5 +++-- .../betting-market/tests/test_betting_market.rs | 2 +- finance/betting-market/anchor/CHANGELOG.md | 9 +++++++++ finance/betting-market/anchor/README.md | 9 +++++---- .../src/instructions/initialize_config.rs | 6 +++--- .../src/instructions/initialize_event.rs | 2 +- .../anchor/programs/betting-market/src/lib.rs | 7 ++++--- .../programs/betting-market/src/state/config.rs | 6 ++++-- .../programs/betting-market/src/state/event.rs | 5 +++-- .../betting-market/tests/test_betting_market.rs | 2 +- finance/betting-market/quasar/CHANGELOG.md | 13 +++++++++++++ finance/betting-market/quasar/README.md | 7 ++++--- .../quasar/src/instructions/claim_refund.rs | 4 ++-- .../quasar/src/instructions/claim_winnings.rs | 4 ++-- .../quasar/src/instructions/close_losing_bet.rs | 4 ++-- .../quasar/src/instructions/initialize_config.rs | 6 +++--- .../quasar/src/instructions/initialize_event.rs | 2 +- finance/betting-market/quasar/src/lib.rs | 8 ++++---- finance/betting-market/quasar/src/state/config.rs | 8 +++++--- finance/betting-market/quasar/src/state/event.rs | 7 ++++--- finance/betting-market/quasar/src/tests.rs | 6 +++--- 27 files changed, 103 insertions(+), 58 deletions(-) diff --git a/finance/betting-market/anchor-v1/CHANGELOG.md b/finance/betting-market/anchor-v1/CHANGELOG.md index 4f1163881..1f23dc2f6 100644 --- a/finance/betting-market/anchor-v1/CHANGELOG.md +++ b/finance/betting-market/anchor-v1/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 2026-09-08 + +Renamed `Config.fee_bps` to `Config.default_fee_bps` (and the matching +`initialize_config` argument). The config's value is only a default copied into +each new event's `fee_bps` at creation; settlement charges the event's copy, so +the old name overstated what the config field did. The event's `fee_bps` keeps +its name because it is the fee actually charged. Account layouts are unchanged; +only the IDL field/argument names differ. + ## 2026-07-07 Added this changelog. Changes prior to this date were tracked in git history only. diff --git a/finance/betting-market/anchor-v1/README.md b/finance/betting-market/anchor-v1/README.md index 56587c283..38b30155e 100644 --- a/finance/betting-market/anchor-v1/README.md +++ b/finance/betting-market/anchor-v1/README.md @@ -29,11 +29,12 @@ powers are creating events/outcomes and choosing the winning outcome (or cancell - **Config** (`seeds = [b"config"]`) - one per deployment. Holds the `admin` (the only key that can create events/outcomes, settle, and cancel), the `token_mint` every market accepts, the - `fee_recipient`, and the `fee_bps`. + `fee_recipient`, and the `default_fee_bps` each new event copies at creation. - **Event** (`seeds = [b"event", event_id]`) - one betting market. Tracks `total_pool`, `status` (`Open` / `Settled` / `Cancelled`), and - once settled - the `winning_outcome_index`, - `winning_pool`, and `distributable_losing_pool` that the payout formula reads. The `fee_bps` is - snapshotted at creation so later Config changes can't alter a market bettors have already joined. + `winning_pool`, and `distributable_losing_pool` that the payout formula reads. The event's + `fee_bps` is copied from the config's `default_fee_bps` at creation and is what settlement + charges, so later Config changes can't alter a market bettors have already joined. - **Outcome** (`seeds = [b"outcome", event, index]`) - one possible result. Its `total_amount` is the outcome's share of the pool and the denominator for pro-rata payouts when it wins. - **Bet** (`seeds = [b"bet", outcome, bettor]`) - a bettor's total stake on one outcome. Re-betting @@ -80,7 +81,7 @@ division floors each share, leaving at most a few minor units of dust in the vau ### Instruction handlers - `initialize_config` - anyone (the signer becomes admin). One-time setup: sets admin, stake - token, fee, fee recipient. + token, default fee, fee recipient. - `initialize_event` - admin. Opens a market and creates its vault. - `add_outcome` - admin. Adds a possible result. Only before any bet is placed. - `place_bet` - bettor. Stakes tokens on one outcome; updates the pools and adds the Bet to the diff --git a/finance/betting-market/anchor-v1/programs/betting-market/src/instructions/initialize_config.rs b/finance/betting-market/anchor-v1/programs/betting-market/src/instructions/initialize_config.rs index ed66deafe..43da5ab6c 100644 --- a/finance/betting-market/anchor-v1/programs/betting-market/src/instructions/initialize_config.rs +++ b/finance/betting-market/anchor-v1/programs/betting-market/src/instructions/initialize_config.rs @@ -28,16 +28,16 @@ pub struct InitializeConfigAccountConstraints<'info> { pub fn handle_initialize_config( context: Context, - fee_bps: u16, + default_fee_bps: u16, fee_recipient: Pubkey, ) -> Result<()> { - require!(fee_bps <= MAX_FEE_BPS, BettingError::FeeTooHigh); + require!(default_fee_bps <= MAX_FEE_BPS, BettingError::FeeTooHigh); context.accounts.config.set_inner(Config { admin: context.accounts.admin.key(), token_mint: context.accounts.token_mint.key(), fee_recipient, - fee_bps, + default_fee_bps, event_count: 0, bump: context.bumps.config, }); diff --git a/finance/betting-market/anchor-v1/programs/betting-market/src/instructions/initialize_event.rs b/finance/betting-market/anchor-v1/programs/betting-market/src/instructions/initialize_event.rs index 1e90e885a..6f0414152 100644 --- a/finance/betting-market/anchor-v1/programs/betting-market/src/instructions/initialize_event.rs +++ b/finance/betting-market/anchor-v1/programs/betting-market/src/instructions/initialize_event.rs @@ -66,7 +66,7 @@ pub fn handle_initialize_event( outcome_count: 0, total_pool: 0, status: EventStatus::Open, - fee_bps: context.accounts.config.fee_bps, + fee_bps: context.accounts.config.default_fee_bps, winning_outcome_index: 0, winning_pool: 0, distributable_losing_pool: 0, diff --git a/finance/betting-market/anchor-v1/programs/betting-market/src/lib.rs b/finance/betting-market/anchor-v1/programs/betting-market/src/lib.rs index 731546e4c..f2a23566e 100644 --- a/finance/betting-market/anchor-v1/programs/betting-market/src/lib.rs +++ b/finance/betting-market/anchor-v1/programs/betting-market/src/lib.rs @@ -14,13 +14,14 @@ pub mod betting_market { use super::*; // One-time setup: the signer becomes the admin and fixes the stake token and - // the settlement fee (basis points) for every market in this deployment. + // the default settlement fee (basis points) that each new market copies at + // creation. pub fn initialize_config( context: Context, - fee_bps: u16, + default_fee_bps: u16, fee_recipient: Pubkey, ) -> Result<()> { - instructions::initialize_config::handle_initialize_config(context, fee_bps, fee_recipient) + instructions::initialize_config::handle_initialize_config(context, default_fee_bps, fee_recipient) } // Admin opens a new market and creates its pool vault. diff --git a/finance/betting-market/anchor-v1/programs/betting-market/src/state/config.rs b/finance/betting-market/anchor-v1/programs/betting-market/src/state/config.rs index 03cbcfb18..1d23ff82a 100644 --- a/finance/betting-market/anchor-v1/programs/betting-market/src/state/config.rs +++ b/finance/betting-market/anchor-v1/programs/betting-market/src/state/config.rs @@ -9,8 +9,10 @@ pub struct Config { pub admin: Pubkey, pub token_mint: Pubkey, pub fee_recipient: Pubkey, - // Protocol fee, in basis points, taken from the losing pool at settlement. - pub fee_bps: u16, + // Protocol fee, in basis points, that new events copy into their own + // `fee_bps` at creation. Settlement charges the event's copy, so changing + // this value only affects events created afterwards. + pub default_fee_bps: u16, pub event_count: u64, pub bump: u8, } diff --git a/finance/betting-market/anchor-v1/programs/betting-market/src/state/event.rs b/finance/betting-market/anchor-v1/programs/betting-market/src/state/event.rs index b88e89180..d7f0e155d 100644 --- a/finance/betting-market/anchor-v1/programs/betting-market/src/state/event.rs +++ b/finance/betting-market/anchor-v1/programs/betting-market/src/state/event.rs @@ -23,8 +23,9 @@ pub struct Event { // Sum of every stake placed across all outcomes. pub total_pool: u64, pub status: EventStatus, - // Fee snapshot taken at creation, so later Config changes can't alter a - // market that bettors have already joined. + // The fee settlement charges, copied from the config's `default_fee_bps` + // at creation so later Config changes can't alter a market that bettors + // have already joined. pub fee_bps: u16, // Fields below are written at settlement and read at claim time. pub winning_outcome_index: u8, diff --git a/finance/betting-market/anchor-v1/programs/betting-market/tests/test_betting_market.rs b/finance/betting-market/anchor-v1/programs/betting-market/tests/test_betting_market.rs index 8390c93f0..784413ad8 100644 --- a/finance/betting-market/anchor-v1/programs/betting-market/tests/test_betting_market.rs +++ b/finance/betting-market/anchor-v1/programs/betting-market/tests/test_betting_market.rs @@ -107,7 +107,7 @@ fn initialize_config_ix(admin: Pubkey, mint: Pubkey, fee_recipient: Pubkey) -> I Instruction::new_with_bytes( betting_market::id(), &betting_market::instruction::InitializeConfig { - fee_bps: FEE_BPS, + default_fee_bps: FEE_BPS, fee_recipient, } .data(), diff --git a/finance/betting-market/anchor/CHANGELOG.md b/finance/betting-market/anchor/CHANGELOG.md index 4f1163881..1f23dc2f6 100644 --- a/finance/betting-market/anchor/CHANGELOG.md +++ b/finance/betting-market/anchor/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 2026-09-08 + +Renamed `Config.fee_bps` to `Config.default_fee_bps` (and the matching +`initialize_config` argument). The config's value is only a default copied into +each new event's `fee_bps` at creation; settlement charges the event's copy, so +the old name overstated what the config field did. The event's `fee_bps` keeps +its name because it is the fee actually charged. Account layouts are unchanged; +only the IDL field/argument names differ. + ## 2026-07-07 Added this changelog. Changes prior to this date were tracked in git history only. diff --git a/finance/betting-market/anchor/README.md b/finance/betting-market/anchor/README.md index b8a22b84a..72682fec7 100644 --- a/finance/betting-market/anchor/README.md +++ b/finance/betting-market/anchor/README.md @@ -29,11 +29,12 @@ powers are creating events/outcomes and choosing the winning outcome (or cancell - **Config** (`seeds = [b"config"]`) - one per deployment. Holds the `admin` (the only key that can create events/outcomes, settle, and cancel), the `token_mint` every market accepts, the - `fee_recipient`, and the `fee_bps`. + `fee_recipient`, and the `default_fee_bps` each new event copies at creation. - **Event** (`seeds = [b"event", event_id]`) - one betting market. Tracks `total_pool`, `status` (`Open` / `Settled` / `Cancelled`), and - once settled - the `winning_outcome_index`, - `winning_pool`, and `distributable_losing_pool` that the payout formula reads. The `fee_bps` is - snapshotted at creation so later Config changes can't alter a market bettors have already joined. + `winning_pool`, and `distributable_losing_pool` that the payout formula reads. The event's + `fee_bps` is copied from the config's `default_fee_bps` at creation and is what settlement + charges, so later Config changes can't alter a market bettors have already joined. - **Outcome** (`seeds = [b"outcome", event, index]`) - one possible result. Its `total_amount` is the outcome's share of the pool and the denominator for pro-rata payouts when it wins. - **Bet** (`seeds = [b"bet", outcome, bettor]`) - a bettor's total stake on one outcome. Re-betting @@ -80,7 +81,7 @@ division floors each share, leaving at most a few minor units of dust in the vau ### Instruction handlers - `initialize_config` - anyone (the signer becomes admin). One-time setup: sets admin, stake - token, fee, fee recipient. + token, default fee, fee recipient. - `initialize_event` - admin. Opens a market and creates its vault. - `add_outcome` - admin. Adds a possible result. Only before any bet is placed. - `place_bet` - bettor. Stakes tokens on one outcome; updates the pools and adds the Bet to the diff --git a/finance/betting-market/anchor/programs/betting-market/src/instructions/initialize_config.rs b/finance/betting-market/anchor/programs/betting-market/src/instructions/initialize_config.rs index fbd0b4fd3..94b2af7da 100644 --- a/finance/betting-market/anchor/programs/betting-market/src/instructions/initialize_config.rs +++ b/finance/betting-market/anchor/programs/betting-market/src/instructions/initialize_config.rs @@ -29,16 +29,16 @@ pub struct InitializeConfigAccountConstraints { pub fn handle_initialize_config( context: &mut Context, - fee_bps: u16, + default_fee_bps: u16, fee_recipient: Address, ) -> Result<()> { - require!(fee_bps <= MAX_FEE_BPS, BettingError::FeeTooHigh); + require!(default_fee_bps <= MAX_FEE_BPS, BettingError::FeeTooHigh); *context.accounts.config = Config { admin: *context.accounts.admin.address(), token_mint: *context.accounts.token_mint.address(), fee_recipient, - fee_bps, + default_fee_bps, event_count: 0, bump: context.bumps.config, }; diff --git a/finance/betting-market/anchor/programs/betting-market/src/instructions/initialize_event.rs b/finance/betting-market/anchor/programs/betting-market/src/instructions/initialize_event.rs index 62f1c1332..c5c852e6e 100644 --- a/finance/betting-market/anchor/programs/betting-market/src/instructions/initialize_event.rs +++ b/finance/betting-market/anchor/programs/betting-market/src/instructions/initialize_event.rs @@ -68,7 +68,7 @@ pub fn handle_initialize_event( outcome_count: 0, total_pool: 0, status: EventStatus::Open, - fee_bps: context.accounts.config.fee_bps, + fee_bps: context.accounts.config.default_fee_bps, winning_outcome_index: 0, winning_pool: 0, distributable_losing_pool: 0, diff --git a/finance/betting-market/anchor/programs/betting-market/src/lib.rs b/finance/betting-market/anchor/programs/betting-market/src/lib.rs index bbd58f343..e897cfd5d 100644 --- a/finance/betting-market/anchor/programs/betting-market/src/lib.rs +++ b/finance/betting-market/anchor/programs/betting-market/src/lib.rs @@ -14,13 +14,14 @@ pub mod betting_market { use super::*; // One-time setup: the signer becomes the admin and fixes the stake token and - // the settlement fee (basis points) for every market in this deployment. + // the default settlement fee (basis points) that each new market copies at + // creation. pub fn initialize_config( context: &mut Context, - fee_bps: u16, + default_fee_bps: u16, fee_recipient: Address, ) -> Result<()> { - instructions::initialize_config::handle_initialize_config(context, fee_bps, fee_recipient) + instructions::initialize_config::handle_initialize_config(context, default_fee_bps, fee_recipient) } // Admin opens a new market and creates its pool vault. diff --git a/finance/betting-market/anchor/programs/betting-market/src/state/config.rs b/finance/betting-market/anchor/programs/betting-market/src/state/config.rs index a417c5528..4770ac65e 100644 --- a/finance/betting-market/anchor/programs/betting-market/src/state/config.rs +++ b/finance/betting-market/anchor/programs/betting-market/src/state/config.rs @@ -9,8 +9,10 @@ pub struct Config { pub admin: Address, pub token_mint: Address, pub fee_recipient: Address, - // Protocol fee, in basis points, taken from the losing pool at settlement. - pub fee_bps: u16, + // Protocol fee, in basis points, that new events copy into their own + // `fee_bps` at creation. Settlement charges the event's copy, so changing + // this value only affects events created afterwards. + pub default_fee_bps: u16, pub event_count: u64, pub bump: u8, } diff --git a/finance/betting-market/anchor/programs/betting-market/src/state/event.rs b/finance/betting-market/anchor/programs/betting-market/src/state/event.rs index 068d086ec..25e8f147e 100644 --- a/finance/betting-market/anchor/programs/betting-market/src/state/event.rs +++ b/finance/betting-market/anchor/programs/betting-market/src/state/event.rs @@ -23,8 +23,9 @@ pub struct Event { // Sum of every stake placed across all outcomes. pub total_pool: u64, pub status: EventStatus, - // Fee snapshot taken at creation, so later Config changes can't alter a - // market that bettors have already joined. + // The fee settlement charges, copied from the config's `default_fee_bps` + // at creation so later Config changes can't alter a market that bettors + // have already joined. pub fee_bps: u16, // Fields below are written at settlement and read at claim time. pub winning_outcome_index: u8, diff --git a/finance/betting-market/anchor/programs/betting-market/tests/test_betting_market.rs b/finance/betting-market/anchor/programs/betting-market/tests/test_betting_market.rs index ce27640dc..440058761 100644 --- a/finance/betting-market/anchor/programs/betting-market/tests/test_betting_market.rs +++ b/finance/betting-market/anchor/programs/betting-market/tests/test_betting_market.rs @@ -114,7 +114,7 @@ fn initialize_config_ix(admin: Address, mint: Address, fee_recipient: Address) - Instruction::new_with_bytes( betting_market::id(), &betting_market::instruction::InitializeConfig { - fee_bps: FEE_BPS, + default_fee_bps: FEE_BPS, fee_recipient, } .data(), diff --git a/finance/betting-market/quasar/CHANGELOG.md b/finance/betting-market/quasar/CHANGELOG.md index 9306abd0c..f43513d7a 100644 --- a/finance/betting-market/quasar/CHANGELOG.md +++ b/finance/betting-market/quasar/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## [2026-09-08] + +### Changed + +- Renamed `Config.fee_bps` to `Config.default_fee_bps` (and the matching + `initialize_config` argument), mirroring the Anchor builds. The config's + value is only a default copied into each new event's `fee_bps` at creation; + settlement charges the event's copy, so the old name overstated what the + config field did. Account layouts and instruction data encoding are + unchanged. Also fixed the README's port-notes bullet, which mentioned a + `side` field this program does not have (left over from the + perpetual-futures port notes). + ## [2026-07-22] ### Changed diff --git a/finance/betting-market/quasar/README.md b/finance/betting-market/quasar/README.md index 7e82be0b2..bf7daf405 100644 --- a/finance/betting-market/quasar/README.md +++ b/finance/betting-market/quasar/README.md @@ -44,7 +44,8 @@ exists. - **Config**, PDA `["config"]`. The single global account. Its `admin` is the only key allowed to create, settle, and cancel events; `token_mint` fixes the - one stake asset; `fee_recipient` and `fee_bps` set the settlement fee. + one stake asset; `fee_recipient` receives the settlement fee, and + `default_fee_bps` is the fee each new event copies at creation. - **Event**, PDA `["event", event_id]`. One market. Holds the running `total_pool`, the status (Open, Settled, Cancelled), a fee snapshot taken at creation, and the winning figures written at settlement. Its PDA is the token @@ -89,8 +90,8 @@ differences follow from Quasar being zero-copy and fixed-layout: - **The pool vault is a program-derived token account** (`["vault", event]`) rather than an associated token account, matching how the other Quasar finance examples (lending, perpetual-futures) hold pool funds. -- **Enums are stored as `u8`** (zero-copy accounts hold POD scalars). `side` and - status values match the Anchor build's byte encodings. +- **Enums are stored as `u8`** (zero-copy accounts hold POD scalars). The + `EventStatus` values match the Anchor build's byte encodings. ## Building and testing diff --git a/finance/betting-market/quasar/src/instructions/claim_refund.rs b/finance/betting-market/quasar/src/instructions/claim_refund.rs index 466daf74c..b5b023814 100644 --- a/finance/betting-market/quasar/src/instructions/claim_refund.rs +++ b/finance/betting-market/quasar/src/instructions/claim_refund.rs @@ -45,9 +45,9 @@ pub fn handle_claim_refund( // Canonical-PDA check for the bet account. The pre-0.1.0 constraint // `address = Bet::seeds(&bet.outcome, ...)` is inexpressible in 0.1.0 // (an Address-typed stored-data seed cannot both feed client codegen and - // typecheck on-chain), and the generated `Bet::find_address` helper is a + // typecheck onchain), and the generated `Bet::find_address` helper is a // const-context/client function whose software SHA-256 exhausts the CU - // budget on-chain. Verifying against the stored bump costs one sha256 + // budget onchain. Verifying against the stored bump costs one sha256 // syscall and rejects non-canonical bet accounts just the same. quasar_lang::pda::verify_program_address( &Bet::seeds(&accounts.bet.outcome, accounts.bettor.address()) diff --git a/finance/betting-market/quasar/src/instructions/claim_winnings.rs b/finance/betting-market/quasar/src/instructions/claim_winnings.rs index d3e994f53..832718f8a 100644 --- a/finance/betting-market/quasar/src/instructions/claim_winnings.rs +++ b/finance/betting-market/quasar/src/instructions/claim_winnings.rs @@ -45,9 +45,9 @@ pub fn handle_claim_winnings( // Canonical-PDA check for the bet account. The pre-0.1.0 constraint // `address = Bet::seeds(&bet.outcome, ...)` is inexpressible in 0.1.0 // (an Address-typed stored-data seed cannot both feed client codegen and - // typecheck on-chain), and the generated `Bet::find_address` helper is a + // typecheck onchain), and the generated `Bet::find_address` helper is a // const-context/client function whose software SHA-256 exhausts the CU - // budget on-chain. Verifying against the stored bump costs one sha256 + // budget onchain. Verifying against the stored bump costs one sha256 // syscall and rejects non-canonical bet accounts just the same. quasar_lang::pda::verify_program_address( &Bet::seeds(&accounts.bet.outcome, accounts.bettor.address()) diff --git a/finance/betting-market/quasar/src/instructions/close_losing_bet.rs b/finance/betting-market/quasar/src/instructions/close_losing_bet.rs index 861838a07..25d32a024 100644 --- a/finance/betting-market/quasar/src/instructions/close_losing_bet.rs +++ b/finance/betting-market/quasar/src/instructions/close_losing_bet.rs @@ -34,9 +34,9 @@ pub fn handle_close_losing_bet( // Canonical-PDA check for the bet account. The pre-0.1.0 constraint // `address = Bet::seeds(&bet.outcome, ...)` is inexpressible in 0.1.0 // (an Address-typed stored-data seed cannot both feed client codegen and - // typecheck on-chain), and the generated `Bet::find_address` helper is a + // typecheck onchain), and the generated `Bet::find_address` helper is a // const-context/client function whose software SHA-256 exhausts the CU - // budget on-chain. Verifying against the stored bump costs one sha256 + // budget onchain. Verifying against the stored bump costs one sha256 // syscall and rejects non-canonical bet accounts just the same. quasar_lang::pda::verify_program_address( &Bet::seeds(&accounts.bet.outcome, accounts.bettor.address()) diff --git a/finance/betting-market/quasar/src/instructions/initialize_config.rs b/finance/betting-market/quasar/src/instructions/initialize_config.rs index 5904d8f3b..a4363ffa8 100644 --- a/finance/betting-market/quasar/src/instructions/initialize_config.rs +++ b/finance/betting-market/quasar/src/instructions/initialize_config.rs @@ -24,17 +24,17 @@ pub struct InitializeConfigAccountConstraints { #[inline(always)] pub fn handle_initialize_config( accounts: &mut InitializeConfigAccountConstraints, - fee_bps: u16, + default_fee_bps: u16, fee_recipient: Address, bumps: &InitializeConfigAccountConstraintsBumps, ) -> Result<(), ProgramError> { - require!(fee_bps <= MAX_FEE_BPS, BettingError::FeeTooHigh); + require!(default_fee_bps <= MAX_FEE_BPS, BettingError::FeeTooHigh); accounts.config.set_inner(ConfigInner { admin: *accounts.admin.address(), token_mint: *accounts.token_mint.address(), fee_recipient, - fee_bps, + default_fee_bps, event_count: 0, bump: bumps.config, }); diff --git a/finance/betting-market/quasar/src/instructions/initialize_event.rs b/finance/betting-market/quasar/src/instructions/initialize_event.rs index 6c2d3d791..726b8388a 100644 --- a/finance/betting-market/quasar/src/instructions/initialize_event.rs +++ b/finance/betting-market/quasar/src/instructions/initialize_event.rs @@ -56,7 +56,7 @@ pub fn handle_initialize_event( let mut description_buffer = [0u8; MAX_DESCRIPTION_LEN]; description_buffer[..description_bytes.len()].copy_from_slice(description_bytes); - let fee_bps = u16::from(accounts.config.fee_bps); + let fee_bps = u16::from(accounts.config.default_fee_bps); accounts.event.set_inner(EventInner { event_id, diff --git a/finance/betting-market/quasar/src/lib.rs b/finance/betting-market/quasar/src/lib.rs index 3fb44204d..519a385e8 100644 --- a/finance/betting-market/quasar/src/lib.rs +++ b/finance/betting-market/quasar/src/lib.rs @@ -22,17 +22,17 @@ mod quasar_betting_market { use super::*; /// One-time setup: the signer becomes the admin and fixes the stake token - /// and the settlement fee (basis points) for every market in this - /// deployment. + /// and the default settlement fee (basis points) that each new market + /// copies at creation. #[instruction(discriminator = 0)] pub fn initialize_config( ctx: Ctx, - fee_bps: u16, + default_fee_bps: u16, fee_recipient: Address, ) -> Result<(), ProgramError> { instructions::initialize_config::handle_initialize_config( &mut ctx.accounts, - fee_bps, + default_fee_bps, fee_recipient, &ctx.bumps, ) diff --git a/finance/betting-market/quasar/src/state/config.rs b/finance/betting-market/quasar/src/state/config.rs index f16884709..d4e915728 100644 --- a/finance/betting-market/quasar/src/state/config.rs +++ b/finance/betting-market/quasar/src/state/config.rs @@ -13,8 +13,10 @@ pub struct Config { pub admin: Address, pub token_mint: Address, pub fee_recipient: Address, - /// Protocol fee, in basis points, taken from the losing pool at settlement. - pub fee_bps: u16, + /// Protocol fee, in basis points, that new events copy into their own + /// `fee_bps` at creation. Settlement charges the event's copy, so changing + /// this value only affects events created afterwards. + pub default_fee_bps: u16, pub event_count: u64, pub bump: u8, } @@ -24,7 +26,7 @@ pub fn snapshot_config(config: &Account) -> ConfigInner { admin: config.admin, token_mint: config.token_mint, fee_recipient: config.fee_recipient, - fee_bps: u16::from(config.fee_bps), + default_fee_bps: u16::from(config.default_fee_bps), event_count: u64::from(config.event_count), bump: config.bump, } diff --git a/finance/betting-market/quasar/src/state/event.rs b/finance/betting-market/quasar/src/state/event.rs index 5b09a3f63..d3a8972e4 100644 --- a/finance/betting-market/quasar/src/state/event.rs +++ b/finance/betting-market/quasar/src/state/event.rs @@ -8,7 +8,7 @@ pub const EVENT_SEED: &[u8] = b"event"; /// mutation (place_bet, settle, cancel) is a plain in-place write. pub const MAX_DESCRIPTION_LEN: usize = 200; -/// Lifecycle of a market. Stored on-chain as a `u8`. +/// Lifecycle of a market. Stored onchain as a `u8`. #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[repr(u8)] pub enum EventStatus { @@ -30,8 +30,9 @@ pub struct Event { /// Sum of every stake placed across all outcomes. pub total_pool: u64, pub status: u8, - /// Fee snapshot taken at creation, so later Config changes can't alter a - /// market bettors have already joined. + /// The fee settlement charges, copied from the config's `default_fee_bps` + /// at creation so later Config changes can't alter a market bettors have + /// already joined. pub fee_bps: u16, /// Written at settlement, read at claim time. pub winning_outcome_index: u8, diff --git a/finance/betting-market/quasar/src/tests.rs b/finance/betting-market/quasar/src/tests.rs index 90ef882d0..ebe22d8c7 100644 --- a/finance/betting-market/quasar/src/tests.rs +++ b/finance/betting-market/quasar/src/tests.rs @@ -1,6 +1,6 @@ //! quasar-test integration tests. They drive the real program instructions //! end-to-end: initialize the config, open an event, add outcomes, place bets, -//! settle, and claim, asserting on-chain state and token balances at each step. +//! settle, and claim, asserting onchain state and token balances at each step. use { crate::{ @@ -39,7 +39,7 @@ fn base_world(test: &mut Test) { test.send(InitializeConfigInstruction { admin: ADMIN, token_mint: TOKEN_MINT, - fee_bps: FEE_BPS, + default_fee_bps: FEE_BPS, fee_recipient: FEE_RECIPIENT, }) .succeeds(); @@ -54,7 +54,7 @@ fn initialize_config_records_admin_mint_and_fee(test: &mut Test) { assert_eq!(state.admin, ADMIN, "admin"); assert_eq!(state.token_mint, TOKEN_MINT, "token_mint"); assert_eq!(state.fee_recipient, FEE_RECIPIENT, "fee_recipient"); - assert_eq!(u16::from(state.fee_bps), FEE_BPS, "fee_bps"); + assert_eq!(u16::from(state.default_fee_bps), FEE_BPS, "default_fee_bps"); } /// Full parimutuel flow: two bettors stake on opposing outcomes, the admin From 374aca39c02b27b327d1e1dba9e2bc6e2c557dda Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 8 Sep 2026 17:16:03 +0000 Subject: [PATCH 2/2] Wrap the initialize_config forwarding call for rustfmt The default_fee_bps rename pushed the one-line call past the width limit in both Anchor builds; CI's Rustfmt check caught the anchor one. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01X78wMd7r7ZMMM4AwbbnpAD --- .../anchor-v1/programs/betting-market/src/lib.rs | 6 +++++- .../anchor/programs/betting-market/src/lib.rs | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/finance/betting-market/anchor-v1/programs/betting-market/src/lib.rs b/finance/betting-market/anchor-v1/programs/betting-market/src/lib.rs index f2a23566e..abf93e169 100644 --- a/finance/betting-market/anchor-v1/programs/betting-market/src/lib.rs +++ b/finance/betting-market/anchor-v1/programs/betting-market/src/lib.rs @@ -21,7 +21,11 @@ pub mod betting_market { default_fee_bps: u16, fee_recipient: Pubkey, ) -> Result<()> { - instructions::initialize_config::handle_initialize_config(context, default_fee_bps, fee_recipient) + instructions::initialize_config::handle_initialize_config( + context, + default_fee_bps, + fee_recipient, + ) } // Admin opens a new market and creates its pool vault. diff --git a/finance/betting-market/anchor/programs/betting-market/src/lib.rs b/finance/betting-market/anchor/programs/betting-market/src/lib.rs index e897cfd5d..bedb55d15 100644 --- a/finance/betting-market/anchor/programs/betting-market/src/lib.rs +++ b/finance/betting-market/anchor/programs/betting-market/src/lib.rs @@ -21,7 +21,11 @@ pub mod betting_market { default_fee_bps: u16, fee_recipient: Address, ) -> Result<()> { - instructions::initialize_config::handle_initialize_config(context, default_fee_bps, fee_recipient) + instructions::initialize_config::handle_initialize_config( + context, + default_fee_bps, + fee_recipient, + ) } // Admin opens a new market and creates its pool vault.