Personal Notes-Solidity-1.0.2

Lesson 3

In order to interact with a contract, you need 2 things

  • Address
  • ABI -> Application Binary Interface

How do I inherit?

contract inheritedContract is ParentContract {

}

how to inherit a function, we use override.

parent function => function functionName(datatype argument) public **virtual** {

}

child function => function functionName( dataType Argument) public **override** {

}

Lesson 4

Sending ETH Through a function and Reverts.

Remix Fund Me

The following contract will do the following

  • Get funds from users.
  • Withdraw funds (only who publishes the contract)
  • Set a minimum funding value in USD

SideNote:

  • Smart Contract can hold funds just like how wallets can.
  • payable keyword allows the function to deal with currency
  • msg.value determines the value send to the payable function

  • to validate something we can add middleware in a contract for example `` require(msg.value >1e18, "Didn't send the required amount" );

  • 1e18 => 1 10 *18 wei => 1 eth => money transaction is done in terms of wei.
  • The second parameter is the fallback msg incase the condition is not met.

  • reverts means that in case the middleware fails, any transaction done before the middleware will be reset.


// SPDX-License-Identifier: MIT

pragma soidity ^0.8.8;

contract FundMe {

    function fund() public  payable {  //send money to the owner




      }

  function withdraw(){ //only who publishes the contract can withdraw the funds

  }


}

In solidity, we cannot use fetch to call an API, as a blockchain is a deterministic system we cannot use API calls. If a given node calls an API and its data changes for different nodes, nodes will have different values, which defeats the purpose. for that reason, we use an oracle. An oracle is a distributed network that gets values from different points of interest, combines the value, and sends it to the blockchain. if the node fails to send the value, other nodes in the oracle will forward the respective values, since an oracle does not have a single point to send data, it is not centralized.

To use an oracle we need to use an interface. an interface basically has a list of function calls whose code is not visible, in other words, an interface is an abstraction of a list of functions, which you use to access the functionality of the oracle. Think of it as ABI's

Steps to use an oracle.

  • Find the address of the oracles functionality you want to use.
  • import directly from GitHub. import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol "
  • AggregatorV3Interface( Address Of Contract ).functionality()
(, int256 price,,,) = AggregatorV3Interface( **Address Of Contract**).latestRoundData();
// ETH price in USD

The value of price should have 18 decimal places because all value is in ref, of Wei. 1Eth -> 1e18 -> 110**18. So to get it to 18 dec places we multiply the result by `` price1e18 ``

  • So now the price we got is in 18decimal places (ethPrice), and the msg.value by default is in 18decimal (ethAmount) places.

Since the price we get is in int and msg.value is uint we need to do type casting. => uint256(price *1e10).

  • (ethPrice * ethAmount)/1e18

  • any and all monitary values should be in the syntax of 1e18

Arrays and Structs - 2

  • msg.sender is the address of whoever calls that function in a contract
  • msg.value is the amount of eth the sender sends.
address[] public funder; //array of addresses
mapping(address=>uint256) public addressToAmountFunded;

 //holds the list of addresses that payed
funder.push(msg.sender)             

//holds the list of addresses against the amount paid.
addressToAmountFunded[msg.sender]=msg.value

Sidenote: If a function works with money, add a keyword called payable.

Library

A library is somewhat like a contract, but does not have state variables, and does not deal with money. So basically you can add functions that do not deal with state variables and currency.

  • A library function should be internal.

  • It can be called as a method in another contract.

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol ";

library PriceConverter {

    function getPrice() **internal** view returns(uint256){

    }


}
  • we import PriceConverter to the contract we want to use it in.
  • we assign PriceConverter to a datatype using PriceConverter for uint256;
  • we can use the libraries on any state variables having the data type mentioned above, in this case uint256 msg.value.getConversionRate()

safeMath, Overflow checking, and the "unchecked" keyword

  • uint max size is 255;

  • reset an array `` arrayName = new address

Different ways to send money

  • Transfer : payable(owner_Address).transfer(amount-to-transfer) this can be msg.value or the amount present in the contract. (address(this).balance). It automatically revets if the transaction fails.
  • Send: send returns a boolean, based on if the transaction failed. `` bool sendSuccess=payable(msg.sender).send(address(this).balance); require(sendSuccess,"Send failed")
  • Call: Read more about it. This is standard.
    (bool callSuccess,)= payable(msg.sender).call{value: address(this).balance}("");
    require(callSuccess,"Call failed")
    

Constructor

we use this to set the address of the user as the owner of the contract.

address owner public;

constructor(){
owner =msg.sender
}

Modifiers

A modifier is like a middleware, whose value is associated with a keyword. so you don't have to copy-paste repeated code multiple times.

  • The underscore basically means where the following code is executed. since its after a condition, we execute the code after the condition.

modifier onlyOwner {

require(msg.sender == owner, "Sender is not owner");
_;

}

function withdraw() public **onlyOwner** {
//some code
}

Advanced Solidity Concepts

Keep in mind 2 keywords that affect gas consumption

  • constant : keywords assigned with constant keyword don't change values

  • immutable : Both immutable and constant are keywords that can be used on state variables to restrict modifications to their state. The difference is that constant variables can never be changed after compilation, while immutable variables can be set within the constructor.

Advanced Solidity Custom Errors

//space outside the contract



contract ContractName {


if(msg.sender != i_owner) {
revert NotOwner();
}

}

fallback and receive

  • receive is a default function that gets triggered when token/ money is send to the contract.
  • fallback is a default function that gets triggered when information/data is send to the contract
receive() external payable {
  fund() //routes incase of accidental sending of money
}

fallback() external payable {
  fund() //routes incase of accidental sending of money
}

Ether.js

6:47:01

Ganache & Networks

  • npm i solc
  • Solc allows you to compile solidity contracts in our code
  • Solc allows you to compile solidity contracts separately

How to compile our contract?: Run the following command=>npm solcjs --bin

  • --bin => to get the binary
  • --abi => to get the abi
  • --include-path node_modules/ => to get the node modules
  • --base-path . -o . SimpleStorage.sol=> the "." means the current folder, the "-o" means to output the binary in the "." current directory and "SimpleStorage.sol" is the current solidity file to compile

npm solcjs --bin --abi --include-path node_modules/ --base-path . -o . SimpleStorage.sol

  • 2 files will be outputted => called simpeStorage_sol_simpleStorage.abi and simpeStorage_sol_simpleStorage.bin

"scripts":{
  "compile":"yarn solcjs --bin --abi --include-path node_modules/ --base-path . -o . SimpleStorage.sol"
}

Ganache & Networks

In order to execute and test the code in a blockchain, we need a fake blockchain.

  • Hardhat
  • Ganache ~ a virtual machine. it's basically a fake blockchain that we can use to test/deploy/run code locally

  • install Ganache application. > quickstart Etherium

  • rpc-url is an entry point to connect to a blockchain.