Created
December 26, 2024 16:01
-
-
Save theishu4/7a2c942e0896b273ecf7b9329775a718 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.24+commit.e11b9ed9.js&optimize=false&runs=200&gist=
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity 0.8.24; | |
import {PriceConverter} from "../PriceConverter.sol"; | |
// import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol"; | |
error NotOwner(); | |
error IndexOutOfBound(); | |
error InsufficientBalanceToWithdraw(); | |
/** | |
* Prefer using custom error types with `revert` instead of `require()` for error handling | |
* to save gas. Custom errors are more efficient because they don't store the error message | |
* as a string in the contract's bytecode, reducing gas costs. | |
* Example: if (msg.sender != owner) { revert NotOwner(); } | |
*/ | |
contract FundMe { | |
// using custom library | |
using PriceConverter for uint; | |
/** | |
* `constant`: A constant variable is a value that is fixed at compile-time and cannot be changed. | |
* It is embedded directly into the contract’s bytecode, making it gas-efficient. | |
* | |
* `immutable`: An immutable variable is set once during contract deployment (usually in the constructor) | |
* and cannot be changed afterward. It is stored in contract storage, making it slightly more expensive | |
* than constant but still more efficient than regular state variables. | |
*/ | |
address public immutable i_owner; | |
uint public constant MINIMUM_USD = 5e18; // 5 USD in wei | |
address[] private fundersAddressList; | |
mapping(address funderAddress => uint totalFunded) private fundsList; | |
mapping(address => bool) private hasFunded; | |
constructor() { | |
i_owner = msg.sender; | |
} | |
modifier onlyOwner() { | |
if (msg.sender != i_owner) {revert NotOwner();} | |
/** `_` is a special placeholder represents the point where the function’s | |
* body is inserted within the modifier. | |
*/ | |
_; | |
} | |
modifier hasBalance() { | |
// require(address(this).balance > 0, "Insufficient contract balance for withdrawal!"); | |
if (address(this).balance <= 0) {revert InsufficientBalanceToWithdraw();} | |
_; | |
} | |
/* | |
* `payable`: Allows a function to receive Ether. | |
* | |
* `msg`: It is a global object in Solidity that contains information about the current transaction. | |
* | |
* | |
* Important `msg` properties include: | |
* - `msg.value` : It is the amount of Ether (in wei) sent with the transaction. | |
* - `msg.sender`: The address of the sender who initiated the transaction. | |
* - `msg.data`: The calldata of the transaction (input data for the function call). | |
*/ | |
function fund() public payable { | |
/* | |
* If the transaction fails, it is reverted. | |
* -> Reverting cancels all previous operations performed in the transaction | |
* and refunds the remaining gas back to the sender. | |
* | |
* `value` is passed as first argument to `convertToUSD()` | |
*/ | |
require(msg.value.convertToUSD() >= MINIMUM_USD, "Amount is less than minimum USD"); | |
if (!hasFunded[msg.sender]){ | |
fundersAddressList.push(msg.sender); | |
hasFunded[msg.sender] = true; | |
} | |
fundsList[msg.sender] += msg.value; | |
} | |
// Function to transfer Ether using `transfer` | |
// Both modifier execute serial wise. | |
function withdrawUsingTransfer() public onlyOwner hasBalance { | |
/** | |
* Transfer: | |
* - Sends Ether to the recipient with a fixed gas limit of 2300 gas. | |
* - If the gas limit is exceeded or the transfer fails, the transaction reverts. | |
* - Note: Not recommended for sending Ether in complex scenarios. | |
*/ | |
payable(msg.sender).transfer(address(this).balance); | |
resetFunders(); | |
} | |
// Function to transfer Ether using `send` | |
function withdrawUsingSend() public onlyOwner hasBalance { | |
/** | |
* Send: | |
* - Sends Ether to the recipient with a fixed gas limit of 2300 gas. | |
* - Unlike `transfer`, it returns `false` on failure instead of reverting. | |
* - You must check the return value to handle errors. | |
* - Note: Consider using `call` instead for better flexibility. | |
*/ | |
bool isSuccess = payable(msg.sender).send(address(this).balance); | |
require(isSuccess, "Send failed!"); | |
resetFunders(); | |
} | |
// Function to transfer Ether using `call` (recommended way) | |
function withdrawUsingCall() public onlyOwner hasBalance { | |
/** | |
* Call: Recommended | |
* - Sends Ether without a fixed gas limit, making it more flexible. | |
* - Returns a success flag (`bool`) and optional returned data (`bytes`). | |
* - Always check the success flag to handle errors properly. | |
*/ | |
(bool isCallSuccess, ) = payable(msg.sender).call{value: address(this).balance}(""); | |
require(isCallSuccess, "Call failed!"); | |
resetFunders(); | |
} | |
function resetFunders() internal { | |
for (uint i = 0; i < fundersAddressList.length; i++) { | |
address funder = fundersAddressList[i]; | |
fundsList[funder] = 0; | |
hasFunded[funder] = false; | |
} | |
// fundersAddressList = new address[](0); | |
delete fundersAddressList; | |
} | |
function getBalance() public view returns (uint) { | |
return address(this).balance; | |
} | |
function getFunderAddress(uint index) public view returns (address) { | |
if(index >= fundersAddressList.length) {revert IndexOutOfBound();} | |
return fundersAddressList[index]; | |
} | |
function getFunderContribution(address funderAddress) public view returns (uint) { | |
return fundsList[funderAddress]; | |
} | |
/** | |
* TODO: Write about receive and fallback and also draw that tree chart | |
* TODO: Test it on the metamask | |
*/ | |
receive() external payable { | |
fund(); | |
} | |
fallback() external payable { | |
fund(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity 0.8.24; | |
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol"; | |
library PriceConverter { | |
/** | |
* Library doesn't have state variable. | |
* Library can't send ether. | |
* Library function can only have visibility `internal` | |
*/ | |
function currentPrice() internal view returns (uint) { | |
// Sepolia testnet: 0x694AA1769357215DE4FAC081bf1f309aDC325306 | |
// ZKsync Sepolia testnet: 0xfEefF7c3fB57d18C5C6Cdd71e45D2D0b4F9377bF | |
// network: sepolia testnet | |
// Aggregator: ETH/USD | |
AggregatorV3Interface dataFeed = AggregatorV3Interface(0x694AA1769357215DE4FAC081bf1f309aDC325306); | |
(, int answer,,,) = dataFeed.latestRoundData(); | |
// Making 8bit precision to 18bit | |
return uint(answer) * 1e10; | |
} | |
function convertToUSD(uint256 amountInETH) internal view returns (uint){ | |
uint amountInUSD = (amountInETH * currentPrice()) / 1e18; | |
return amountInUSD; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment