Skip to content

Commit 39bb212

Browse files
authored
Update AgentTrumpGame.sol
1. Replaced Unix-based timestamp with block.number for better precision. 2. Added Pause, Unpause, and Emergency Withdrawal functions for smart contract remediations in case of an emergency or hack. Signed-off-by: Pavon Dunbar <36899956+pavondunbar@users.noreply.github.com>
1 parent 4061996 commit 39bb212

File tree

1 file changed

+66
-14
lines changed

1 file changed

+66
-14
lines changed

src/AgentTrumpGame.sol

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,19 @@ pragma solidity 0.8.26;
33

44
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
55
import "@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

Comments
 (0)