From bc11534721b74c9a9732da5aa3eb82fb2b39d4d6 Mon Sep 17 00:00:00 2001 From: syahirAmali Date: Sun, 27 Oct 2024 00:56:01 +0800 Subject: [PATCH 1/3] forge install: forge-std v1.9.4 --- lib/forge-std | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/forge-std b/lib/forge-std index 8f24d6b..1eea5ba 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit 8f24d6b04c92975e0795b5868aa0d783251cdeaa +Subproject commit 1eea5bae12ae557d589f9f0f0edae2faa47cb262 From 9a0ab2963a94ae1a9a6e24c6a1676d0b2f9d915e Mon Sep 17 00:00:00 2001 From: syahirAmali Date: Sun, 27 Oct 2024 02:21:42 +0800 Subject: [PATCH 2/3] Added events --- src/RaidGeld.sol | 79 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 10 deletions(-) diff --git a/src/RaidGeld.sol b/src/RaidGeld.sol index 361d645..5bb3e75 100644 --- a/src/RaidGeld.sol +++ b/src/RaidGeld.sol @@ -15,6 +15,25 @@ contract RaidGeld is ERC20, Ownable { mapping(address => Player) private players; mapping(address => Army) private armies; + // Events + event PlayerRegistered(address indexed player, uint256 initialGeld); + event RaidPerformed( + address indexed player, + uint256 totalMinted, + uint256 geldBalance + ); + event UnitAdded( + address indexed player, + uint8 unitType, + uint16 nUnits, + uint256 cost, + uint256 geldBalance, + uint16 molochDenierLevel, + uint16 apprenticeLevel, + uint16 anointedLevel, + uint16 championLevel + ); + // Modifier for functions that should only be available to registered players modifier onlyPlayer() { require(players[msg.sender].created_at != 0, "Not an initiated player"); @@ -25,15 +44,21 @@ contract RaidGeld is ERC20, Ownable { // This effectively registers the user function register() external payable { - require(players[msg.sender].created_at == 0, "Whoops, player already exists :)"); + require( + players[msg.sender].created_at == 0, + "Whoops, player already exists :)" + ); require(msg.value == BUY_IN_AMOUNT, "Incorrect buy in amount"); // Mint some starting tokens to the player _mint(msg.sender, INITIAL_GELD); // Set initial states - players[msg.sender] = - Player({total_minted: INITIAL_GELD, created_at: block.timestamp, last_raided_at: block.timestamp}); + players[msg.sender] = Player({ + total_minted: INITIAL_GELD, + created_at: block.timestamp, + last_raided_at: block.timestamp + }); armies[msg.sender] = Army({ moloch_denier: Raider({level: 0}), apprentice: Raider({level: 0}), @@ -41,6 +66,9 @@ contract RaidGeld is ERC20, Ownable { champion: Raider({level: 0}), profit_per_second: 0 }); + + // Emit event + emit PlayerRegistered(msg.sender, INITIAL_GELD); } // Override for default number of decimals @@ -55,11 +83,14 @@ contract RaidGeld is ERC20, Ownable { // Manual minting for itchy fingers function raid() external onlyPlayer { - performRaid(msg.sender); + uint256 totalMinted = performRaid(msg.sender); + + // Emit event + emit RaidPerformed(msg.sender, totalMinted, balanceOf(msg.sender)); } // Helper so we can use it when buying units too - function performRaid(address player) private { + function performRaid(address player) private returns (uint256) { uint256 time_past = block.timestamp - players[player].last_raided_at; uint256 new_geld = armies[player].profit_per_second * time_past; @@ -68,6 +99,8 @@ contract RaidGeld is ERC20, Ownable { _mint(player, new_geld); players[player].last_raided_at = block.timestamp; players[player].total_minted += new_geld; + + return players[player].total_minted; } // Function to get Player struct @@ -105,13 +138,24 @@ contract RaidGeld is ERC20, Ownable { currentLevel = army.champion.level; } - uint256 cost = RaidGeldUtils.calculateUnitPrice(unit, currentLevel, n_units); + uint256 cost = RaidGeldUtils.calculateUnitPrice( + unit, + currentLevel, + n_units + ); // First trigger a raid so player receives what he is due at to this moment - uint256 time_past = block.timestamp - players[msg.sender].last_raided_at; + uint256 time_past = block.timestamp - + players[msg.sender].last_raided_at; uint256 new_geld = armies[msg.sender].profit_per_second * time_past; - require(balanceOf(msg.sender) + new_geld > cost, "Not enough GELD to add this unit"); - performRaid(msg.sender); + require( + balanceOf(msg.sender) + new_geld >= cost, + "Not enough GELD to add this unit" + ); + uint256 totalMinted = performRaid(msg.sender); + + // Emit event + emit RaidPerformed(msg.sender, totalMinted, balanceOf(msg.sender)); // TODO: Since we are first minting then burning the token, this could be simplified // by first calculating the difference and then minting / burning in just one operation @@ -136,10 +180,25 @@ contract RaidGeld is ERC20, Ownable { // update profite per second army.profit_per_second = RaidGeldUtils.calculateProfitsPerSecond(army); + + // Emit event + emit UnitAdded( + msg.sender, + unit, + n_units, + cost, + balanceOf(msg.sender), + army.moloch_denier.level, + army.apprentice.level, + army.anointed.level, + army.champion.level + ); } receive() external payable { - revert("No plain Ether accepted, use register() function to check in :)"); + revert( + "No plain Ether accepted, use register() function to check in :)" + ); } // Revert any non-function-call Ether transfers or calls to non-existent functions From 0b1499a1228c2c0ae1eb6242953218eb164df920 Mon Sep 17 00:00:00 2001 From: syahirAmali Date: Tue, 29 Oct 2024 03:03:59 +0800 Subject: [PATCH 3/3] Events test added --- test/RaidGeld.t.sol | 115 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 3 deletions(-) diff --git a/test/RaidGeld.t.sol b/test/RaidGeld.t.sol index 378e289..b741884 100644 --- a/test/RaidGeld.t.sol +++ b/test/RaidGeld.t.sol @@ -11,6 +11,24 @@ contract raid_geldTest is Test { address public player2; address public owner; + event PlayerRegistered(address indexed player, uint256 initialGeld); + event RaidPerformed( + address indexed player, + uint256 totalMinted, + uint256 geldBalance + ); + event UnitAdded( + address indexed player, + uint8 unitType, + uint16 nUnits, + uint256 cost, + uint256 geldBalance, + uint16 molochDenierLevel, + uint16 apprenticeLevel, + uint16 anointedLevel, + uint16 championLevel + ); + function setUp() public { owner = address(0x126); player1 = address(0x123); @@ -27,7 +45,7 @@ contract raid_geldTest is Test { function test_00_no_fallback() public { vm.expectRevert(); // Send Ether with some data to trigger fallback - (bool success,) = address(raid_geld).call{value: 0.1 ether}("0x1234"); + (bool success, ) = address(raid_geld).call{value: 0.1 ether}("0x1234"); } function test_01_no_receive() public { @@ -41,6 +59,11 @@ contract raid_geldTest is Test { uint256 initialBalance = address(raid_geld).balance; + // Making sure event is emitted when player is registered + vm.expectEmit(address(raid_geld)); + + emit PlayerRegistered(player1, raid_geld.INITIAL_GELD()); + // Send registration fee ETH to the contract registerPlayer(); @@ -48,7 +71,10 @@ contract raid_geldTest is Test { assertEq(raid_geld.balanceOf(player1), raid_geld.INITIAL_GELD()); // Verify the contract balance is updated - assertEq(address(raid_geld).balance, initialBalance + raid_geld.BUY_IN_AMOUNT()); + assertEq( + address(raid_geld).balance, + initialBalance + raid_geld.BUY_IN_AMOUNT() + ); // Verify player is set initially Player memory player = raid_geld.getPlayer(player1); @@ -69,6 +95,12 @@ contract raid_geldTest is Test { // Switch to Player 1 and register it vm.startPrank(player1); + + // Making sure event is emitted when player is registered + vm.expectEmit(address(raid_geld)); + + emit PlayerRegistered(player1, raid_geld.INITIAL_GELD()); + registerPlayer(); // Switch back to owner and withdraw funds @@ -86,6 +118,12 @@ contract raid_geldTest is Test { function test_04_only_owner_can_withdraw() public { // Register player 1 vm.startPrank(player1); + + // Making sure event is emitted when player is registered + vm.expectEmit(address(raid_geld)); + + emit PlayerRegistered(player1, raid_geld.INITIAL_GELD()); + registerPlayer(); // attempt to withdraw with player 1, it should fail @@ -97,6 +135,12 @@ contract raid_geldTest is Test { bool is_registered = raid_geld.isRegistered(player1); assertEq(is_registered, false); vm.startPrank(player1); + + // Making sure event is emitted when player is registered + vm.expectEmit(address(raid_geld)); + + emit PlayerRegistered(player1, raid_geld.INITIAL_GELD()); + registerPlayer(); is_registered = raid_geld.isRegistered(player1); assertEq(is_registered, true); @@ -104,6 +148,12 @@ contract raid_geldTest is Test { function test_06_add_unit() public { vm.startPrank(player1); + + // Making sure event is emitted when player is registered + vm.expectEmit(address(raid_geld)); + + emit PlayerRegistered(player1, raid_geld.INITIAL_GELD()); + registerPlayer(); vm.expectRevert(); @@ -118,6 +168,25 @@ contract raid_geldTest is Test { uint256 unit_level = army.moloch_denier.level; uint256 balance = raid_geld.balanceOf(player1); uint256 income_per_sec = army.profit_per_second; + + uint256 cost = RaidGeldUtils.calculateUnitPrice(0, 0, 1); + uint256 playerBalance = raid_geld.balanceOf(address(player1)); + + // Making sure event is emitted when player adds a unit + vm.expectEmit(address(raid_geld)); + + emit UnitAdded( + address(player1), + 0, + 1, + cost, + playerBalance - cost, + 1, + 0, + 0, + 0 + ); + // Add 1 unit raid_geld.addUnit(0, 1); uint256 unitPrice = RaidGeldUtils.calculateUnitPrice(0, 0, 1); @@ -146,23 +215,63 @@ contract raid_geldTest is Test { vm.startPrank(player1); registerPlayer(); + uint256 cost = RaidGeldUtils.calculateUnitPrice(0, 0, 1); + uint256 playerBalance = raid_geld.balanceOf(address(player1)); + + // Making sure event is emitted when player adds a unit + vm.expectEmit(address(raid_geld)); + + emit UnitAdded( + address(player1), + 0, + 1, + cost, + playerBalance - cost, + 1, + 0, + 0, + 0 + ); + // bought 1 moloch_denier raid_geld.addUnit(0, 1); vm.warp(block.timestamp + 15); uint256 balance = raid_geld.balanceOf(player1); + Army memory army = raid_geld.getArmy(player1); + Player memory player = raid_geld.getPlayer(player1); + + uint256 amountMinted = army.profit_per_second * 15; + + // Making sure event is emitted when player performs a raid + vm.expectEmit(address(raid_geld)); + + emit RaidPerformed( + address(player1), + player.total_minted + amountMinted, + balance + amountMinted + ); // Trigger raid funds minting raid_geld.raid(); // New balance should be larger uint256 newBalance = raid_geld.balanceOf(player1); - Player memory player = raid_geld.getPlayer(player1); + player = raid_geld.getPlayer(player1); uint256 last_raided_at = player.last_raided_at; assertLt(balance, newBalance); // After wait time passes raid should bring in profits again vm.warp(block.timestamp + 15); + + amountMinted = army.profit_per_second * 15; + + emit RaidPerformed( + address(player1), + player.total_minted + amountMinted, + balance + amountMinted + ); + raid_geld.raid(); // Balance should reflect that