In Progress Add Mock
This commit is contained in:
+78
-54
@@ -1,86 +1,110 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.8;
|
||||
/*
|
||||
Get funds from users
|
||||
Withdraw funds
|
||||
Set a minimum funding value in USD
|
||||
*/
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
|
||||
import "./PriceConverter.sol";
|
||||
// Save Gas - constant, immutable
|
||||
|
||||
error NotOwner();
|
||||
|
||||
// 816914
|
||||
contract FundMe {
|
||||
/*
|
||||
Transaction Fields
|
||||
Nonce
|
||||
Gas Price
|
||||
Gas Limit - Max Gas that this TX can use
|
||||
To - Address
|
||||
Value - Amount of wei to send
|
||||
Data - What to send to the Address (Can Empty)
|
||||
v, r, s - components of TX signature
|
||||
*/
|
||||
|
||||
using PriceConverter for uint256;
|
||||
uint256 public constant MINIMUM_USD = 50 * 1e18;
|
||||
|
||||
mapping(address => uint256) public addressToAmountFunded;
|
||||
address[] public funders;
|
||||
mapping(address => uint256) public addressToAmountFunded;
|
||||
|
||||
// Could we make this constant? /* hint: no! We should make it immutable! */
|
||||
address public /* immutable */ i_owner;
|
||||
uint256 public constant MINIMUM_USD = 50 * 10 ** 18;
|
||||
|
||||
constructor() {
|
||||
// immutable only can declare 1 time at contructor
|
||||
address public immutable i_owner;
|
||||
|
||||
AggregatorV3Interface public priceFeed;
|
||||
|
||||
constructor(address priceFeedAddress) {
|
||||
i_owner = msg.sender;
|
||||
priceFeed = AggregatorV3Interface(priceFeedAddress);
|
||||
}
|
||||
|
||||
function fund() public payable {
|
||||
require(msg.value.getConversionRate() >= MINIMUM_USD, "You need to spend more ETH!");
|
||||
// require(PriceConverter.getConversionRate(msg.value) >= MINIMUM_USD, "You need to spend more ETH!");
|
||||
addressToAmountFunded[msg.sender] += msg.value;
|
||||
/*
|
||||
Want to be able to set a minimum fund amount in USD
|
||||
1. How do we send ETH to this contract
|
||||
*/
|
||||
//require (msg.value >= 1e18, "Didn't send enough"); // 1e18 = 1 * 10 * 18 = 1000000000000000000
|
||||
require(
|
||||
msg.value.getConversionRate(priceFeed) >= MINIMUM_USD,
|
||||
"Didn't send enough"
|
||||
);
|
||||
funders.push(msg.sender);
|
||||
addressToAmountFunded[msg.sender] = msg.value;
|
||||
}
|
||||
|
||||
function getVersion() public view returns (uint256){
|
||||
// ETH/USD price feed address of Sepolia Network.
|
||||
AggregatorV3Interface priceFeed = AggregatorV3Interface(0x694AA1769357215DE4FAC081bf1f309aDC325306);
|
||||
return priceFeed.version();
|
||||
}
|
||||
|
||||
modifier onlyOwner {
|
||||
// require(msg.sender == owner);
|
||||
if (msg.sender != i_owner) revert NotOwner();
|
||||
_;
|
||||
}
|
||||
|
||||
|
||||
// Owner of this contract only can withdraw
|
||||
function withdraw() public onlyOwner {
|
||||
for (uint256 funderIndex=0; funderIndex < funders.length; funderIndex++){
|
||||
// Can use modifier to replace
|
||||
// require(msg.sender == owner, "Sender is not owner");
|
||||
|
||||
/* starting index, eding index, step amount */
|
||||
for (
|
||||
uint256 funderIndex = 0;
|
||||
funderIndex < funders.length;
|
||||
funderIndex++
|
||||
) {
|
||||
address funder = funders[funderIndex];
|
||||
addressToAmountFunded[funder] = 0;
|
||||
}
|
||||
// reset the array
|
||||
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}("");
|
||||
|
||||
/*
|
||||
// transfer - over 2300 gas will cause exception
|
||||
payable(msg.sender).transfer(address(this).balance);
|
||||
// send - over 2300 gas will not cause exception, only will return true or false
|
||||
bool sendSuccess = payable(msg.sender).send(address(this).balance);
|
||||
require(sendSuccess, "Send failed");
|
||||
*/
|
||||
|
||||
// call - lower level
|
||||
(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();
|
||||
modifier onlyOwner() {
|
||||
// require(msg.sender == i_owner, "Sender is not owner!");
|
||||
if (msg.sender != i_owner) {
|
||||
revert NotOwner();
|
||||
}
|
||||
|
||||
_; // doing the rest of the code
|
||||
}
|
||||
|
||||
// What happens if someone send this contract ETH without calling the fund fucntion
|
||||
/*
|
||||
receive - people send money / empty money into this contract
|
||||
fallback - cannot identify which function to run
|
||||
*/
|
||||
receive() external payable {
|
||||
fund();
|
||||
}
|
||||
|
||||
fallback() external payable {
|
||||
fund();
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -6,13 +6,14 @@ import "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.so
|
||||
// Why is this a library and not abstract?
|
||||
// Why not an interface?
|
||||
library PriceConverter {
|
||||
// Sepolia ETH / USD Address
|
||||
// https://docs.chain.link/data-feeds/price-feeds/addresses#Sepolia%20Testnet
|
||||
//0x694AA1769357215DE4FAC081bf1f309aDC325306
|
||||
|
||||
// We could make this public, but then we'd have to deploy it
|
||||
function getPrice() internal view returns (uint256) {
|
||||
// Sepolia ETH / USD Address
|
||||
// https://docs.chain.link/data-feeds/price-feeds/addresses#Sepolia%20Testnet
|
||||
AggregatorV3Interface priceFeed = AggregatorV3Interface(
|
||||
0x694AA1769357215DE4FAC081bf1f309aDC325306
|
||||
);
|
||||
function getPrice(
|
||||
AggregatorV3Interface priceFeed
|
||||
) internal view returns (uint256) {
|
||||
(, int256 answer, , , ) = priceFeed.latestRoundData();
|
||||
// ETH/USD rate in 18 digit
|
||||
return uint256(answer * 10000000000);
|
||||
@@ -22,9 +23,10 @@ library PriceConverter {
|
||||
|
||||
// 1000000000
|
||||
function getConversionRate(
|
||||
uint256 ethAmount
|
||||
uint256 ethAmount,
|
||||
AggregatorV3Interface priceFeed
|
||||
) internal view returns (uint256) {
|
||||
uint256 ethPrice = getPrice();
|
||||
uint256 ethPrice = getPrice(priceFeed);
|
||||
uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1000000000000000000;
|
||||
// or (Both will do the same thing)
|
||||
// uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1e18; // 1 * 10 ** 18 == 1000000000000000000
|
||||
|
||||
Reference in New Issue
Block a user