解决问题
编写 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();
}
}
代码说明
-
priceFeed
:Chainlink 价格喂价合约地址,用于将 ETH 转换为 USD。 -
fund
函数:-
接收用户转账的 ETH。
-
使用
require
检查转账金额是否大于等于 1 ETH。 -
记录转账金额和参与者地址。
-
-
withdraw
函数:-
仅管理员可调用。
-
使用
for
循环重置所有参与者的转账金额。 -
清空参与者列表。
-
使用
call
发送合约中的所有 ETH 给管理员。
-
-
onlyOwner
修改器:限制只有管理员可以调用withdraw
函数。 -
回退函数:
receive
和fallback
函数允许合约直接接收 ETH,并自动调用fund
函数。