Added FundMe & PriceConverter

This commit is contained in:
hoelee 2024-08-04 00:04:33 +08:00
parent 09ad760b53
commit 89363c573a
8 changed files with 1130 additions and 26 deletions

7
.solhint.json Normal file
View File

@ -0,0 +1,7 @@
{
"extends": "solhint:recommended",
"rules": {
"compiler-version": ["error", "^0.8.0"],
"func-visibility": ["warn", { "ignoreConstructors": true }]
}
}

2
.solhintignore Normal file
View File

@ -0,0 +1,2 @@
node_modules
contracts/test

86
contracts/FundMe.sol Normal file
View File

@ -0,0 +1,86 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
import "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
import "./PriceConverter.sol";
error NotOwner();
contract FundMe {
using PriceConverter for uint256;
mapping(address => uint256) public addressToAmountFunded;
address[] public funders;
// 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() {
i_owner = msg.sender;
}
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;
funders.push(msg.sender);
}
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();
_;
}
function withdraw() public onlyOwner {
for (uint256 funderIndex=0; funderIndex < funders.length; funderIndex++){
address funder = funders[funderIndex];
addressToAmountFunded[funder] = 0;
}
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");
}
// 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();
}
}
// 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,34 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
import "@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() internal view returns (uint256) {
// Sepolia ETH / USD Address
// https://docs.chain.link/data-feeds/price-feeds/addresses#Sepolia%20Testnet
AggregatorV3Interface priceFeed = AggregatorV3Interface(
0x694AA1769357215DE4FAC081bf1f309aDC325306
);
(, int256 answer, , , ) = priceFeed.latestRoundData();
// ETH/USD rate in 18 digit
return uint256(answer * 10000000000);
// or (Both will do the same thing)
// return uint256(answer * 1e10); // 1* 10 ** 10 == 10000000000
}
// 1000000000
function getConversionRate(
uint256 ethAmount
) internal view returns (uint256) {
uint256 ethPrice = getPrice();
uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1000000000000000000;
// or (Both will do the same thing)
// uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1e18; // 1 * 10 ** 18 == 1000000000000000000
// the actual ETH/USD conversion rate, after adjusting the extra 0s.
return ethAmountInUsd;
}
}

View File

@ -5,10 +5,10 @@ contract SimpleStorage {
// boolean, uint, int, address, bytes
address public myAddress = 0xc9445E993dAeA4bA3F1FE1080F0F6f8c46b4d967;
uint256 public myNumber = 123; // With Getter, Retrieval Need Gas
string myText = "Hello World";
string private myText = "Hello World";
//int256 favoriteInt = -5;
//bytes32 favoriteBytes = "cat";
uint256 myDefaultZero; // Initialize default to 0
uint256 private myDefaultZero; // Initialize default to 0
// Paid
function storeMyNumber(uint256 _favoriteNumber) public virtual {

View File

@ -42,7 +42,7 @@ module.exports = {
chainId: 31337,
},
},
solidity: "0.8.24",
solidity: "0.8.8",
etherscan: {
apiKey: ETHERSCAN_API_KEY,
},

View File

@ -7,6 +7,7 @@
"license": "Unlicense",
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
"devDependencies": {
"@chainlink/contracts": "^1.2.0",
"@nomicfoundation/hardhat-chai-matchers": "^2.0.0",
"@nomicfoundation/hardhat-ethers": "^3.0.0",
"@nomicfoundation/hardhat-ignition": "^0.15.0",
@ -26,6 +27,7 @@
"hardhat-gas-reporter": "^1.0.8",
"prettier": "^3.3.3",
"prettier-plugin-solidity": "^1.3.1",
"solhint": "^5.0.2",
"solidity-coverage": "^0.8.12",
"ts-node": ">=8.0.0",
"typechain": "^8.3.0",

1019
yarn.lock

File diff suppressed because it is too large Load Diff