contract FundMe {
// Smart Contracts can hold funds like wallets can
function fund() public payable {
// Want to be able to set a mininum fund amount in USD
// 1. How do we send ETH to this contract?
// require means this function needs this specific condition to fulfill to run
// else revert : undo any action before, and send remaining gas back
// 1e18 === 1 * 10 ** 18 === 1000000000000000000 === value in wei of 1 ethereum
require(msg.value > 1e18, "Didn't send enough!");
}
}
Chainlinks & Oracles
Oracles are centralized network which introduce single point of failure
Chainlinks are Decentralized Oracle Network
Chainlink has many features out of the box
Chainlink Price Feeds
Chainlink Data Feeds are the quickest way to connect your smart contracts to the real-world market prices of assets. https://docs.chain.link/docs/data-feeds/price-feeds/
Chainlink VRF (Verifiable Random Function)
It is a provably fair and verifiable random number generator (RNG) that enables smart contracts to access random values without compromising security or usability. They are also used in building blockchain games and NFTs.
Chainlink Automation (Chainlink Keepers)
Enables conditional execution of your smart contracts based on trigger of an event. https://docs.chain.link/docs/chainlink-automation/
Chainlink Any API
Chainlink nodes can request any API using any api. It requires LINK tokens for the transaction. https://docs.chain.link/docs/any-api/
Interfaces and Price Feeds
contract FundMe {
function getVersion() public view returns (uint256) {
// ABI
// Address (Goerli ETH Testnet) 0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e
// Method 1 of ABI : Copy the Interface code and paste it in this contract
// Interface is the template code (.h file in c++) which includes
// function definations and not the actual implementation
AggregatorV3Interface priceFeed = AggregatorV3Interface(0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e);
return priceFeed.version();
}
}
contract FundMe {
using PriceConverter for uint256;
uint256 public mininumUsd = 50 * 1e18 ;
address[] public funders;
mapping(address => uint256) public addressToAmountFunded;
function fund() public payable {
// If function had 2 parameters like
// getConversionRate(uint256 value, uint somethingElse) {}
// We can call like this
// msg.value.getConversionRate(12);
require(msg.value.getConversionRate() >= mininumUsd, "Didn't send enough!");
funders.push(msg.sender);
addressToAmountFunded[msg.sender] = msg.value;
}
}
SafeMath, Overflow Checking, and the "unchecked" keyword
Was used widely before version 0.8 of solidity
Unsigned integers were going unchecked which led to overflows
uint256 bigNumber = 255
bigNumber = bigNumber + 1
// value becomes 0
Safemath library was used for checking the upper limits to avoid overflows
Onward version 0.8, this check was automatically added
We can still use unchecked {} keyword to revert back to unchecked mode
function withdraw() public onlyOwner {
for(uint256 funderIndex = 0; funderIndex < funders.length; funderIndex++) {
address funder = funders[funderIndex];
addressToAmountFunded[funder] = 0;
}
funders = new address[](0);
(bool callSuccess,) = payable(msg.sender).call{value: address(this).balance}("");
require(callSuccess, "Call failed");
}
modifier onlyOwner {
require(msg.sender == owner, "Sender is now owner!");
_; // Doing rest of code
}
Advanced Solidity Concepts
Immutable & Constant
Used to make contract gas efficient
Instead of storing these variables in the storage class, we save them in the byte code of the contract hence gas efficient.
If a variable is assigned value at compile time and is never changed, then we can add constant keyword with it.
Naming convention is usually all caps
Variables that we set one time but not on the same line where they are declared, we add immutable keyword with it.
Name convention is usually i_<name-of-var>
// Initialized on same line
uint256 public constant MINIMUM_USD = 50 * 1e18 ;
// Initialized later on in contract
address public immutable i_owner;
constructor() {
i_owner = msg.sender;
}
What happens if someone send this contract ETH without calling any function
contract FallbackExample {
uint256 public result;
// Dont add function keyword with receive since it is a special function
// Other special funtions are Constructor(), Fallback(), etc
// Trigerred when someone send ETH to contract without calling any ftn and
// also when there is no call data with the transaction
receive() external payable {
result = 1;
}
// Trigerred when someone send ETH to contract without calling any ftn and
// also when there is call data with the transaction
fallback() external payable {
result = 2;
}
}