part 1 of a 5 part series on essentials for solidity devs
- solidity_cheatsheet.sol
- cryptography_cheatsheet.sol
- assembly_cheatsheet.sol
- designPatterns_cheatsheet.sol
- security_cheatsheet.sol
It compiles! Get the full cheatsheet here. Drop a star if you find this useful, it will motivate me to do more of it.
table of contents
- basics
- license
- pragma
- imports
- contract
- events
- constructor
- receive
- modifier
- functions
- symbols
- variables
- control sturctures
- units
- block
- msg
- tx
- intermediate
- OOPs
- library
- custom errors
- fallback
- variable passing
- value types
- reference types
- type conversion
- datatype builtins
- fringe arithmetic
- advanced
- function signatures and selectors
- abi encoding
- low level calls
- error handling
- bit operations
- bitmasking
license
- copyleft:
- ensure that the software is free and open-source even in its derivative versions
- you use this when you do open source software and don't want to let someone else make it proprietary
- examples: GNU General Public License v3.0 (GPL-3.0)
- permissive:
- allows the software to be used in proprietary software
- you use this when you want maximum adoption with minimal legal overhead
- examples: MIT, Apache-2.0, BSD-3-Clause
- implementaion: SPDX-License-Identifier: licence
- Software Package Data Exchange (SPDX)
- this licence declaration is directly included in the source code as a commment
// SPDX-License-Identifier : GPL-3.0
pragma
- ^version: means versions above this but below breaking changes version
- nothing before the version means just that one version
pragma solidity ^0.8.20;
imports
- import "filename";
- imports everything from that file
- import {symbol1, symbol2} from "filename";
- imports only the mentioned items
- import {symbol1 as alias1, symbol2 as alias2} from "filename";
import "@openzeppelin/token/ERC20/utils/SafeERC20.sol";
OOPs
- problem : large codebases are hard to manage
- solution : structure code into smaller packets.
- implementation
- components: class, object, method, variables
- is: inherits contracts
- contract A is B,C,D : B is most base, D is most derived
- C3 linearization right to left(D to B) to resolve conflicts in inheritance
- constructor: order of execution from most base to most derived (B to D)
- visibility: public, internal, private, external
- abstract: when a function is missing definition
- super: call parent class definition
- this: the contract itself in which 'this' is invoked(contract type)
- virtual and override: manage polymorphism
- properties
- encapsulation: bundling everything to form a fully working entity
- abstraction: only expose what is required, rest is kept enclosed
- inheritance: acquiring properties from parents
- polymorphism: The ability to take multiple forms (method overloading & method overriding)
- pros :
- Code Reusability
- Modularity
- Security & Data Hiding
- Easy Maintenance & Scalability
- trivia:
- C3 linearization to resolve inheritance conflicts: inheritance from right to left in the 'is' statement
library
- implementation
- cannot have state variables
- functions in library to have the first parameter as the 'datatype' on which to attach the library
- libraries can be used in two methods
- using library for type : attaches library functions to the type
- library.method
- trivia:
- cannot inherit, nor be inherited
- inheritance doesnt bring using for statement from parent to child, need to write using for again in child.
- cannot recieve ether
- deployment:
- libraries are deployed only when it contains external functions and called by delegatecall
- else its code is embedded into the calling contract at compile time
- the calling convention is designed like internal call not following the abi standard
using SafeERC20 for IERC20;
events
- has normal params and indexed params(for quick searches)
- indexed topics are capped at max 3
- trivia:
- Event logs are stored on blockchain but not accessible from within contracts not even from the contract that created them
- indexed are special params included in a seperate place called topics
- 'indexed' arguments make it easy for searching and filtering through the logs
event Log(string message);
event newOwner(address indexed owner);
custom errors
- Cheaper gas costs (saves storage compared to string messages)
- More structured error messages.
- implementation
- error certain_edge_case_messing_up();
- error certain_edge_case_messing_up_explained_with_args(args);
- revert certain_edge_case_messing_up();
- revert certain_edge_case_messing_up_explained_with_args(args);
error amount_smaller_than_100(uint256 amount);
function custom_error(uint256 amount) public pure {
if (amount< 100) {
revert amount_smaller_than_100(amount);
}
}
constructor
- executes once during deployment
- can recieve ether during deployment
- its runtime code, not part of the contract
- constructor execution order: B -> C -> solidity_cheatsheet
- most base to most derived
constructor(/* args1, args2 */) /* B(args1) C(args2) */ payable {
wingman = new Wingman();
owner = msg.sender;
emit newOwner(owner);
}
fallback
- called when the contract is invoked with calldata, but function definition is absent
- this function has builtin definition and its very strict, only two variations allowed
- fallback() external [payable] {}
- fallback(bytes calldata input) external [payable] returns(bytes memory) {}
- trivia:
- does not have a function signature
fallback(bytes calldata _shipment) external payable returns(bytes memory){
string memory payload = abi.decode(_shipment,(string));
return bytes(string.concat(payload, "_done"));
}
receive
- this function is called when the contract is invoked without calldata
- main purpose is to receive ETH
- this function has builtin definition, only one variation allowed
- receive() external payable {}
- its mostly kept empty
- trivia:
- does not have a function signature
receive() external payable {}
modifier
- a piece of code that generally contains some checks and is placed on top of a function
- modifiers can accept arguments
- function body represented by _ it can be included multiple times.
- Modifiers wrap around the function body using the special placeholder _ When multiple modifiers are applied, they execute in a nested manner:
- The first modifier runs until it reaches _.
- Control moves to the next modifier in the order they are listed.
- This continues until the function itself executes.
- Once the function completes, execution unwinds back up through the modifiers.
modifier onlyOwner() {
require(msg.sender == owner, "only owner can call this function");
_;
}
modifier single_digit_value(uint256 _value) {
require(_value < 10, "value should be less than 10");
_;
}
function onlyOwnerFunction(uint256 value) view public onlyOwner single_digit_value(value) returns(string memory) {
return "greetings to the owner";
}
functions
- return variables can be used as any other local variable.
- members: .selector
- return: concludes the function execution generally returns some value.
symbols
- () --> functions, mapping, typecasting
- {} --> function blocks, struct blocks, conditional blocks, loop blocks
- [] --> arrays
- ; --> end of statement
- : --> key value pair, array slicing, ternary operator
- , --> seperator
- . --> access
- - --> subtraction
- + --> addition
- * --> multiplication
- / --> division
- % --> modulo
- ** --> power
- || --> or
- && --> and
- | --> bitwise or
- & --> bitwise and
- ! --> not
- ~ --> bitwise not
- ^ --> bitwise xor
- << --> left shift
- >> --> right shift
- == --> equal
- != --> not equal
- < --> less than
- > --> greater than
- <= --> less than or equal
- >= --> greater than or equal
- = --> assignment
- += --> addition assignment
- _ --> integer filler
- "" --> string
- '' --> string
- \ --> escape character
- // --> single line comment
- /// --> natspec comment
- /* */ --> multi line comment
- /** */ --> multi line natspec comment
variables
- life cycle of a variable
- definition
- declaration
- assignment
- access
- attributes
- interpretation
- size
- type
- data location
- slot position
- behaviour
- visibility
- name
- value
variable passing
pass by value: value copy pasted to new location, new variable (copy paste)
-
pass by reference:
- pass in same data location: nothing is copy pasted, instead a new name is given to the same location value pair (renaming)
- pass in different data location: pass by value
| value |
|-----------|
| location |
name1
data location
bit level architecture, data location, inline assembly and gas costs covered in assembly cheatsheet.
--- memory ---
- structure : byte addressable array that reads and writes on 32 byte words
- trivia
- locally available, function scoped
- temporary existence, only for duration of tx
- cheap
--- storage ---
- structure
- mapping of 32-byte keys(storage-slots) to a 32-byte values
- storage slots start at slot 0
- trivia
- globally avilable
- permanent existance
- expensive
--- calldata ---
samae as memory, but its read only