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