170 lines
4.9 KiB
Solidity
170 lines
4.9 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
/*
|
|
Get funds from users
|
|
Withdraw funds
|
|
Set a minimum funding value in USD
|
|
*/
|
|
/***** 1. Pragma *****/
|
|
pragma solidity ^0.8.0;
|
|
|
|
/***** 2. Import *****/
|
|
import "./PriceConverter.sol";
|
|
import "hardhat/console.sol";
|
|
// Save Gas by using constant, immutable for variables
|
|
|
|
/***** 3. Error Codes *****/
|
|
error FundMe__NotOwner();
|
|
|
|
/***** 4. Interfaces *****/
|
|
|
|
/***** 5. Libraries *****/
|
|
|
|
/***** 6. Contracts *****/
|
|
/**
|
|
* @title A contract for crowd funding
|
|
* @author hoelee
|
|
* @notice This contract is to demo a sample funding contract
|
|
* @dev This implements price feed as our library
|
|
*/
|
|
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
|
|
*/
|
|
|
|
/***** 6.1 Type Declarations *****/
|
|
using PriceConverter for uint256;
|
|
uint256 public constant MINIMUM_USD = 50 * 1e18;
|
|
address[] private s_funders;
|
|
address private immutable i_owner; // immutable only can declare 1 time at contructor
|
|
AggregatorV3Interface private s_priceFeed;
|
|
|
|
/***** 6.2 State Variable *****/
|
|
mapping(address => uint256) private s_addressToAmountFunded;
|
|
|
|
/***** 6.3 Modifier *****/
|
|
modifier onlyOwner() {
|
|
// require(msg.sender == i_owner, "Sender is not owner!");
|
|
if (msg.sender != i_owner) {
|
|
revert FundMe__NotOwner();
|
|
}
|
|
_; // doing the rest of the code
|
|
|
|
console.log("Log available via 'yarn hardhat test'");
|
|
}
|
|
|
|
/***** Function Orders:
|
|
* Constructor
|
|
* Receive
|
|
* Fallback
|
|
* External
|
|
* Public Internal
|
|
* Private
|
|
* View / Pure
|
|
* *****/
|
|
|
|
constructor(address s_priceFeedAddress) {
|
|
i_owner = msg.sender;
|
|
s_priceFeed = AggregatorV3Interface(s_priceFeedAddress);
|
|
}
|
|
|
|
// What happens if someone send this contract ETH without calling the fund function
|
|
receive() external payable {
|
|
// people send money / empty money into this contract
|
|
fund();
|
|
}
|
|
|
|
fallback() external payable {
|
|
// cannot identify which function to run
|
|
fund();
|
|
}
|
|
|
|
/**
|
|
* @notice Minimum sending USD50, Check Conversion In Real Time
|
|
* @dev This implements price feed as our library
|
|
*/
|
|
function fund() public payable {
|
|
//require (msg.value >= 1e18, "Didn't send enough"); // 1e18 = 1 * 10 * 18 = 1000000000000000000
|
|
require(
|
|
msg.value.getConversionRate(s_priceFeed) >= MINIMUM_USD,
|
|
"Didn't send enough"
|
|
); // Use error code is gas cheaper
|
|
s_funders.push(msg.sender);
|
|
s_addressToAmountFunded[msg.sender] = msg.value;
|
|
}
|
|
|
|
// Owner of this contract only can withdraw
|
|
function withdraw() public onlyOwner {
|
|
// Can use modifier to replace
|
|
// require(msg.sender == owner, "Sender is not owner");
|
|
|
|
/* starting index, eding index, step amount */
|
|
for (
|
|
uint256 funderIndex = 0;
|
|
funderIndex < s_funders.length;
|
|
funderIndex++
|
|
) {
|
|
address funder = s_funders[funderIndex];
|
|
s_addressToAmountFunded[funder] = 0;
|
|
}
|
|
// reset the array
|
|
s_funders = new address[](0);
|
|
|
|
/*
|
|
// 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");
|
|
}
|
|
|
|
function cheaperWithdraw() public onlyOwner {
|
|
address[] memory funders = s_funders;
|
|
for (
|
|
uint256 funderIndex = 0;
|
|
funderIndex < funders.length;
|
|
funderIndex++
|
|
) {
|
|
address funder = funders[funderIndex];
|
|
s_addressToAmountFunded[funder] = 0;
|
|
}
|
|
// reset the array
|
|
s_funders = new address[](0);
|
|
|
|
(bool callSuccess, ) = i_owner.call{value: address(this).balance}("");
|
|
require(callSuccess, "Call failed");
|
|
}
|
|
|
|
// private variable is gas cheaper
|
|
function getOwner() public view returns (address) {
|
|
return i_owner;
|
|
}
|
|
|
|
function getFunders(uint256 index) public view returns (address) {
|
|
return s_funders[index];
|
|
}
|
|
|
|
function getAddressToAmountFunded(
|
|
address funder
|
|
) public view returns (uint256) {
|
|
return s_addressToAmountFunded[funder];
|
|
}
|
|
|
|
function getPriceFeed() public view returns (AggregatorV3Interface) {
|
|
return s_priceFeed;
|
|
}
|
|
}
|