diff --git a/contracts/game_contract/src/lib.rs b/contracts/game_contract/src/lib.rs index c73cfc7..d853fad 100644 --- a/contracts/game_contract/src/lib.rs +++ b/contracts/game_contract/src/lib.rs @@ -104,6 +104,7 @@ const TREASURY: Symbol = symbol_short!("TREASURY"); // i128 treasury reserve const BALANCES: Symbol = symbol_short!("BALANCES"); // Map const USED_NONCE: Symbol = symbol_short!("NONCES"); // Map const MAX_STAKE: Symbol = symbol_short!("MAXSTAKE"); +const MAX_PRIZE_POOL: Symbol = symbol_short!("MAXPOOL"); // Maximum number of proofs accepted by a single claim_puzzle_rewards_batch call. // Keeps per-invocation resource usage (CPU/memory/events) bounded. @@ -230,10 +231,12 @@ pub enum ContractError { EscrowStillLocked = 34, /// Tournament escrow already released (#532) EscrowAlreadyReleased = 35, + /// Total prize pool would exceed the configured limit + PrizePoolLimitExceeded = 36, /// claim_puzzle_rewards_batch called with an empty proof list - EmptyBatch = 36, + EmptyBatch = 37, /// claim_puzzle_rewards_batch called with more proofs than MAX_BATCH_SIZE - BatchTooLarge = 37, + BatchTooLarge = 38, } #[contract] @@ -348,6 +351,18 @@ impl GameContract { return Err(ContractError::StakeLimitExceeded); } + let max_prize_pool: i128 = env + .storage() + .instance() + .get(&MAX_PRIZE_POOL) + .unwrap_or(2_000); + let expected_pool = wager_amount + .checked_mul(2) + .ok_or(ContractError::InvalidAmount)?; + if expected_pool > max_prize_pool { + return Err(ContractError::PrizePoolLimitExceeded); + } + player1.require_auth(); let token_client = Self::token_client(&env); @@ -420,6 +435,19 @@ impl GameContract { return Err(ContractError::StakeLimitExceeded); } + let max_prize_pool: i128 = env + .storage() + .instance() + .get(&MAX_PRIZE_POOL) + .unwrap_or(2_000); + let total_pool = game + .wager_amount + .checked_mul(2) + .ok_or(ContractError::InvalidAmount)?; + if total_pool > max_prize_pool { + return Err(ContractError::PrizePoolLimitExceeded); + } + player2.require_auth(); let token_client = Self::token_client(&env); let contract_address = env.current_contract_address(); @@ -957,6 +985,7 @@ impl GameContract { .instance() .set(&TREASURY_ADDR, &treasury_address); env.storage().instance().set(&MAX_STAKE, &1_000i128); + env.storage().instance().set(&MAX_PRIZE_POOL, &2_000i128); } pub fn set_max_stake(env: Env, admin: Address, new_limit: i128) { @@ -975,6 +1004,22 @@ impl GameContract { env.storage().instance().set(&MAX_STAKE, &new_limit); } + pub fn set_max_prize_pool(env: Env, admin: Address, new_limit: i128) { + let current_admin: Address = env + .storage() + .instance() + .get(&CONTRACT_ADMIN) + .expect("Not initialized"); + current_admin.require_auth(); + if admin != current_admin { + panic!("Unauthorized admin address"); + } + if new_limit <= 0 { + panic!("Max prize pool must be positive"); + } + env.storage().instance().set(&MAX_PRIZE_POOL, &new_limit); + } + pub fn configure_fees(env: Env, admin: Address, fee_bips: u32, treasury_address: Address) { let current_admin: Address = env .storage() diff --git a/contracts/game_contract/test_snapshots/test/test_configure_fees_permissioned.1.json b/contracts/game_contract/test_snapshots/test/test_configure_fees_permissioned.1.json index f191d46..9fe10fc 100644 --- a/contracts/game_contract/test_snapshots/test/test_configure_fees_permissioned.1.json +++ b/contracts/game_contract/test_snapshots/test/test_configure_fees_permissioned.1.json @@ -122,6 +122,17 @@ "u32": 50 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -515,4 +526,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/test/test_payout_with_fee.1.json b/contracts/game_contract/test_snapshots/test/test_payout_with_fee.1.json index 3252f31..5030e00 100644 --- a/contracts/game_contract/test_snapshots/test/test_payout_with_fee.1.json +++ b/contracts/game_contract/test_snapshots/test/test_payout_with_fee.1.json @@ -522,6 +522,17 @@ "u64": 1 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -2287,4 +2298,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/test/test_set_max_stake.1.json b/contracts/game_contract/test_snapshots/test/test_set_max_stake.1.json index 25bb47b..2cbeccc 100644 --- a/contracts/game_contract/test_snapshots/test/test_set_max_stake.1.json +++ b/contracts/game_contract/test_snapshots/test/test_set_max_stake.1.json @@ -427,6 +427,17 @@ "u64": 1 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -1643,4 +1654,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/test/test_set_max_stake_rejects_non_admin.1.json b/contracts/game_contract/test_snapshots/test/test_set_max_stake_rejects_non_admin.1.json index fbe5e41..416651c 100644 --- a/contracts/game_contract/test_snapshots/test/test_set_max_stake_rejects_non_admin.1.json +++ b/contracts/game_contract/test_snapshots/test/test_set_max_stake_rejects_non_admin.1.json @@ -97,6 +97,17 @@ "u32": 0 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -400,4 +411,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_claim_puzzle_reward_invalid_amount_rejected.1.json b/contracts/game_contract/test_snapshots/tests/test_claim_puzzle_reward_invalid_amount_rejected.1.json index e9ac5bd..1b9acd3 100644 --- a/contracts/game_contract/test_snapshots/tests/test_claim_puzzle_reward_invalid_amount_rejected.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_claim_puzzle_reward_invalid_amount_rejected.1.json @@ -97,6 +97,17 @@ "u32": 0 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -404,4 +415,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_claim_puzzle_reward_invalid_sig.1.json b/contracts/game_contract/test_snapshots/tests/test_claim_puzzle_reward_invalid_sig.1.json index 81d395d..c74e90a 100644 --- a/contracts/game_contract/test_snapshots/tests/test_claim_puzzle_reward_invalid_sig.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_claim_puzzle_reward_invalid_sig.1.json @@ -97,6 +97,17 @@ "u32": 0 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -454,4 +465,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_claim_puzzle_reward_replay_rejected.1.json b/contracts/game_contract/test_snapshots/tests/test_claim_puzzle_reward_replay_rejected.1.json index 1a7119c..9491f95 100644 --- a/contracts/game_contract/test_snapshots/tests/test_claim_puzzle_reward_replay_rejected.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_claim_puzzle_reward_replay_rejected.1.json @@ -118,6 +118,17 @@ "u32": 0 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -531,4 +542,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_claim_puzzle_reward_valid_sig.1.json b/contracts/game_contract/test_snapshots/tests/test_claim_puzzle_reward_valid_sig.1.json index b0b1fef..7a82492 100644 --- a/contracts/game_contract/test_snapshots/tests/test_claim_puzzle_reward_valid_sig.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_claim_puzzle_reward_valid_sig.1.json @@ -119,6 +119,17 @@ "u32": 0 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -491,4 +502,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_claim_timeout_win_not_reached.1.json b/contracts/game_contract/test_snapshots/tests/test_claim_timeout_win_not_reached.1.json index 6760fde..7f41b68 100644 --- a/contracts/game_contract/test_snapshots/tests/test_claim_timeout_win_not_reached.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_claim_timeout_win_not_reached.1.json @@ -797,6 +797,17 @@ "u64": 1 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -2264,4 +2275,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_claim_timeout_win_rejects_current_turn_player.1.json b/contracts/game_contract/test_snapshots/tests/test_claim_timeout_win_rejects_current_turn_player.1.json index d12ca80..e398edc 100644 --- a/contracts/game_contract/test_snapshots/tests/test_claim_timeout_win_rejects_current_turn_player.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_claim_timeout_win_rejects_current_turn_player.1.json @@ -798,6 +798,17 @@ "u64": 1 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -2265,4 +2276,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_claim_timeout_win_success.1.json b/contracts/game_contract/test_snapshots/tests/test_claim_timeout_win_success.1.json index 839b6aa..001077d 100644 --- a/contracts/game_contract/test_snapshots/tests/test_claim_timeout_win_success.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_claim_timeout_win_success.1.json @@ -855,6 +855,17 @@ "u64": 1 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -2425,4 +2436,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_configure_timeout.1.json b/contracts/game_contract/test_snapshots/tests/test_configure_timeout.1.json index d10ac8c..298d4f9 100644 --- a/contracts/game_contract/test_snapshots/tests/test_configure_timeout.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_configure_timeout.1.json @@ -118,6 +118,17 @@ "u32": 0 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -377,4 +388,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_fee_redirection_2_percent.1.json b/contracts/game_contract/test_snapshots/tests/test_fee_redirection_2_percent.1.json index 05dd196..fe88d1f 100644 --- a/contracts/game_contract/test_snapshots/tests/test_fee_redirection_2_percent.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_fee_redirection_2_percent.1.json @@ -742,6 +742,17 @@ "u64": 1 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -2215,4 +2226,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_fee_redirection_2_percent_large.1.json b/contracts/game_contract/test_snapshots/tests/test_fee_redirection_2_percent_large.1.json index 7ca0e99..c5ac58d 100644 --- a/contracts/game_contract/test_snapshots/tests/test_fee_redirection_2_percent_large.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_fee_redirection_2_percent_large.1.json @@ -811,6 +811,17 @@ "u64": 1 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -2506,4 +2517,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_file_dispute_rejects_settled_games.1.json b/contracts/game_contract/test_snapshots/tests/test_file_dispute_rejects_settled_games.1.json index 7948d91..f1b666a 100644 --- a/contracts/game_contract/test_snapshots/tests/test_file_dispute_rejects_settled_games.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_file_dispute_rejects_settled_games.1.json @@ -879,6 +879,17 @@ "u64": 1 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -2502,4 +2513,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_file_dispute_success.1.json b/contracts/game_contract/test_snapshots/tests/test_file_dispute_success.1.json index 8c8c825..bb14b46 100644 --- a/contracts/game_contract/test_snapshots/tests/test_file_dispute_success.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_file_dispute_success.1.json @@ -1000,6 +1000,17 @@ "u64": 1 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -2744,4 +2755,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_get_timeout_remaining.1.json b/contracts/game_contract/test_snapshots/tests/test_get_timeout_remaining.1.json index 5311273..9fe3e1f 100644 --- a/contracts/game_contract/test_snapshots/tests/test_get_timeout_remaining.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_get_timeout_remaining.1.json @@ -799,6 +799,17 @@ "u64": 1 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -2288,4 +2299,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_payout_cannot_be_called_twice.1.json b/contracts/game_contract/test_snapshots/tests/test_payout_cannot_be_called_twice.1.json index 0f43ce5..299bfa1 100644 --- a/contracts/game_contract/test_snapshots/tests/test_payout_cannot_be_called_twice.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_payout_cannot_be_called_twice.1.json @@ -511,6 +511,17 @@ "u64": 1 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -2236,4 +2247,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_payout_tournament_optimized_splits_correctly.1.json b/contracts/game_contract/test_snapshots/tests/test_payout_tournament_optimized_splits_correctly.1.json index d7f40d8..563517e 100644 --- a/contracts/game_contract/test_snapshots/tests/test_payout_tournament_optimized_splits_correctly.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_payout_tournament_optimized_splits_correctly.1.json @@ -816,6 +816,17 @@ "u64": 1 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -2455,4 +2466,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_reject_dispute_refund_fee.1.json b/contracts/game_contract/test_snapshots/tests/test_reject_dispute_refund_fee.1.json index 2df88a2..f4e1229 100644 --- a/contracts/game_contract/test_snapshots/tests/test_reject_dispute_refund_fee.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_reject_dispute_refund_fee.1.json @@ -1060,6 +1060,17 @@ "u64": 1 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -2985,4 +2996,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_resolve_dispute_rejects_already_settled_games.1.json b/contracts/game_contract/test_snapshots/tests/test_resolve_dispute_rejects_already_settled_games.1.json index baea9f2..3db9299 100644 --- a/contracts/game_contract/test_snapshots/tests/test_resolve_dispute_rejects_already_settled_games.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_resolve_dispute_rejects_already_settled_games.1.json @@ -1032,6 +1032,17 @@ "u64": 1 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -2747,4 +2758,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_resolve_dispute_winner_takes_all.1.json b/contracts/game_contract/test_snapshots/tests/test_resolve_dispute_winner_takes_all.1.json index 1fab106..085240a 100644 --- a/contracts/game_contract/test_snapshots/tests/test_resolve_dispute_winner_takes_all.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_resolve_dispute_winner_takes_all.1.json @@ -1041,6 +1041,17 @@ "u64": 1 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -2825,4 +2836,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_submit_move_rejects_out_of_turn_and_empty_moves.1.json b/contracts/game_contract/test_snapshots/tests/test_submit_move_rejects_out_of_turn_and_empty_moves.1.json index 141b3a0..35b4b97 100644 --- a/contracts/game_contract/test_snapshots/tests/test_submit_move_rejects_out_of_turn_and_empty_moves.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_submit_move_rejects_out_of_turn_and_empty_moves.1.json @@ -743,6 +743,17 @@ "u64": 1 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -2299,4 +2310,4 @@ "failed_call": false } ] -} \ No newline at end of file +} diff --git a/contracts/game_contract/test_snapshots/tests/test_submit_move_sequence_updates_turn_and_history.1.json b/contracts/game_contract/test_snapshots/tests/test_submit_move_sequence_updates_turn_and_history.1.json index cc1864a..6727215 100644 --- a/contracts/game_contract/test_snapshots/tests/test_submit_move_sequence_updates_turn_and_history.1.json +++ b/contracts/game_contract/test_snapshots/tests/test_submit_move_sequence_updates_turn_and_history.1.json @@ -943,6 +943,17 @@ "u64": 1 } }, + { + "key": { + "symbol": "MAXPOOL" + }, + "val": { + "i128": { + "hi": 0, + "lo": 2000 + } + } + }, { "key": { "symbol": "MAXSTAKE" @@ -2557,4 +2568,4 @@ "failed_call": false } ] -} \ No newline at end of file +}