add Fund Me Foundry Smart Contract

This commit is contained in:
han
2024-12-18 18:15:59 +07:00
parent e87bce6d80
commit 517ff0c9c9
18 changed files with 617 additions and 57 deletions

View File

@@ -1,14 +0,0 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
contract Counter {
uint256 public number;
function setNumber(uint256 newNumber) public {
number = newNumber;
}
function increment() public {
number++;
}
}

123
fund-me/src/FundMe.sol Normal file
View File

@@ -0,0 +1,123 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
// Note: The AggregatorV3Interface might be at a different location than what was in the video!
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
import {PriceConverter} from "./PriceConverter.sol";
error NotOwner();
contract FundMe {
using PriceConverter for uint256;
// private is more gas efficient compared to public
mapping(address => uint256) private s_addressToAmountFunded;
address[] private s_funders;
// Could we make this constant? /* hint: no! We should make it immutable! */
address private /* immutable */ i_owner;
uint256 public constant MINIMUM_USD = 5 * 10 ** 18;
AggregatorV3Interface private s_priceFeed;
constructor(address priceFeed) {
i_owner = msg.sender;
s_priceFeed = AggregatorV3Interface(priceFeed);
}
function fund() public payable {
require(msg.value.getConversionRate(s_priceFeed) >= MINIMUM_USD, "You need to spend more ETH!");
// require(PriceConverter.getConversionRate(msg.value) >= MINIMUM_USD, "You need to spend more ETH!");
s_addressToAmountFunded[msg.sender] += msg.value;
s_funders.push(msg.sender);
}
function getVersion() public view returns (uint256) {
return s_priceFeed.version();
}
modifier onlyOwner() {
// require(msg.sender == owner);
if (msg.sender != i_owner) revert NotOwner();
_;
}
function withdraw() public onlyOwner {
for (uint256 funderIndex = 0; funderIndex < s_funders.length; funderIndex++) {
address funder = s_funders[funderIndex];
s_addressToAmountFunded[funder] = 0;
}
s_funders = new address[](0);
// // transfer
// payable(msg.sender).transfer(address(this).balance);
// // send
// bool sendSuccess = payable(msg.sender).send(address(this).balance);
// require(sendSuccess, "Send failed");
// call
(bool callSuccess,) = payable(msg.sender).call{value: address(this).balance}("");
require(callSuccess, "Call failed");
}
function cheaperWithdraw() public onlyOwner {
uint256 fundersLength = s_funders.length;
for (uint256 funderIndex = 0; funderIndex < fundersLength; funderIndex++) {
address funder = s_funders[funderIndex];
s_addressToAmountFunded[funder] = 0;
}
s_funders = new address[](0);
(bool callSuccess,) = payable(msg.sender).call{value: address(this).balance}("");
require(callSuccess, "Call failed");
}
// Explainer from: https://solidity-by-example.org/fallback/
// Ether is sent to contract
// is msg.data empty?
// / \
// yes no
// / \
// receive()? fallback()
// / \
// yes no
// / \
//receive() fallback()
fallback() external payable {
fund();
}
receive() external payable {
fund();
}
/**
* View / Pure Functions (Getters)
*/
function getAddressToAmountFunded(
address fundingAddress
) external view returns (uint256) {
return s_addressToAmountFunded[fundingAddress];
}
function getFunder(uint256 funderIndex) external view returns (address) {
return s_funders[funderIndex];
}
function getOwner() external view returns (address) {
return i_owner;
}
function getPriceFeed() external view returns (AggregatorV3Interface) {
return s_priceFeed;
}
}
// Concepts we didn't cover yet (will cover in later sections)
// 1. Enum
// 2. Events
// 3. Try / Catch
// 4. Function Selector
// 5. abi.encode / decode
// 6. Hash with keccak256
// 7. Yul / Assembly

View File

@@ -0,0 +1,28 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
// Why is this a library and not abstract?
// Why not an interface?
library PriceConverter {
// We could make this public, but then we'd have to deploy it
function getPrice(AggregatorV3Interface priceFeed) internal view returns (uint256) {
// Sepolia ETH / USD Address
// https://docs.chain.link/data-feeds/price-feeds/addresses
(, int256 answer, , , ) = priceFeed.latestRoundData();
// ETH/USD rate in 18 digit
return uint256(answer * 10000000000);
}
// 1000000000
function getConversionRate(
uint256 ethAmount,
AggregatorV3Interface priceFeed
) internal view returns (uint256) {
uint256 ethPrice = getPrice(priceFeed);
uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1000000000000000000;
// the actual ETH/USD conversion rate, after adjusting the extra 0s.
return ethAmountInUsd;
}
}