@@ -3,17 +3,19 @@ pragma solidity 0.8.26;
33
44import "@openzeppelin/contracts/utils/ReentrancyGuard.sol " ;
55import "@openzeppelin/contracts/access/Ownable.sol " ;
6+ import "@openzeppelin/contracts/utils/Pausable.sol " ;
67
7- contract AgentTrumpGame is ReentrancyGuard , Ownable {
8+ contract AgentTrumpGame is ReentrancyGuard , Ownable , Pausable {
89 uint256 public gameEndBlock;
910 uint256 public escalationStartBlock;
1011 uint256 public lastGuessBlock;
1112
12- uint256 public constant BLOCKS_PER_MINUTE = 4 ;
13- uint256 public constant INITIAL_GAME_DURATION = 20 * BLOCKS_PER_MINUTE;
13+ uint256 public constant BLOCKS_PER_MINUTE = 30 ;
14+ uint256 public constant INITIAL_GAME_DURATION = 4320 * BLOCKS_PER_MINUTE;
1415 uint256 public constant ESCALATION_PERIOD = 5 * BLOCKS_PER_MINUTE;
1516 uint256 public constant BASE_MULTIPLIER = 200 ;
16- uint256 public constant GAME_FEE = 0.0009 ether ;
17+ uint256 public constant GAME_FEE = 0.009 ether ;
18+ uint256 public constant MAX_RESPONSE_LENGTH = 2000 ;
1719
1820 uint256 public currentMultiplier;
1921 uint256 public totalCollected;
@@ -35,6 +37,9 @@ contract AgentTrumpGame is ReentrancyGuard, Ownable {
3537 event GameEnded (address indexed lastPlayer , uint256 lastPlayerReward , uint256 ownerReward );
3638 event EscalationStarted (uint256 startBlock );
3739 event GameExtended (uint256 newEndBlock , uint256 newMultiplier );
40+ event Deposited (address indexed owner , uint256 amount );
41+ event Withdrawn (address indexed owner , uint256 amount );
42+ event EmergencyWithdrawn (address indexed owner , uint256 amount );
3843
3944 constructor () Ownable (msg .sender ) {
4045 gameEndBlock = block .number + INITIAL_GAME_DURATION;
@@ -43,7 +48,34 @@ contract AgentTrumpGame is ReentrancyGuard, Ownable {
4348 currentRequiredAmount = GAME_FEE;
4449 }
4550
46- function endGame () external onlyOwner nonReentrant {
51+ modifier validResponse (string calldata response ) {
52+ require (bytes (response).length > 0 , "Response cannot be empty " );
53+ require (bytes (response).length <= MAX_RESPONSE_LENGTH, "Response too long " );
54+ require (_isValidString (response), "Response contains invalid characters " );
55+ _;
56+ }
57+
58+ function _isValidString (string calldata str ) internal pure returns (bool ) {
59+ bytes memory b = bytes (str);
60+ for (uint i; i < b.length ; i++ ) {
61+ bytes1 char = b[i];
62+ // Allow alphanumeric, spaces, and basic punctuation
63+ if (! (char >= 0x20 && char <= 0x7E )) {
64+ return false ;
65+ }
66+ }
67+ return true ;
68+ }
69+
70+ function pause () external onlyOwner {
71+ _pause ();
72+ }
73+
74+ function unpause () external onlyOwner {
75+ _unpause ();
76+ }
77+
78+ function endGame () external onlyOwner nonReentrant whenNotPaused {
4779 require (totalCollected > 0 , "No funds to distribute " );
4880 require (lastPlayer != address (0 ), "No players participated " );
4981
@@ -74,13 +106,32 @@ contract AgentTrumpGame is ReentrancyGuard, Ownable {
74106 emit GameEnded (paymentReceiver, lastPlayerReward, ownerReward);
75107 }
76108
77- function withdraw () external onlyOwner {
109+ function withdraw () external onlyOwner whenNotPaused {
78110 require (address (this ).balance > 0 , "No balance to withdraw " );
79111 require (totalCollected == 0 , "Must call endGame first to distribute rewards " );
80-
81- (bool success , ) = payable (owner ()).call {value: address (this ).balance}("" );
112+
113+ uint256 amount = address (this ).balance;
114+
115+ // Emit event before external call
116+ emit Withdrawn (owner (), amount);
117+
118+ // Make external call last
119+ (bool success , ) = payable (owner ()).call {value: amount}("" );
82120 require (success, "Withdraw failed " );
83121 }
122+
123+ function emergencyWithdraw () external onlyOwner whenPaused {
124+ require (address (this ).balance > 0 , "No balance to withdraw " );
125+
126+ uint256 amount = address (this ).balance;
127+
128+ // Emit event before external call
129+ emit EmergencyWithdrawn (owner (), amount);
130+
131+ // Make external call last
132+ (bool success , ) = payable (owner ()).call {value: amount}("" );
133+ require (success, "Emergency withdraw failed " );
134+ }
84135
85136 function getCurrentRequiredAmount () public view returns (uint256 ) {
86137 if (! escalationActive) return GAME_FEE;
@@ -98,17 +149,16 @@ contract AgentTrumpGame is ReentrancyGuard, Ownable {
98149 (block .number - lastGuessBlock) <= ESCALATION_PERIOD;
99150 }
100151
101- function submitGuess (string calldata response ) external payable nonReentrant {
152+ function submitGuess (string calldata response ) external payable nonReentrant whenNotPaused validResponse (response) {
102153 require (! gameWon, "Game already won " );
103- require (bytes (response).length > 0 , "Response cannot be empty " );
104- require (bytes (response).length <= 1000 , "Response too long " );
105154
106155 uint256 requiredAmount = getCurrentRequiredAmount ();
107156 require (msg .value >= requiredAmount, "Insufficient payment " );
108157
109158 if (shouldStartEscalation ()) {
110159 escalationActive = true ;
111160 escalationStartBlock = block .number ;
161+ currentMultiplier = BASE_MULTIPLIER; // Add this line
112162 currentRequiredAmount = GAME_FEE * BASE_MULTIPLIER / 100 ;
113163 emit EscalationStarted (escalationStartBlock);
114164 }
@@ -185,10 +235,11 @@ contract AgentTrumpGame is ReentrancyGuard, Ownable {
185235 return (responses, timestamps, exists);
186236 }
187237
188- function buttonPushed (address winner ) external onlyOwner nonReentrant {
238+ function buttonPushed (address winner ) external onlyOwner nonReentrant whenNotPaused {
189239 require (! gameWon, "Game already won " );
190240 require (winner != address (0 ), "Invalid winner address " );
191241 require (playerResponses[winner].length > 0 , "Winner must have submitted at least one response " );
242+ require (payable (winner).code.length == 0 , "Winner cannot be a contract " );
192243
193244 gameWon = true ;
194245 uint256 reward = totalCollected;
@@ -203,7 +254,7 @@ contract AgentTrumpGame is ReentrancyGuard, Ownable {
203254 function getTimeRemaining () public view returns (uint256 ) {
204255 if (block .number >= gameEndBlock) return 0 ;
205256 // Convert blocks to seconds (approximate)
206- return (gameEndBlock - block .number ) * 15 ;
257+ return (gameEndBlock - block .number ) * 2 ;
207258 }
208259
209260 function getContractBalance () public view returns (uint256 ) {
@@ -215,8 +266,9 @@ contract AgentTrumpGame is ReentrancyGuard, Ownable {
215266 return (block .number - escalationStartBlock) / ESCALATION_PERIOD;
216267 }
217268
218- function deposit () external payable onlyOwner {
269+ function deposit () external payable onlyOwner whenNotPaused {
219270 require (msg .value > 0 , "Must deposit some ETH " );
271+ emit Deposited (msg .sender , msg .value );
220272 }
221273
222274 receive () external payable {}
0 commit comments