Smart Contracts
A Smart Contract is a program that runs in the EVM (Ethereum Virtual Machine). Functions within a Smart Contract deal with/process the data from a transaction that calls it. Smart Contracts have an address, and can send/transfer funds.
Solidity was a great starting point, since I'm already well-versed with Javascript. Here is an example of what a Smart Contract looks like in Solidity:
pragma solidity 0.8.26;
// SPDX-License-Identifier: GPL-3.0
// Our first contract is a faucet!
contract Faucet {
// Give out ether to anyone who asks
function withdraw(uint256 _withdrawAmount, address payable _to) public {
// Limit withdrawal amount
require(_withdrawAmount <= 1000000000000);
// Send the amount to the address that requested it
_to.transfer(_withdrawAmount);
}
// Function to receive Ether. msg.data must be empty
receive() external payable {}
// Fallback function is called when msg.data is not empty
fallback() external payable {}
}
this code is from Ethereumbook
Dissecting:
- Contract -> Javascript's Class
- Require -> function, Condition A must be true, otherwise output Condition B
State Variables & Integers
uint (is also uint256) means unsigned integer. It is used for values that should never be negative such as: balance, counters, etc.
uint8 means a maximum of 255 (0-255, 256 or 11111111)
Another new data type I learned was address, which is used for Ethereum wallet or smart contract addresses.
There may be cases of overflow or underflow when dealing with values in Smart Contracts, which is dangerous especially since you're dealing with funds. For versions below Solidity 0.8.0, you must import SafeMath
Data Locations
| Storage | Stores data permanently in the blockchain. Data in the storage must be mutable, thus this is where state variables (variables outside of a function) are stored. Reminds me of Hardrive |
| Memory | Stores data needed only during function execution, temporary. Used for: Local Variables, arrays inside a function or arguments...Reminds me of RAM |
| CallData | Read-only, immutable and temporary location where function arguments are stored. Kind of like memory but for array parameters, calldata is more approriate since it uses less gas compared to memory. It can only be used for function declaration parameters and not function logic |
Examples from Alchemy
Use Case A (Storage):
contract ColorStorage {
mapping(address => string) private favoriteColors;
function setFavoriteColor(string calldata color) public {
favoriteColors[msg.sender] = color;
}
function getFavoriteColor(address userAddress) public view returns (string memory) {
return favoriteColors[userAddress];
}
}
The favoriteColors is a state variable and is thus placed in Storage..it also noticeable that it can be mutated
Use Case B (Memory):
function sumArray(uint[] memory arr) public pure returns (uint) {
uint sum = 0
for(uint i = 0; i < arr.length; i++) {
sum += array[i];
//or if you want to use SafeMath
// sum = sum.add(array[i])
}
return sum;
}
Function Modifiers: Public vs. Private vs. Internal vs. External
- Public -> Anyone can call it (By anyone I mean you every contract can call it).
- Private -> Belongs only to the class it was created. if the function is private, put a _ before the name.
- Internal -> Can be called through inheritance.
- External -> Invoked by other contracts only, not itself.
- Payable -> used for functions that will send/receive ETH. Refer to this
Types of functions
- Pure - Doesn't read/modify any value of the data in the blockchain. Only uses variables within the function. The allowed to use require() and revert() though.
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.5.0;
/// @title A contract for demonstrating pure functions
/// @notice For now, this contract defining pure function to calculate product and sum of two numbers
contract Test {
function getResult(
) public pure returns(
uint product, uint sum){
uint num1 = 2;
uint num2 = 4;
product = num1 * num2;
sum = num1 + num2;
}
}
- View - Read-only, similar to get method. They usually dont cost gas.
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.5.0;
/// @title A contract for demonstrating view functions
/// @author Jitendra Gangwar
/// @notice For now, this contract defining view function to calculate product and sum of two numbers
contract Test {
// Declaring state variables
uint num1 = 2;
uint num2 = 4;
function getResult(
) public view returns(
uint product, uint sum){
product = num1 * num2;
sum = num1 + num2;
}
}
Why do I need to know all this?
Every Ethereum transaction requires payment of a fee, which is collected by the network to validate the transaction. This fee is called gas. You pay for the gas with ether.
Code Optimization is very important to reduce gas costs. There are many ways to do this. For instance:
- Inside a struct, be specific with uint size so they take up less storage. Solidity will assign 256 bits.
- Pure and View will cost something only if they're called internally by another gas-costing function.
More tips here
Some more useful built-in functions
- require()
- msg.sender()
- transfer()
- send()
Storing Data
Unlike regular code where you store data in a Database, Solidity usually stores them in Mappings. (looks like HashMaps)
mapping(address => uint256) public balances;
What the mapping above those is it stores the a value and pairs it with an address, which in this case, is the owner.
Sample code:
pragma solidity ^0.8.0;
contract SimpleBank {
// Define a mapping to store balances
mapping(address => uint) public balances;
// Function to deposit ether into the contract
function deposit() public payable {
balances[msg.sender] += msg.value;
}
// Function to withdraw ether from the contract
function withdraw(uint amount) public {
require(balances[msg.sender] >= amount, "Insufficient balance");
balances[msg.sender] -= amount;
payable(msg.sender).transfer(amount);
}
// Function to check the balance of the caller
function getBalance() public view returns (uint) {
return balances[msg.sender];
}
}
Resources
- https://medium.com/coinmonks/practicing-safemath-with-solidity-and-openzeppelin-cde4cba9ce39
- https://medium.com/coinmonks/solidity-storage-vs-memory-vs-calldata-8c7e8c38bce
- https://www.geeksforgeeks.org/solidity/solidity-view-and-pure-functions/
- https://medium.com/@ancilartech/stop-burning-money-a-developers-guide-to-smart-contract-gas-optimization-3b5c6c3ce519
- https://cryptomarketpool.com/payable-modifier-in-solidity-smart-contracts/
- https://medium.com/@nareshmmr/understanding-mapping-in-solidity-637e995b0fd4