Solidity Snippets

First of all, we need to declare which version of Solidity the compiler should use at the top of the contract:

pragma solidity ^0.8.1;

afterwards we can start writing our first contract like this:

pragma solidity ^0.8.1;

contract contract1 {
    string public aString = "Hello World!";
}

Basic value types:

Here are some data types available in Solidity. When they are used as function arguments or variable assignments, their values are copied over to the new variable.

boolean
int
uint
address
bytes32

Example:

pragma solidity ^0.8.3;

contract contract2 {
    bool public b = false;
    int public i = -2;
    uint public u = 12345;
    address public addr = 0x5B38Da6a401c568545dCfcB03FcB875f56beddC4;
    bytes32 public b32 = 0x89c58ced8a9078bdef2bc60f22e58eeff7dbfed6c2dff3e7c508b629295926fa;
}

External And PURE:

external tells Solidity that the function can only be called from outside this contract.

pure tells Solidity that the function does not write anything to the blockchain.

pragma solidity ^0.8.1;

contract contract3 {
    function add(uint x, uint y) external pure returns (uint) {
        return x + y;
    }
    function sub(uint x, uint y) external pure returns (uint) {
        return x - y;
    }
}

local, state and global variables.
State variables are stored on chain.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract contract4 {
    uint public num;

    function setNum(uint _num) external {
        num = _num;
    }

    // What is "view"?
    // "view" tells Solidity that this is a read-only function.
    // It does not make any updates to the blockchain.
    function getNum() external view returns (uint) {
        return num;
    }
    
    function resetNum() external {
        num = 0;
    }
    
    function getNumPlusOne() external view returns (uint) {
        return num + 1;
    }
}

Global Variables

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract GlobalVariables {
    function globalVars() external {
        // address that called this function
        address sender = msg.sender;
        // timestamp (in seconds) of current block
        uint timeStamp = block.timestamp;
        // current block number
        uint blockNum = block.number;
        // hash of given block
        // here we get the hash of the current block
        // WARNING: only works for 256 recent blocks
        bytes32 blockHash = blockhash(block.number);
    }
    function returnSender() external view returns (address) {
        return msg.sender;
    }
}

view functions can read state and global variables.

pure functions cannot read state or global variables.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract ViewAndPureFunctions {
    uint public num;

    // This is a view function. It reads the state variable "num"
    function viewFunc() external view returns (uint) {
        return num;
    }

    // This is a pure function. It does not read any state or global variables.
    function pureFunc() external pure returns (uint) {
        return 1;
    }
    
    
    function addToNum(uint x) external view returns (uint) {
        return num + x;
    }
    function add(uint x, uint y) external pure returns (uint) {
        return x + y;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract Counter {
    uint public count;
    
    function inc() external {
        count = count + 1;
    }
    function dec() external {
        count = count - 1;
    }
}

Here are the default values for data types that we have covered so far.

type default value
int 0
uint 0
bool false
address 0x0000000000000000000000000000000000000000
bytes32 0x0000000000000000000000000000000000000000000000000000000000000000

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract DefaultValues {
    int public i; // 0
    bytes32 public b32; // 0x0000000000000000000000000000000000000000000000000000000000000000
    address public addr; // 0x0000000000000000000000000000000000000000
    
    uint public u;
    bool public b;
}

Constants

State variables can be declared as constant. Value of constant variables must be set before compilation and it cannot be modified after the contract is compiled.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract Constants {
    address public constant MY_ADDR = 0x777788889999AaAAbBbbCcccddDdeeeEfFFfCcCc;
    
    uint public MY_UINT = 123;
}

if and else

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract IfElse {
    function ifElse(uint _x) external pure returns (uint) {
        if (_x < 10) {
            return 1;
        } else if (_x < 20) {
            return 2;
        } else {
            return 3;
        }
    }

    function ternaryOperator(uint _x) external pure returns (uint) {
        // condition ? value to return if true : value to return if false
        return _x > 1 ? 10 : 20;
    }

    function exercise_1(uint _x) external pure returns (uint) {
        
        
        return _x > 0 ? 1 : 0;
    }

    function exercise_2(uint _x) external pure returns (uint) {
        
        return _x > 0 ? 1 : 0;
    }
}

for and while loops

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract ForAndWhileLoops {
    function loop() external pure {
        // for loop
        for (uint i = 0; i < 10; i++) {
            if (i == 3) {
                // Skip to next iteration with continue
                continue;
            }
            if (i == 5) {
                // Exit loop with break
                break;
            }
        }

        // while loop
        uint j;
        while (j < 10) {
            j++;
        }
    }

    function sum(uint _n) external pure returns (uint) {
        
        
        uint ok;
        for (uint i = 0; i <= _n; i++) {
            ok += i;
        }
        return ok;
        
    }
}

Solidity has 3 ways to throw an error, require, revert and assert.

require is used to validate inputs and check conditions before and after execution.
revert is like require but more handy when the condition to check is nested in several if statements.
assert is used to check invariants, code that should never be false. Failing assertion probably means that there is a bug.
An error will undo all changes made during a transaction.


// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract ErrorHandling {
    function testRequire(uint _i) external pure {
        // Require should be used to validate conditions such as:
        // - inputs
        // - conditions before execution
        // - return values from calls to other functions
        require(_i <= 10, "i > 10");
    }

    function testRevert(uint _i) external pure {
        // Revert is useful when the condition to check is complex.
        // This code does the exact same thing as the example above
        if (_i > 10) {
            revert("i > 10");
        }
    }

    uint num;

    function testAssert() external view {
        // Assert should only be used to test for internal errors,
        // and to check invariants.

        // Here we assert that num is always equal to 0
        // since it is impossible to update the value of num
        assert(num == 0);
    }

    function div(uint x, uint y) external pure returns (uint) {
        
 
        require(y != 0, "div by 0");
        return x / y;
    }
}


Modifier

Function modifiers are reuseable code that can be run before and / or after a function call.

Here are some examples of how they are used.

Restrict access
Validate inputs
Check states right before and after a function call


// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract FunctionModifier {
    bool public paused;
    uint public count;

    // Modifire to check if not paused
    modifier whenNotPaused() {
        require(!paused, "paused");
        // Underscore is a special character only used inside
        // a function modifier and it tells Solidity to
        // execute the rest of the code.
        _;
    }
    modifier whenPaused() {
        require(paused, "not paused");
        _;
    }

    function setPause(bool _paused) external {
        paused = _paused;
    }

    // This function will throw an error if paused
    function inc() external whenNotPaused {
        count += 1;
    }

    function dec() external whenNotPaused {
        count -= 1;
    }

    // Modifiers can take inputs.
    // Here is an example to check that x is < 10
    modifier cap(uint _x) {
        require(_x < 10, "x >= 10");
        _;
    }

    function incBy(uint _x) external whenNotPaused cap(_x) {
        count += _x;
    }

    // Modifiers can execute code before and after the function.
    modifier sandwich() {
        // code here
        _;
        // more code here
    }
    
    function reset() external whenPaused {
        count = 0;
    }
}

constructor is a special function that is called only once when the contract is deployed.

The main purpose of the the constructor is to set state variables to some initial state.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract ConstructorIntro {
    address public owner;
    uint public x;

    constructor(uint _x) {
        // Here the owner is set to the caller
        owner = msg.sender;
        x = _x;
    }
}

Ownable

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract Ownable {
    address public owner;
    
    
 constructor() {
    owner = msg.sender;
}
modifier onlyOwner() {
    require(msg.sender == owner, "not owner");
    _;
}
    

    
    function setOwner(address _newOwner) external onlyOwner {
    require(_newOwner != address(0), "new owner = zero address");

    owner = _newOwner;
    }
}


Functions can return multiple outputs.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract FunctionOutputs {
    // Functions can return multiple outputs.
    function returnMany() public pure returns (uint, bool) {
        return (1, true);
    }

    // Outputs can be named.
    function named() public pure returns (uint x, bool b) {
        return (1, true);
    }

    // Outputs can be assigned to their name.
    // In this case the return statement can be omitted.
    function assigned() public pure returns (uint x, bool b) {
        x = 1;
        b = true;
    }

    // Use destructing assignment when calling another
    // function that returns multiple outputs.
    function destructingAssigments() public pure {
        (uint i, bool b) = returnMany();

        // Outputs can be left out.
        (, bool bb) = returnMany();
    }
    
    function myFunc() external view returns(address, bool) {
        return (msg.sender, false);
    }
}

Arrays

“delete” can be used in order to remove an element in an array.


// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract ArrayBasic {
    // Several ways to initialize an array
    uint[] public arr;
    uint[] public arr2 = [1, 2, 3];
    // Fixed sized array, all elements initialize to 0
    uint[3] public arrFixedSize;

    // Insert, read, update and delete
    function examples() external {
        // Insert - add new element to end of array
        arr.push(1);
        // Read
        uint first = arr[0];
        // Update
        arr[0] = 123;
        // Delete does not change the array length.
        // It resets the value at index to it's default value,
        // in this case 0
        delete arr[0];

        // pop removes last element
        arr.push(1);
        arr.push(2);
        // 2 is removed
        arr.pop();

        // Get length of array
        uint len = arr.length;

        // Fixed size array can be created in memory
        uint[] memory a = new uint[](3);
        // push and pop are not available
        // a.push(1);
        // a.pop(1);
        a[0] = 1;
    }
    function get(uint i) external view returns(uint) {
        return arr[i];
    }
    function push(uint x) external {
        arr.push(x);
    }
    function remove(uint i) external {
       delete arr[i];
    }
    function getLength() external view returns(uint) {
        return arr.length;
    }
    
    
}


Mapping

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

contract MappingBasic {
    // Mapping from address to uint used to store balance of addresses
    mapping(address => uint) public balances;

    // Nested mapping from address to address to bool
    // used to store if first address is a friend of second address
    mapping(address => mapping(address => bool)) public isFriend;

    function examples() external {
        // Insert
        balances[msg.sender] = 123;
        // Read
        uint bal = balances[msg.sender];
        // Update
        balances[msg.sender] += 456;
        // Delete
        delete balances[msg.sender];

        // msg.sender is a friend of this contract
        isFriend[msg.sender][address(this)] = true;
    }
    
    function get(address _addr) external view returns(uint) {
        return balances[_addr];
    }
    function set(address _addr, uint _val) external {
        balances[_addr] = _val;
    }
    function remove(address _addr) external {
        delete balances[_addr];
    }
}

Add your comment