Bootstrap

Solidity合约编写(五)

解决问题

编写 FundMe.sol 一个众筹合约,允许用户向合约转账 ETH,并记录每个地址的转账金额。同时,合约还要求每次转账至少为 1 ETH,否则交易失败。最后,合约管理员可以提取资金,并使用 call 函数发送 ETH。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// 导入 PriceConverter 库
import "./PriceConverter.sol";

contract FundMe {
    using PriceConverter for uint256;

    // 最小转账金额:1 ETH
    uint256 public constant MINIMUM_USD = 1 * 1e18; // 1 ETH in wei

    // 记录每个地址的转账金额
    mapping(address => uint256) public addressToAmountFunded;

    // 记录所有参与者的地址
    address[] public funders;

    // 合约管理员地址
    address public immutable owner;

    // Chainlink 价格喂价合约地址
    AggregatorV3Interface public priceFeed;

    // 构造函数:设置管理员和价格喂价合约地址
    constructor(address _priceFeedAddress) {
        owner = msg.sender;
        priceFeed = AggregatorV3Interface(_priceFeedAddress);
    }

    // 接收 ETH 的函数
    function fund() public payable {
        // 检查转账金额是否大于等于 1 ETH
        require(
            msg.value.getConversionRate(priceFeed) >= MINIMUM_USD,
            "You need to spend at least 1 ETH!"
        );

        // 记录转账金额
        addressToAmountFunded[msg.sender] += msg.value;

        // 记录参与者地址
        funders.push(msg.sender);
    }

    // 提取合约中的所有资金(仅管理员可调用)
    function withdraw() public onlyOwner {
        // 重置所有参与者的转账金额
        for (uint256 i = 0; i < funders.length; i++) {
            address funder = funders[i];
            addressToAmountFunded[funder] = 0;
        }

        // 清空参与者列表
        funders = new address[](0);

        // 使用 call 发送合约中的所有 ETH 给管理员
        (bool success, ) = payable(owner).call{value: address(this).balance}("");
        require(success, "Transfer failed.");
    }

    // 修改器:仅允许管理员调用
    modifier onlyOwner() {
        require(msg.sender == owner, "Only the owner can call this function!");
        _;
    }

    // 回退函数:允许合约直接接收 ETH
    receive() external payable {
        fund();
    }

    // 回退函数:允许合约直接接收 ETH
    fallback() external payable {
        fund();
    }
}

代码说明

  1. priceFeed:Chainlink 价格喂价合约地址,用于将 ETH 转换为 USD。

  2. fund 函数

    • 接收用户转账的 ETH。

    • 使用 require 检查转账金额是否大于等于 1 ETH。

    • 记录转账金额和参与者地址。

  3. withdraw 函数

    • 仅管理员可调用。

    • 使用 for 循环重置所有参与者的转账金额。

    • 清空参与者列表。

    • 使用 call 发送合约中的所有 ETH 给管理员。

  4. onlyOwner 修改器:限制只有管理员可以调用 withdraw 函数。

  5. 回退函数receive 和 fallback 函数允许合约直接接收 ETH,并自动调用 fund 函数。

;