InterviewPitch
Solidity interview questions

Solidity Interview Questions with Answers

Most Asked Solidity Interview Questions for Blockchain and Web3 Roles

100+ QuestionsDetailed AnswersCode ExamplesUpdated for 2026

Introduction

Solidity is the premier language for smart contracts on Ethereum and EVM‑compatible blockchains, combining object‑oriented and security‑focused design. This page compiles the most frequently asked Solidity interview questions – from basic syntax and data types to advanced design patterns, gas optimisation, and security best practices – essential for any blockchain or Web3 developer.

Why Solidity?

  • Purpose‑built for Ethereum and EVM chains
  • Turing‑complete – supports complex logic
  • Security‑focused with built‑in modifiers and guards
  • Used in DeFi, NFTs, DAOs, and Web3
  • Gas‑efficient – optimised for blockchain resources
  • Vibrant ecosystem with Hardhat, Foundry, and Truffle
  • High demand in the growing blockchain industry

Most Asked Solidity Interview Questions

Beginner
1. What is Solidity?

Solidity is a high-level, object-oriented programming language for implementing smart contracts on various blockchain platforms, most notably Ethereum.

  • Contract-oriented: Designed for smart contracts
  • EVM-based: Compiles to Ethereum Virtual Machine bytecode
  • Statically typed: Type checking at compile time
  • Inheritance: Supports multiple inheritance
  • Security-focused: Built-in security features
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Hello World in Solidity
contract HelloWorld {
    string public greeting = "Hello, World!";
    
    function greet() public view returns (string memory) {
        return greeting;
    }
}
Beginner
2. How to declare variables in Solidity?

Variables in Solidity are declared with explicit types. They can be state variables, local variables, or global variables.

  • State variables: Stored on blockchain
  • Local variables: Stored in memory
  • Constants: constant keyword
  • Immutables: immutable keyword
  • Global variables: msg.sender, block.number
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Variables in Solidity
contract Variables {
    // State variables (stored on blockchain)
    string public mutableVar = "Hello";
    string public constant immutableVar = "World";
    uint256 public inferred = 42;
    
    // Data types
    bool public isActive = true;
    int256 public intNum = -10;
    uint256 public uintNum = 100;
    address public owner = msg.sender;
    
    // Display
    function getVariables() public view returns (string memory, string memory, uint256) {
        return (mutableVar, immutableVar, inferred);
    }
    
    // Update variable
    function setMutableVar(string memory _newValue) public {
        mutableVar = _newValue;
    }
}
Beginner
3. What are the data types in Solidity?

Solidity provides several data types including integers, booleans, addresses, bytes, strings, arrays, structs, and mappings.

  • Integers: int, uint (signed/unsigned)
  • Boolean: bool
  • Address: address, address payable
  • Bytes: bytes, bytes1...bytes32
  • String: string
  • Array: type[]
  • Struct: struct
  • Mapping: mapping
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Data Types in Solidity
contract DataTypes {
    // Integer types
    int8 public int8Num = -128;
    int16 public int16Num = -32768;
    int32 public int32Num = -2147483648;
    int64 public int64Num = -9223372036854775808;
    int256 public int256Num = -57896044618658097711785492504343953926634992332820282019728792003956564819968;
    
    uint8 public uint8Num = 255;
    uint16 public uint16Num = 65535;
    uint32 public uint32Num = 4294967295;
    uint64 public uint64Num = 18446744073709551615;
    uint256 public uint256Num = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
    
    // Boolean
    bool public isActive = true;
    
    // Address
    address public owner = 0x742d35Cc6634C0532925a3b844Bc454e4438f44e;
    address payable public payableAddress = payable(0x742d35Cc6634C0532925a3b844Bc454e4438f44e);
    
    // Fixed-size byte arrays
    bytes1 public byte1 = 0x01;
    bytes32 public bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000001;
    
    // Dynamic byte array
    bytes public dynamicBytes = "Hello";
    
    // String
    string public str = "Hello Solidity";
    
    // Array
    uint256[] public uintArray = [1, 2, 3, 4, 5];
    uint256[5] public fixedArray = [1, 2, 3, 4, 5];
    
    // Struct
    struct Person {
        string name;
        uint256 age;
    }
    Person public person = Person("Alice", 25);
    
    // Mapping
    mapping(address => uint256) public balances;
}
Beginner
4. How to define functions in Solidity?

Functions in Solidity are defined with the function keyword, visibility modifiers, and return types.

  • Visibility: public, private, internal, external
  • State mutability: view, pure, payable
  • Parameters: Input parameters with types
  • Returns: returns (type)
  • Modifiers: modifier for custom logic
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Functions in Solidity
contract Functions {
    // Basic function
    function add(uint256 a, uint256 b) public pure returns (uint256) {
        return a + b;
    }
    
    // Multiple return values
    function divide(uint256 a, uint256 b) public pure returns (uint256 quotient, uint256 remainder) {
        require(b != 0, "Division by zero");
        quotient = a / b;
        remainder = a % b;
    }
    
    // Function with default parameters (using overload)
    function greet() public pure returns (string memory) {
        return greet("Guest");
    }
    
    function greet(string memory name) public pure returns (string memory) {
        return string(abi.encodePacked("Hello, ", name, "!"));
    }
    
    // View function (read-only)
    function getBlockNumber() public view returns (uint256) {
        return block.number;
    }
    
    // Pure function (no state access)
    function pureAdd(uint256 a, uint256 b) public pure returns (uint256) {
        return a + b;
    }
    
    // Payable function
    function receivePayment() public payable {
        // Receive ether
    }
    
    // Function with modifiers
    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }
    
    address public owner;
    
    function setOwner(address _owner) public onlyOwner {
        owner = _owner;
    }
}
Beginner
5. What are arrays in Solidity?

Arrays in Solidity can be fixed-size or dynamic. They store elements of the same type and support various operations.

  • Fixed-size: uint256[5]
  • Dynamic: uint256[]
  • Push/Pop: push(), pop()
  • Length: array.length
  • Memory arrays: new uint256[](size)
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Arrays in Solidity
contract Arrays {
    // Dynamic array
    uint256[] public numbers;
    string[] public strings = ["Apple", "Banana", "Orange"];
    
    // Fixed array
    uint256[5] public fixedNumbers = [1, 2, 3, 4, 5];
    
    // Array operations
    function addNumber(uint256 _num) public {
        numbers.push(_num);
    }
    
    function getNumber(uint256 _index) public view returns (uint256) {
        return numbers[_index];
    }
    
    function getLength() public view returns (uint256) {
        return numbers.length;
    }
    
    function removeLast() public {
        numbers.pop();
    }
    
    // Array iteration
    function sumArray() public view returns (uint256) {
        uint256 sum = 0;
        for (uint256 i = 0; i < numbers.length; i++) {
            sum += numbers[i];
        }
        return sum;
    }
    
    // Array methods
    function getDoubled() public view returns (uint256[] memory) {
        uint256[] memory doubled = new uint256[](numbers.length);
        for (uint256 i = 0; i < numbers.length; i++) {
            doubled[i] = numbers[i] * 2;
        }
        return doubled;
    }
    
    function getFiltered() public view returns (uint256[] memory) {
        uint256 count = 0;
        for (uint256 i = 0; i < numbers.length; i++) {
            if (numbers[i] > 2) {
                count++;
            }
        }
        uint256[] memory filtered = new uint256[](count);
        uint256 index = 0;
        for (uint256 i = 0; i < numbers.length; i++) {
            if (numbers[i] > 2) {
                filtered[index] = numbers[i];
                index++;
            }
        }
        return filtered;
    }
}
Beginner
6. What are collections in Solidity?

Solidity provides arrays, mappings, and structs as collections for storing and organizing data.

  • Arrays: Ordered list of elements
  • Mappings: Key-value storage
  • Structs: Custom data structures
  • Nested collections: Arrays of structs, mappings to structs
  • Operations: Iteration, access, modification
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Collections in Solidity
contract Collections {
    // Arrays (List)
    uint256[] public list = [1, 2, 3, 4, 5];
    
    // Mapping (Dictionary)
    mapping(address => uint256) public balances;
    
    // Nested mapping
    mapping(address => mapping(uint256 => bool)) public permissions;
    
    // Struct with mapping
    struct User {
        string name;
        uint256 age;
        mapping(uint256 => bool) permissions;
    }
    mapping(address => User) public users;
    
    // Array of structs
    struct Item {
        string name;
        uint256 price;
    }
    Item[] public items;
    
    // Collection operations
    function addItem(string memory _name, uint256 _price) public {
        items.push(Item(_name, _price));
    }
    
    function getItem(uint256 _index) public view returns (string memory, uint256) {
        return (items[_index].name, items[_index].price);
    }
    
    function setBalance(address _user, uint256 _amount) public {
        balances[_user] = _amount;
    }
    
    function getBalance(address _user) public view returns (uint256) {
        return balances[_user];
    }
    
    // Mapping iteration (not directly possible, use array of keys)
    address[] public userList;
    
    function addUser(address _user) public {
        if (balances[_user] == 0) {
            userList.push(_user);
        }
        balances[_user]++;
    }
    
    function getAllUsers() public view returns (address[] memory) {
        return userList;
    }
}
Beginner
7. What are structs in Solidity?

Structs are custom data types that group related variables. They are used to create complex data structures.

  • Definition: struct Person { string name; uint256 age; }
  • Creation: Person("Alice", 25)
  • Access: person.name
  • Storage: Can be stored in arrays and mappings
  • Memory vs Storage: memory vs storage keyword
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Structs (Data Classes) in Solidity
contract DataClasses {
    // Struct definition
    struct Person {
        string name;
        uint256 age;
        string city;
    }
    
    // Struct instance
    Person public person1 = Person("Alice", 25, "NYC");
    
    // Array of structs
    Person[] public people;
    
    // Mapping of structs
    mapping(address => Person) public userProfiles;
    
    // Constructor
    constructor() {
        people.push(Person("Alice", 25, "NYC"));
    }
    
    // Create person
    function createPerson(string memory _name, uint256 _age, string memory _city) public {
        Person memory newPerson = Person({
            name: _name,
            age: _age,
            city: _city
        });
        people.push(newPerson);
    }
    
    // Update person
    function updatePerson(uint256 _index, string memory _name, uint256 _age, string memory _city) public {
        require(_index < people.length, "Index out of bounds");
        people[_index] = Person(_name, _age, _city);
    }
    
    // Get person
    function getPerson(uint256 _index) public view returns (string memory, uint256, string memory) {
        require(_index < people.length, "Index out of bounds");
        Person storage person = people[_index];
        return (person.name, person.age, person.city);
    }
    
    // Get all people
    function getAllPeople() public view returns (Person[] memory) {
        return people;
    }
}
Beginner
8. What are enums in Solidity?

Enums define a set of named constants. They are used to represent a fixed set of states or options.

  • Definition: enum Status { Pending, Active, Inactive }
  • Usage: Status public status = Status.Pending
  • Values: uint8 representation
  • Comparison: status == Status.Active
  • Gas: Enums are gas efficient
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Enums in Solidity
contract Enums {
    // Enum definition
    enum Status {
        Pending,
        Active,
        Inactive,
        Suspended
    }
    
    enum Color {
        Red,
        Green,
        Blue
    }
    
    // Enum variable
    Status public status = Status.Pending;
    Color public color = Color.Red;
    
    // Enum in struct
    struct User {
        string name;
        Status status;
    }
    User[] public users;
    
    // Enum in mapping
    mapping(address => Status) public userStatus;
    
    // Set enum
    function setStatus(Status _status) public {
        status = _status;
    }
    
    // Get enum value
    function getStatus() public view returns (Status) {
        return status;
    }
    
    // Check enum
    function isActive() public view returns (bool) {
        return status == Status.Active;
    }
    
    // Enum in function
    function setUserStatus(address _user, Status _status) public {
        userStatus[_user] = _status;
    }
    
    // Create user with status
    function createUser(string memory _name, Status _status) public {
        users.push(User(_name, _status));
    }
    
    // Get user status
    function getUserStatus(uint256 _index) public view returns (Status) {
        return users[_index].status;
    }
}
Beginner
9. What is null safety in Solidity?

Solidity doesn't have null values. Instead, it uses default values for uninitialized variables and custom patterns for optional values.

  • Default values: 0, false, address(0)
  • Optional pattern: Struct with isSet flag
  • Address check: address != address(0)
  • Exists pattern: Mapping with existence check
  • Require: Validate before use
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Null Safety in Solidity
contract NullSafety {
    // Solidity doesn't have null, uses default values
    // Use custom patterns for null-like behavior
    
    // Default values
    uint256 public defaultUint; // 0
    bool public defaultBool; // false
    address public defaultAddress; // 0x0
    string public defaultString; // ""
    
    // Custom null pattern using struct
    struct OptionalUint {
        bool isSet;
        uint256 value;
    }
    OptionalUint public optionalValue;
    
    // Set optional value
    function setOptional(uint256 _value) public {
        optionalValue = OptionalUint(true, _value);
    }
    
    // Clear optional value
    function clearOptional() public {
        optionalValue.isSet = false;
    }
    
    // Get optional value with default
    function getOptional(uint256 _default) public view returns (uint256) {
        if (optionalValue.isSet) {
            return optionalValue.value;
        }
        return _default;
    }
    
    // Null check for address
    function isValidAddress(address _addr) public pure returns (bool) {
        return _addr != address(0);
    }
    
    // Using require for null checks
    function transfer(address _to, uint256 _amount) public {
        require(_to != address(0), "Invalid address");
        // Transfer logic
    }
    
    // Using mapping with exists pattern
    mapping(address => bool) public exists;
    
    function addAddress(address _addr) public {
        exists[_addr] = true;
    }
    
    function addressExists(address _addr) public view returns (bool) {
        return exists[_addr];
    }
}
Beginner
10. What are control flow statements in Solidity?

Solidity supports if-else, for loops, while loops, and ternary operators for control flow.

  • If-else: if (condition) { } else { }
  • For loop: for (uint i = 0; i < n; i++) { }
  • While loop: while (condition) { }
  • Do-while: do { } while (condition)
  • Ternary: condition ? value1 : value2
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Control Flow in Solidity
contract ControlFlow {
    // If-else
    function getStatus(uint256 _age) public pure returns (string memory) {
        if (_age < 18) {
            return "Minor";
        } else {
            return "Adult";
        }
    }
    
    // If-else-if
    function getGrade(uint8 _score) public pure returns (string memory) {
        if (_score >= 90) {
            return "A";
        } else if (_score >= 80) {
            return "B";
        } else if (_score >= 70) {
            return "C";
        } else {
            return "F";
        }
    }
    
    // For loop
    function sumArray(uint256[] memory _arr) public pure returns (uint256) {
        uint256 sum = 0;
        for (uint256 i = 0; i < _arr.length; i++) {
            sum += _arr[i];
        }
        return sum;
    }
    
    // While loop
    function countDown(uint256 _start) public pure returns (uint256[] memory) {
        uint256[] memory result = new uint256[](_start);
        uint256 i = 0;
        while (_start > 0) {
            result[i] = _start;
            _start--;
            i++;
        }
        return result;
    }
    
    // Do-while (using while with condition)
    function doWhileExample(uint256 _n) public pure returns (uint256) {
        uint256 sum = 0;
        uint256 i = 0;
        do {
            sum += i;
            i++;
        } while (i <= _n);
        return sum;
    }
    
    // Ternary operator
    function isEven(uint256 _num) public pure returns (bool) {
        return _num % 2 == 0 ? true : false;
    }
}
Beginner
11. What is inheritance in Solidity?

Inheritance allows contracts to derive from other contracts, inheriting their functions and state variables.

  • Single inheritance: contract Child is Parent
  • Multiple inheritance: contract Child is Parent1, Parent2
  • Constructor: Call parent constructor
  • Override: virtual and override
  • Interfaces: Define function signatures
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Inheritance in Solidity
// Base contract
contract Animal {
    string public name;
    
    constructor(string memory _name) {
        name = _name;
    }
    
    function makeSound() public view virtual returns (string memory) {
        return "Animal sound";
    }
}

// Derived contract (single inheritance)
contract Dog is Animal {
    string public breed;
    
    constructor(string memory _name, string memory _breed) Animal(_name) {
        breed = _breed;
    }
    
    function makeSound() public view override returns (string memory) {
        return "Woof!";
    }
}

// Multiple inheritance
contract Flyable {
    function fly() public pure returns (string memory) {
        return "Flying";
    }
}

contract Swimmable {
    function swim() public pure returns (string memory) {
        return "Swimming";
    }
}

contract Duck is Flyable, Swimmable {
    // Inherits from both
}

// Abstract contract
abstract contract Vehicle {
    function start() public virtual returns (string memory);
    
    function stop() public pure returns (string memory) {
        return "Stopped";
    }
}

contract Car is Vehicle {
    function start() public pure override returns (string memory) {
        return "Car started";
    }
}

// Interface
interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
}
Beginner
12. What are properties in Solidity?

Properties in Solidity are state variables with custom getters and setters implemented through functions.

  • State variables: Stored on blockchain
  • Getters: view functions
  • Setters: Functions with validation
  • Computed: view functions that calculate values
  • Lazy: Cache computed results
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Properties in Solidity
contract Properties {
    // State variables (properties)
    string public name;
    uint256 public age;
    address public owner;
    
    // Private variable with getter
    uint256 private _balance;
    
    // Constructor
    constructor() {
        owner = msg.sender;
        _balance = 0;
    }
    
    // Getter (view function)
    function getName() public view returns (string memory) {
        return name;
    }
    
    // Setter with validation
    function setName(string memory _name) public {
        require(bytes(_name).length > 0, "Name cannot be empty");
        name = _name;
    }
    
    // Setter with age validation
    function setAge(uint256 _age) public {
        require(_age >= 0 && _age <= 150, "Invalid age");
        age = _age;
    }
    
    // Read-only property
    function getBalance() public view returns (uint256) {
        return _balance;
    }
    
    // Computed property
    function getFullName() public view returns (string memory) {
        return string(abi.encodePacked(name, " (Age: ", uint2str(age), ")"));
    }
    
    // Lazy property (cached computation)
    uint256 private _expensiveData;
    bool private _expensiveDataComputed;
    
    function getExpensiveData() public returns (uint256) {
        if (!_expensiveDataComputed) {
            // Compute expensive data
            _expensiveData = block.number * 1000;
            _expensiveDataComputed = true;
        }
        return _expensiveData;
    }
    
    // Helper function
    function uint2str(uint256 _i) internal pure returns (string memory) {
        if (_i == 0) return "0";
        uint256 j = _i;
        uint256 len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint256 k = len;
        while (_i != 0) {
            k = k - 1;
            uint8 temp = (48 + uint8(_i - _i / 10 * 10));
            bytes1 b1 = bytes1(temp);
            bstr[k] = b1;
            _i /= 10;
        }
        return string(bstr);
    }
}
Intermediate
13. What are events and modifiers in Solidity?

Events emit data to the blockchain logs, and modifiers add reusable conditions to functions.

  • Events: event Transfer(address indexed from, address indexed to, uint256 amount)
  • Modifiers: modifier onlyOwner() { require(msg.sender == owner); _; }
  • Multiple modifiers: Chain modifiers on functions
  • Events logging: Emit events for off-chain tracking
  • Gas: Events are gas efficient
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Events and Modifiers
contract EventsModifiers {
    // Events
    event ValueChanged(address indexed changer, uint256 oldValue, uint256 newValue);
    event UserRegistered(address indexed user, string name);
    event Transfer(address indexed from, address indexed to, uint256 amount);
    
    // Modifiers
    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }
    
    modifier validAddress(address _addr) {
        require(_addr != address(0), "Invalid address");
        _;
    }
    
    modifier validAmount(uint256 _amount) {
        require(_amount > 0, "Amount must be greater than 0");
        _;
    }
    
    // State variables
    address public owner;
    uint256 public value;
    mapping(address => bool) public registered;
    
    constructor() {
        owner = msg.sender;
    }
    
    // Function with modifiers
    function setValue(uint256 _newValue) public onlyOwner {
        uint256 oldValue = value;
        value = _newValue;
        emit ValueChanged(msg.sender, oldValue, _newValue);
    }
    
    function registerUser(string memory _name) public {
        require(!registered[msg.sender], "Already registered");
        registered[msg.sender] = true;
        emit UserRegistered(msg.sender, _name);
    }
    
    function transfer(address _to, uint256 _amount) public 
        validAddress(_to)
        validAmount(_amount)
    {
        // Transfer logic
        emit Transfer(msg.sender, _to, _amount);
    }
    
    // Multiple modifiers
    function secureTransfer(address _to, uint256 _amount) public 
        onlyOwner
        validAddress(_to)
        validAmount(_amount)
    {
        // Transfer logic
    }
    
    // Modifier with parameters
    modifier minimumBalance(uint256 _min) {
        require(address(this).balance >= _min, "Insufficient balance");
        _;
    }
    
    function withdraw(uint256 _amount) public onlyOwner minimumBalance(_amount) {
        payable(msg.sender).transfer(_amount);
    }
}
Intermediate
14. How to handle errors in Solidity?

Solidity handles errors using require, revert, assert, and custom errors.

  • require: require(condition, "message")
  • revert: revert("message")
  • assert: assert(condition)
  • Custom errors: error InsufficientBalance(uint256 balance, uint256 requested)
  • Gas: Custom errors are more gas efficient
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Error Handling in Solidity
contract ErrorHandling {
    // Custom errors (gas efficient)
    error InsufficientBalance(uint256 balance, uint256 requested);
    error Unauthorized(address caller);
    error InvalidAmount(uint256 amount);
    error UserNotFound(address user);
    
    // State variables
    mapping(address => uint256) public balances;
    mapping(address => bool) public users;
    
    // Require statements
    function withdraw(uint256 _amount) public {
        require(balances[msg.sender] >= _amount, "Insufficient balance");
        require(_amount > 0, "Amount must be greater than 0");
        
        balances[msg.sender] -= _amount;
        payable(msg.sender).transfer(_amount);
    }
    
    // Custom error with require
    function withdrawCustom(uint256 _amount) public {
        if (balances[msg.sender] < _amount) {
            revert InsufficientBalance({
                balance: balances[msg.sender],
                requested: _amount
            });
        }
        if (_amount <= 0) {
            revert InvalidAmount(_amount);
        }
        
        balances[msg.sender] -= _amount;
        payable(msg.sender).transfer(_amount);
    }
    
    // Revert with custom error
    function transfer(address _to, uint256 _amount) public {
        if (balances[msg.sender] < _amount) {
            revert InsufficientBalance(balances[msg.sender], _amount);
        }
        if (_to == address(0)) {
            revert("Invalid address");
        }
        
        balances[msg.sender] -= _amount;
        balances[_to] += _amount;
    }
    
    // Try-catch (only for external calls)
    function safeCall(address _contract, uint256 _value) public {
        (bool success, ) = _contract.call{value: _value}("");
        if (!success) {
            // Handle failure
            revert("External call failed");
        }
    }
    
    // Assert for internal errors (gas cost)
    function assertExample(uint256 _a, uint256 _b) public pure returns (uint256) {
        assert(_b != 0);
        return _a / _b;
    }
}
Intermediate
15. What are function types in Solidity?

Function types allow functions to be passed as parameters and returned, enabling higher-order functions.

  • Function type: function(uint256) pure returns (uint256)
  • Parameters: Pass functions as arguments
  • Return: Return functions from functions
  • Internal/External: Function visibility matters
  • Usage: operate(a, b, add)
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Functions and Function Types
contract FunctionTypes {
    // Function types
    function add(uint256 a, uint256 b) public pure returns (uint256) {
        return a + b;
    }
    
    function subtract(uint256 a, uint256 b) public pure returns (uint256) {
        return a - b;
    }
    
    function multiply(uint256 a, uint256 b) public pure returns (uint256) {
        return a * b;
    }
    
    // Function as parameter
    function operate(
        uint256 a,
        uint256 b,
        function(uint256, uint256) pure returns (uint256) operation
    ) public pure returns (uint256) {
        return operation(a, b);
    }
    
    // Function returning function (using internal)
    function getOperation(string memory _type) public pure returns (function(uint256, uint256) pure returns (uint256)) {
        if (keccak256(abi.encodePacked(_type)) == keccak256(abi.encodePacked("add"))) {
            return add;
        } else if (keccak256(abi.encodePacked(_type)) == keccak256(abi.encodePacked("subtract"))) {
            return subtract;
        } else {
            return multiply;
        }
    }
    
    // Library-like functions
    function square(uint256 x) public pure returns (uint256) {
        return x * x;
    }
    
    function cube(uint256 x) public pure returns (uint256) {
        return x * x * x;
    }
    
    // Function composition
    function squareThenAdd(uint256 x, uint256 y) public pure returns (uint256) {
        return square(x) + y;
    }
    
    // Using function as variable
    function(uint256) pure returns (uint256) public squareFunc = square;
    
    function callSquare(uint256 x) public view returns (uint256) {
        return squareFunc(x);
    }
}
Intermediate
16. What are libraries in Solidity?

Libraries are reusable collections of functions that can be attached to types using using ... for ....

  • Library: library Math { function add(uint a, uint b) internal pure returns (uint) }
  • Using for: using Math for uint256
  • Pure functions: Libraries use pure/internal functions
  • Gas: Libraries are gas efficient
  • Deployment: Libraries can be deployed separately
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Libraries and Using For
library MathLib {
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }
    
    function subtract(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }
    
    function multiply(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }
    
    function divide(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "Division by zero");
        return a / b;
    }
}

library StringLib {
    function concat(string memory a, string memory b) internal pure returns (string memory) {
        return string(abi.encodePacked(a, b));
    }
    
    function length(string memory str) internal pure returns (uint256) {
        return bytes(str).length;
    }
}

contract UsingForExample {
    using MathLib for uint256;
    using StringLib for string;
    
    function calculate(uint256 a, uint256 b) public pure returns (uint256) {
        return a.add(b).multiply(2);
    }
    
    function combine(string memory a, string memory b) public pure returns (string memory) {
        return a.concat(b);
    }
    
    function getLength(string memory str) public pure returns (uint256) {
        return str.length();
    }
}

// Library with events (not allowed, libraries can't have state)
library EventLib {
    // Libraries cannot have state variables or events
}
Intermediate
17. What are custom modifiers?

Custom modifiers add reusable conditions and logic to functions, improving code modularity.

  • Definition: modifier name() { _; }
  • Parameters: Modifiers can take parameters
  • Multiple: Apply multiple modifiers
  • Inheritance: Modifiers can be overridden
  • Common: onlyOwner, whenNotPaused
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Modifiers and Custom Modifiers
contract CustomModifiers {
    // State variables
    address public owner;
    uint256 public value;
    bool public paused;
    
    // Events
    event ValueChanged(uint256 oldValue, uint256 newValue);
    event Paused(bool status);
    
    constructor() {
        owner = msg.sender;
        paused = false;
    }
    
    // Basic modifier
    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }
    
    // Modifier with parameter
    modifier validValue(uint256 _value) {
        require(_value > 0, "Value must be positive");
        _;
    }
    
    // Modifier with condition
    modifier whenNotPaused() {
        require(!paused, "Contract is paused");
        _;
    }
    
    // Modifier with multiple conditions
    modifier validAddress(address _addr) {
        require(_addr != address(0), "Invalid address");
        _;
    }
    
    // Modifier with complex logic
    modifier onlyWhen(bool _condition) {
        require(_condition, "Condition failed");
        _;
    }
    
    // Using modifiers
    function setValue(uint256 _newValue) public 
        onlyOwner 
        validValue(_newValue) 
        whenNotPaused 
    {
        uint256 oldValue = value;
        value = _newValue;
        emit ValueChanged(oldValue, _newValue);
    }
    
    function pause() public onlyOwner {
        paused = true;
        emit Paused(true);
    }
    
    function unpause() public onlyOwner {
        paused = false;
        emit Paused(false);
    }
    
    // Modifier inheritance
    modifier overrideModifier() virtual {
        _;
    }
    
    function overriddenFunction() public overrideModifier {
        // Function logic
    }
}

contract Child is CustomModifiers {
    // Override modifier
    modifier overrideModifier() override {
        // Additional logic
        _;
        // More logic
    }
}
Intermediate
18. What are events in Solidity?

Events allow logging of contract activity to the blockchain, enabling off-chain applications to track state changes.

  • Definition: event Transfer(address indexed from, address indexed to, uint256 amount)
  • Emit: emit Transfer(msg.sender, to, amount)
  • Indexed: indexed for filtering
  • Gas: Events are gas efficient
  • Anonymous: event Log(string message) anonymous
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Events in Solidity
contract EventsExample {
    // Event definitions
    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);
    event Log(string message, uint256 value);
    event UserRegistered(address indexed user, string name, uint256 timestamp);
    
    // State variables
    mapping(address => uint256) public balances;
    mapping(address => mapping(address => uint256)) public allowances;
    
    // Transfer function with event
    function transfer(address _to, uint256 _amount) public {
        require(balances[msg.sender] >= _amount, "Insufficient balance");
        require(_to != address(0), "Invalid address");
        
        balances[msg.sender] -= _amount;
        balances[_to] += _amount;
        
        emit Transfer(msg.sender, _to, _amount);
    }
    
    // Approve function with event
    function approve(address _spender, uint256 _amount) public {
        allowances[msg.sender][_spender] = _amount;
        emit Approval(msg.sender, _spender, _amount);
    }
    
    // Logging function
    function logMessage(string memory _message, uint256 _value) public {
        emit Log(_message, _value);
    }
    
    // Register user with event
    function registerUser(string memory _name) public {
        emit UserRegistered(msg.sender, _name, block.timestamp);
    }
    
    // Anonymous event (cheaper gas)
    event AnonymousLog(string message) anonymous;
    
    function anonymousLog(string memory _message) public {
        emit AnonymousLog(_message);
    }
}
Intermediate
19. What are interfaces in Solidity?

Interfaces define function signatures without implementations, enabling contract interaction and standards.

  • Definition: interface IERC20 { function totalSupply() external view returns (uint256); }
  • No implementation: Only function signatures
  • External: Functions are external
  • Standards: ERC-20, ERC-721, etc.
  • Interaction: Call functions on external contracts
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Inheritance and Interfaces
interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    
    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);
}

// Implementing interface
contract MyToken is IERC20 {
    string public name = "My Token";
    string public symbol = "MTK";
    uint8 public decimals = 18;
    uint256 private _totalSupply;
    mapping(address => uint256) private _balances;
    mapping(address => mapping(address => uint256)) private _allowances;
    
    constructor(uint256 initialSupply) {
        _totalSupply = initialSupply * 10**uint256(decimals);
        _balances[msg.sender] = _totalSupply;
    }
    
    function totalSupply() external view override returns (uint256) {
        return _totalSupply;
    }
    
    function balanceOf(address account) external view override returns (uint256) {
        return _balances[account];
    }
    
    function transfer(address recipient, uint256 amount) external override returns (bool) {
        require(recipient != address(0), "Invalid recipient");
        require(_balances[msg.sender] >= amount, "Insufficient balance");
        
        _balances[msg.sender] -= amount;
        _balances[recipient] += amount;
        emit Transfer(msg.sender, recipient, amount);
        return true;
    }
    
    function approve(address spender, uint256 amount) external override returns (bool) {
        _allowances[msg.sender][spender] = amount;
        emit Approval(msg.sender, spender, amount);
        return true;
    }
    
    function transferFrom(address sender, address recipient, uint256 amount) external override returns (bool) {
        require(sender != address(0), "Invalid sender");
        require(recipient != address(0), "Invalid recipient");
        require(_balances[sender] >= amount, "Insufficient balance");
        require(_allowances[sender][msg.sender] >= amount, "Insufficient allowance");
        
        _balances[sender] -= amount;
        _balances[recipient] += amount;
        _allowances[sender][msg.sender] -= amount;
        emit Transfer(sender, recipient, amount);
        return true;
    }
}
Intermediate
20. What are higher-order functions in Solidity?

Higher-order functions take functions as parameters or return functions, enabling functional programming patterns.

  • Function parameters: function operate(uint a, uint b, function(uint,uint) pure returns(uint) op)
  • Returning functions: function getMultiplier(uint factor) public pure returns (function(uint) pure returns(uint))
  • Composition: Combine multiple functions
  • Gas: Higher-order functions may cost more gas
  • Limitations: Function types in Solidity have limitations
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Higher-Order Functions and Function Composition
contract HigherOrderFunctions {
    // Function types
    function add(uint256 a, uint256 b) public pure returns (uint256) {
        return a + b;
    }
    
    function subtract(uint256 a, uint256 b) public pure returns (uint256) {
        return a - b;
    }
    
    function multiply(uint256 a, uint256 b) public pure returns (uint256) {
        return a * b;
    }
    
    // Function taking function as parameter
    function applyOperation(
        uint256 a,
        uint256 b,
        function(uint256, uint256) pure returns (uint256) operation
    ) public pure returns (uint256) {
        return operation(a, b);
    }
    
    // Function returning function
    function getMultiplier(uint256 factor) public pure returns (function(uint256) pure returns (uint256)) {
        return function(uint256 x) pure returns (uint256) {
            return x * factor;
        };
    }
    
    // Function composition
    function compose(
        function(uint256) pure returns (uint256) f,
        function(uint256) pure returns (uint256) g
    ) public pure returns (function(uint256) pure returns (uint256)) {
        return function(uint256 x) pure returns (uint256) {
            return f(g(x));
        };
    }
    
    // Square function
    function square(uint256 x) public pure returns (uint256) {
        return x * x;
    }
    
    // Add ten function
    function addTen(uint256 x) public pure returns (uint256) {
        return x + 10;
    }
    
    // Compose example
    function squareThenAddTen(uint256 x) public pure returns (uint256) {
        function(uint256) pure returns (uint256) f = this.addTen;
        function(uint256) pure returns (uint256) g = this.square;
        function(uint256) pure returns (uint256) composed = compose(f, g);
        return composed(x);
    }
}
Advanced
21. What are events and logging?

Events are the primary logging mechanism in Solidity, allowing contracts to emit data for off-chain consumption.

  • Events: Log contract activity
  • Parameters: Can be indexed for filtering
  • Gas: Events are gas efficient
  • Off-chain: Used by dApps and monitoring tools
  • Types: Regular and anonymous events
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Events and Logging
contract EventsLogging {
    // Events
    event Deposit(address indexed account, uint256 amount);
    event Withdraw(address indexed account, uint256 amount);
    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Log(string message, uint256 value);
    event Error(string message);
    
    // State
    mapping(address => uint256) public balances;
    
    // Deposit
    function deposit() public payable {
        balances[msg.sender] += msg.value;
        emit Deposit(msg.sender, msg.value);
    }
    
    // Withdraw
    function withdraw(uint256 _amount) public {
        require(balances[msg.sender] >= _amount, "Insufficient balance");
        balances[msg.sender] -= _amount;
        payable(msg.sender).transfer(_amount);
        emit Withdraw(msg.sender, _amount);
    }
    
    // Transfer
    function transfer(address _to, uint256 _amount) public {
        require(balances[msg.sender] >= _amount, "Insufficient balance");
        require(_to != address(0), "Invalid address");
        
        balances[msg.sender] -= _amount;
        balances[_to] += _amount;
        emit Transfer(msg.sender, _to, _amount);
    }
    
    // Logging
    function logValue(uint256 _value) public {
        emit Log("Value logged", _value);
    }
    
    // Error logging
    function logError(string memory _message) public {
        emit Error(_message);
    }
}
Advanced
22. What are modifiers and guards?

Modifiers provide reusable conditions for functions, implementing access control and validation patterns.

  • Access control: onlyOwner, onlyWhitelisted
  • State guards: whenNotPaused
  • Rate limiting: Time-based modifiers
  • Composition: Multiple modifiers can be combined
  • Parameters: Modifiers can accept parameters
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Modifiers and Guards
contract ModifiersGuards {
    // State
    address public owner;
    bool public paused;
    mapping(address => bool) public whitelist;
    mapping(address => uint256) public dailyLimit;
    mapping(address => uint256) public lastTxTime;
    
    // Events
    event Paused(bool status);
    event WhitelistUpdated(address indexed account, bool status);
    
    constructor() {
        owner = msg.sender;
        paused = false;
    }
    
    // Owner modifier
    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }
    
    // Pause modifier
    modifier whenNotPaused() {
        require(!paused, "Contract paused");
        _;
    }
    
    // Whitelist modifier
    modifier onlyWhitelisted() {
        require(whitelist[msg.sender], "Not whitelisted");
        _;
    }
    
    // Time-based modifier
    modifier rateLimit(uint256 _limit) {
        require(block.timestamp >= lastTxTime[msg.sender] + 1 hours, "Rate limited");
        lastTxTime[msg.sender] = block.timestamp;
        _;
    }
    
    // Balance modifier
    modifier hasBalance(uint256 _amount) {
        require(address(this).balance >= _amount, "Insufficient contract balance");
        _;
    }
    
    // Combined modifiers
    function transfer(address _to, uint256 _amount) public 
        whenNotPaused 
        onlyWhitelisted 
        rateLimit(1000)
        hasBalance(_amount)
    {
        // Transfer logic
    }
    
    // Admin functions
    function pause() public onlyOwner {
        paused = true;
        emit Paused(true);
    }
    
    function unpause() public onlyOwner {
        paused = false;
        emit Paused(false);
    }
    
    function updateWhitelist(address _account, bool _status) public onlyOwner {
        whitelist[_account] = _status;
        emit WhitelistUpdated(_account, _status);
    }
}
Advanced
23. What are libraries and helpers?

Libraries provide reusable functions that can be attached to types, improving code organization and gas efficiency.

  • Libraries: Deploy once, use many times
  • Internal functions: Inlined by compiler
  • Using for: Attach to types
  • Gas: More gas efficient than contracts
  • Helpers: Utility functions for common operations
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Libraries and Helpers
library SafeMath {
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }
    
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }
    
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }
    
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }
}

library AddressUtils {
    function isContract(address account) internal view returns (bool) {
        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }
    
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");
        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value");
    }
}

library StringUtils {
    function concat(string memory a, string memory b) internal pure returns (string memory) {
        return string(abi.encodePacked(a, b));
    }
    
    function compare(string memory a, string memory b) internal pure returns (bool) {
        return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b));
    }
}

contract UsingLibraries {
    using SafeMath for uint256;
    using AddressUtils for address;
    using StringUtils for string;
    
    uint256 public value;
    address public owner;
    
    constructor() {
        owner = msg.sender;
    }
    
    function addValue(uint256 _amount) public {
        value = value.add(_amount);
    }
    
    function subtractValue(uint256 _amount) public {
        value = value.sub(_amount);
    }
    
    function sendTo(address payable _to, uint256 _amount) public {
        require(msg.sender == owner, "Not owner");
        _to.sendValue(_amount);
    }
    
    function isContractAddress(address _addr) public view returns (bool) {
        return _addr.isContract();
    }
    
    function concatStrings(string memory a, string memory b) public pure returns (string memory) {
        return a.concat(b);
    }
}
Advanced
24. What are enums and structs?

Enums and structs are custom data types that help organize and structure contract data.

  • Enums: Fixed set of constants
  • Structs: Custom data containers
  • Nested: Structs can contain enums
  • Storage: Stored in arrays and mappings
  • Gas: Efficient for representing states
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Enums and Structs
contract EnumsStructs {
    // Enums
    enum Status {
        Pending,
        Active,
        Inactive,
        Suspended
    }
    
    enum OrderStatus {
        Created,
        Confirmed,
        Shipped,
        Delivered,
        Cancelled
    }
    
    // Structs
    struct User {
        string name;
        uint256 age;
        Status status;
        address wallet;
    }
    
    struct Product {
        uint256 id;
        string name;
        uint256 price;
        bool inStock;
    }
    
    struct Order {
        uint256 id;
        address customer;
        uint256[] productIds;
        uint256 total;
        OrderStatus status;
        uint256 timestamp;
    }
    
    // State
    User[] public users;
    Product[] public products;
    Order[] public orders;
    mapping(address => User) public userMap;
    
    // Events
    event UserCreated(address indexed user, string name);
    event OrderCreated(uint256 indexed orderId, address customer);
    event OrderStatusChanged(uint256 indexed orderId, OrderStatus status);
    
    // Create user
    function createUser(string memory _name, uint256 _age) public {
        User memory newUser = User({
            name: _name,
            age: _age,
            status: Status.Active,
            wallet: msg.sender
        });
        users.push(newUser);
        userMap[msg.sender] = newUser;
        emit UserCreated(msg.sender, _name);
    }
    
    // Create product
    function createProduct(string memory _name, uint256 _price) public {
        uint256 id = products.length;
        products.push(Product({
            id: id,
            name: _name,
            price: _price,
            inStock: true
        }));
    }
    
    // Create order
    function createOrder(uint256[] memory _productIds) public {
        uint256 total = 0;
        for (uint256 i = 0; i < _productIds.length; i++) {
            require(_productIds[i] < products.length, "Invalid product");
            require(products[_productIds[i]].inStock, "Product out of stock");
            total += products[_productIds[i]].price;
        }
        
        uint256 orderId = orders.length;
        orders.push(Order({
            id: orderId,
            customer: msg.sender,
            productIds: _productIds,
            total: total,
            status: OrderStatus.Created,
            timestamp: block.timestamp
        }));
        
        emit OrderCreated(orderId, msg.sender);
    }
    
    // Update order status
    function updateOrderStatus(uint256 _orderId, OrderStatus _status) public {
        require(_orderId < orders.length, "Order not found");
        require(orders[_orderId].customer == msg.sender, "Not owner");
        orders[_orderId].status = _status;
        emit OrderStatusChanged(_orderId, _status);
    }
    
    // Get user by address
    function getUser(address _addr) public view returns (string memory, uint256, Status) {
        User storage user = userMap[_addr];
        return (user.name, user.age, user.status);
    }
}
Advanced
25. What are mappings and iteration?

Mappings provide key-value storage but cannot be directly iterated. Use separate arrays for iteration.

  • Mapping: mapping(address => uint256) balances
  • Keys: Store keys in separate array
  • Iteration: Loop through keys array
  • Gas: Mappings are gas efficient for lookups
  • Nested: mapping(address => mapping(uint256 => bool)) permissions
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Mappings and Iteration
contract MappingsIteration {
    // Mappings
    mapping(address => uint256) public balances;
    mapping(address => bool) public exists;
    mapping(address => string) public names;
    mapping(uint256 => address) public idToAddress;
    mapping(address => mapping(uint256 => bool)) public permissions;
    
    // Arrays for iteration
    address[] public users;
    uint256[] public userIds;
    
    // Events
    event UserAdded(address indexed user, uint256 id);
    
    // Add user with balance
    function addUser(address _user, uint256 _balance) public {
        require(!exists[_user], "User already exists");
        exists[_user] = true;
        balances[_user] = _balance;
        users.push(_user);
        userIds.push(users.length);
        emit UserAdded(_user, users.length);
    }
    
    // Update balance
    function updateBalance(address _user, uint256 _balance) public {
        require(exists[_user], "User not found");
        balances[_user] = _balance;
    }
    
    // Get all users
    function getAllUsers() public view returns (address[] memory) {
        return users;
    }
    
    // Get user count
    function getUserCount() public view returns (uint256) {
        return users.length;
    }
    
    // Get user at index
    function getUserAtIndex(uint256 _index) public view returns (address) {
        require(_index < users.length, "Index out of bounds");
        return users[_index];
    }
    
    // Get all balances
    function getAllBalances() public view returns (uint256[] memory) {
        uint256[] memory allBalances = new uint256[](users.length);
        for (uint256 i = 0; i < users.length; i++) {
            allBalances[i] = balances[users[i]];
        }
        return allBalances;
    }
    
    // Nested mapping
    function setPermission(address _user, uint256 _resource, bool _allowed) public {
        permissions[_user][_resource] = _allowed;
    }
    
    function hasPermission(address _user, uint256 _resource) public view returns (bool) {
        return permissions[_user][_resource];
    }
}
Advanced
26. What is inheritance and polymorphism in Solidity?

Inheritance allows contracts to extend functionality, and polymorphism enables flexible contract interactions.

  • Inheritance: contract Child is Parent
  • Polymorphism: Different behaviors for same interface
  • Override: virtual and override
  • Abstract: Contracts with unimplemented functions
  • Interfaces: Standardized interactions
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Inheritance and Polymorphism
// Base contract
contract Token {
    string public name;
    string public symbol;
    uint8 public decimals;
    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    
    event Transfer(address indexed from, address indexed to, uint256 amount);
    
    constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _supply) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;
        totalSupply = _supply;
        balanceOf[msg.sender] = _supply;
    }
    
    function transfer(address _to, uint256 _amount) public virtual returns (bool) {
        require(balanceOf[msg.sender] >= _amount, "Insufficient balance");
        balanceOf[msg.sender] -= _amount;
        balanceOf[_to] += _amount;
        emit Transfer(msg.sender, _to, _amount);
        return true;
    }
}

// ERC20 Token (inheritance)
contract ERC20Token is Token {
    mapping(address => mapping(address => uint256)) public allowance;
    
    event Approval(address indexed owner, address indexed spender, uint256 amount);
    
    constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _supply)
        Token(_name, _symbol, _decimals, _supply)
    {}
    
    function approve(address _spender, uint256 _amount) public returns (bool) {
        allowance[msg.sender][_spender] = _amount;
        emit Approval(msg.sender, _spender, _amount);
        return true;
    }
    
    function transferFrom(address _from, address _to, uint256 _amount) public returns (bool) {
        require(allowance[_from][msg.sender] >= _amount, "Insufficient allowance");
        allowance[_from][msg.sender] -= _amount;
        require(balanceOf[_from] >= _amount, "Insufficient balance");
        balanceOf[_from] -= _amount;
        balanceOf[_to] += _amount;
        emit Transfer(_from, _to, _amount);
        return true;
    }
}

// Burnable Token (polymorphism)
contract BurnableToken is ERC20Token {
    event Burn(address indexed from, uint256 amount);
    
    constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _supply)
        ERC20Token(_name, _symbol, _decimals, _supply)
    {}
    
    function burn(uint256 _amount) public {
        require(balanceOf[msg.sender] >= _amount, "Insufficient balance");
        balanceOf[msg.sender] -= _amount;
        totalSupply -= _amount;
        emit Burn(msg.sender, _amount);
    }
}
Advanced
27. What is the factory pattern in Solidity?

Factory pattern creates new contract instances, enabling deployment of multiple copies with different parameters.

  • Factory: Contract that creates other contracts
  • Create: Use new keyword
  • Tracking: Store created instances
  • Deployment: Deploy child contracts
  • Gas: Factory pattern can be gas efficient
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Factory Pattern
contract TokenFactory {
    // Events
    event TokenCreated(address indexed token, string name, string symbol);
    
    // Token contract (simple version)
    contract SimpleToken {
        string public name;
        string public symbol;
        uint256 public totalSupply;
        mapping(address => uint256) public balanceOf;
        
        constructor(string memory _name, string memory _symbol, uint256 _supply) {
            name = _name;
            symbol = _symbol;
            totalSupply = _supply;
            balanceOf[msg.sender] = _supply;
        }
        
        function transfer(address _to, uint256 _amount) public returns (bool) {
            require(balanceOf[msg.sender] >= _amount, "Insufficient balance");
            balanceOf[msg.sender] -= _amount;
            balanceOf[_to] += _amount;
            return true;
        }
    }
    
    // Create token
    function createToken(string memory _name, string memory _symbol, uint256 _supply) public returns (address) {
        SimpleToken token = new SimpleToken(_name, _symbol, _supply);
        emit TokenCreated(address(token), _name, _symbol);
        return address(token);
    }
    
    // Create token with salt (deterministic)
    function createTokenWithSalt(string memory _name, string memory _symbol, uint256 _supply, bytes32 _salt) public returns (address) {
        bytes memory bytecode = type(SimpleToken).creationCode;
        bytes32 hash = keccak256(abi.encodePacked(bytecode, _salt));
        address addr = address(uint160(uint256(hash)));
        // This is a simplified version - in practice, use CREATE2
        return addr;
    }
}
Advanced
28. What is the strategy pattern in Solidity?

Strategy pattern allows switching algorithms at runtime using interfaces and dynamic dispatch.

  • Interface: Define strategy interface
  • Strategies: Different implementations
  • Context: Uses current strategy
  • Dynamic: Change strategy at runtime
  • Flexibility: Swap algorithms without changing context
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Strategy Pattern
contract StrategyPattern {
    // Strategy interface
    interface IPaymentStrategy {
        function pay(address payer, uint256 amount) external returns (bool);
    }
    
    // Concrete strategies
    contract CreditCardStrategy is IPaymentStrategy {
        function pay(address payer, uint256 amount) external pure override returns (bool) {
            // Credit card payment logic
            return true;
        }
    }
    
    contract PayPalStrategy is IPaymentStrategy {
        function pay(address payer, uint256 amount) external pure override returns (bool) {
            // PayPal payment logic
            return true;
        }
    }
    
    contract CryptoStrategy is IPaymentStrategy {
        function pay(address payer, uint256 amount) external pure override returns (bool) {
            // Crypto payment logic
            return true;
        }
    }
    
    // Context
    address public paymentStrategy;
    
    function setStrategy(address _strategy) public {
        require(_strategy != address(0), "Invalid strategy");
        paymentStrategy = _strategy;
    }
    
    function executePayment(uint256 _amount) public returns (bool) {
        require(paymentStrategy != address(0), "Strategy not set");
        IPaymentStrategy strategy = IPaymentStrategy(paymentStrategy);
        return strategy.pay(msg.sender, _amount);
    }
}
Advanced
29. What is the observer pattern in Solidity?

Observer pattern is implemented using events and listener contracts for notification-based communication.

  • Events: Emit notifications
  • Observers: Contracts that listen
  • Registration: Add/remove observers
  • Notification: Emit events on state change
  • Decoupling: Loose coupling between components
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Observer Pattern (Events)
contract ObserverPattern {
    // Events as observer notifications
    event StateChanged(address indexed changer, uint256 oldValue, uint256 newValue);
    event UserUpdated(address indexed user, string oldName, string newName);
    event BalanceChanged(address indexed account, uint256 newBalance);
    
    // State
    uint256 public value;
    mapping(address => string) public userNames;
    mapping(address => uint256) public balances;
    
    // Observers list (simplified)
    address[] public observers;
    mapping(address => bool) public isObserver;
    
    // Add observer
    function addObserver(address _observer) public {
        require(!isObserver[_observer], "Already observer");
        isObserver[_observer] = true;
        observers.push(_observer);
    }
    
    // Remove observer
    function removeObserver(address _observer) public {
        require(isObserver[_observer], "Not observer");
        isObserver[_observer] = false;
        // Remove from array (simplified)
    }
    
    // Notify observers (simplified)
    function notifyObservers(string memory _message) internal {
        // In practice, observers would be contracts with callback functions
        for (uint256 i = 0; i < observers.length; i++) {
            if (isObserver[observers[i]]) {
                // Call observer contract
            }
        }
    }
    
    // Update state with events
    function setValue(uint256 _newValue) public {
        uint256 oldValue = value;
        value = _newValue;
        emit StateChanged(msg.sender, oldValue, _newValue);
    }
    
    function updateUser(string memory _newName) public {
        string memory oldName = userNames[msg.sender];
        userNames[msg.sender] = _newName;
        emit UserUpdated(msg.sender, oldName, _newName);
    }
    
    function updateBalance(uint256 _newBalance) public {
        balances[msg.sender] = _newBalance;
        emit BalanceChanged(msg.sender, _newBalance);
    }
}
Advanced
30. What is the state pattern in Solidity?

State pattern manages contract behavior based on current state using enums and state-specific logic.

  • States: Defined as enum
  • Transitions: Change state with validation
  • Behavior: Functions behave based on state
  • Modifiers: Restrict to certain states
  • Events: Emit on state changes
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// State Pattern
contract StatePattern {
    // States
    enum State {
        Idle,
        Processing,
        Completed,
        Cancelled
    }
    
    // State variables
    State public currentState = State.Idle;
    address public owner;
    uint256 public value;
    
    // Events
    event StateTransition(State from, State to);
    
    constructor() {
        owner = msg.sender;
    }
    
    // State transitions
    modifier onlyInState(State _state) {
        require(currentState == _state, "Invalid state");
        _;
    }
    
    function startProcessing() public onlyInState(State.Idle) {
        currentState = State.Processing;
        emit StateTransition(State.Idle, State.Processing);
    }
    
    function complete() public onlyInState(State.Processing) {
        currentState = State.Completed;
        emit StateTransition(State.Processing, State.Completed);
    }
    
    function cancel() public onlyInState(State.Idle) {
        currentState = State.Cancelled;
        emit StateTransition(State.Idle, State.Cancelled);
    }
    
    function reset() public {
        require(msg.sender == owner, "Not owner");
        currentState = State.Idle;
        emit StateTransition(State.Completed, State.Idle);
    }
    
    // State-dependent behavior
    function getStatus() public view returns (string memory) {
        if (currentState == State.Idle) {
            return "Idle - Ready to start";
        } else if (currentState == State.Processing) {
            return "Processing - Working on task";
        } else if (currentState == State.Completed) {
            return "Completed - Task finished";
        } else {
            return "Cancelled - Task cancelled";
        }
    }
}
Coding Round
31. Reverse a string

Reverse a string using bytes conversion and manual iteration.

  • bytes conversion: bytes(str)
  • Manual: Iterate from end to start
  • Complexity: O(n) time
  • Memory: Uses memory for string
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Reverse a string in Solidity
contract StringReverse {
    function reverseString(string memory _str) public pure returns (string memory) {
        bytes memory strBytes = bytes(_str);
        bytes memory reversed = new bytes(strBytes.length);
        for (uint256 i = 0; i < strBytes.length; i++) {
            reversed[i] = strBytes[strBytes.length - 1 - i];
        }
        return string(reversed);
    }
}
Coding Round
32. Check palindrome

Check if a string is a palindrome using two-pointer approach on bytes.

  • Two-pointer: Compare from both ends
  • bytes conversion: bytes(str)
  • Case sensitive: Solidity strings are case sensitive
  • Complexity: O(n) time
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Check palindrome in Solidity
contract Palindrome {
    function isPalindrome(string memory _str) public pure returns (bool) {
        bytes memory strBytes = bytes(_str);
        for (uint256 i = 0; i < strBytes.length / 2; i++) {
            if (strBytes[i] != strBytes[strBytes.length - 1 - i]) {
                return false;
            }
        }
        return true;
    }
}
Coding Round
33. Find max in array

Find maximum value using manual iteration.

  • Manual: Iterate and track max
  • Empty array: Use require check
  • Complexity: O(n) time
  • Return: Maximum value
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Find max in array in Solidity
contract ArrayMax {
    function findMax(uint256[] memory _arr) public pure returns (uint256) {
        require(_arr.length > 0, "Array is empty");
        uint256 max = _arr[0];
        for (uint256 i = 1; i < _arr.length; i++) {
            if (_arr[i] > max) {
                max = _arr[i];
            }
        }
        return max;
    }
}
Coding Round
34. Remove duplicates

Remove duplicates using nested loops and temporary array.

  • Nested loops: Check for duplicates
  • Temporary array: Store unique elements
  • Complexity: O(n²) time
  • Return: Array without duplicates
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Remove duplicates in Solidity
contract RemoveDuplicates {
    function removeDuplicates(uint256[] memory _arr) public pure returns (uint256[] memory) {
        if (_arr.length <= 1) {
            return _arr;
        }
        
        uint256 uniqueCount = 0;
        for (uint256 i = 0; i < _arr.length; i++) {
            bool isDuplicate = false;
            for (uint256 j = 0; j < i; j++) {
                if (_arr[i] == _arr[j]) {
                    isDuplicate = true;
                    break;
                }
            }
            if (!isDuplicate) {
                uniqueCount++;
            }
        }
        
        uint256[] memory result = new uint256[](uniqueCount);
        uint256 index = 0;
        for (uint256 i = 0; i < _arr.length; i++) {
            bool isDuplicate = false;
            for (uint256 j = 0; j < i; j++) {
                if (_arr[i] == _arr[j]) {
                    isDuplicate = true;
                    break;
                }
            }
            if (!isDuplicate) {
                result[index] = _arr[i];
                index++;
            }
        }
        return result;
    }
}
Coding Round
35. Merge arrays

Merge arrays using a new array with combined length.

  • New array: Create with combined length
  • Loop: Copy elements from both arrays
  • Complexity: O(n) time
  • Return: Merged array
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Merge arrays in Solidity
contract ArrayMerge {
    function mergeArrays(uint256[] memory _arr1, uint256[] memory _arr2) public pure returns (uint256[] memory) {
        uint256[] memory result = new uint256[](_arr1.length + _arr2.length);
        for (uint256 i = 0; i < _arr1.length; i++) {
            result[i] = _arr1[i];
        }
        for (uint256 i = 0; i < _arr2.length; i++) {
            result[_arr1.length + i] = _arr2[i];
        }
        return result;
    }
}
Coding Round
36. Convert string to number

Convert string to number by iterating through bytes.

  • bytes conversion: bytes(str)
  • ASCII values: Check for valid digits
  • Manual: Build number digit by digit
  • Error handling: Revert on invalid input
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Convert string to number in Solidity
contract StringToNumber {
    function stringToUint(string memory _str) public pure returns (uint256) {
        bytes memory strBytes = bytes(_str);
        uint256 result = 0;
        for (uint256 i = 0; i < strBytes.length; i++) {
            require(strBytes[i] >= 48 && strBytes[i] <= 57, "Invalid character");
            result = result * 10 + uint256(uint8(strBytes[i] - 48));
        }
        return result;
    }
}
Coding Round
37. Loop through mapping

Loop through mapping using separate array for keys.

  • Keys array: Store keys for iteration
  • Mapping: Store values by key
  • Manual: Iterate through keys array
  • Return: Array of values
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Loop through mapping in Solidity
contract MappingIteration {
    mapping(address => uint256) public balances;
    address[] public users;
    
    function addUser(address _user, uint256 _balance) public {
        balances[_user] = _balance;
        users.push(_user);
    }
    
    function getAllBalances() public view returns (address[] memory, uint256[] memory) {
        uint256[] memory allBalances = new uint256[](users.length);
        for (uint256 i = 0; i < users.length; i++) {
            allBalances[i] = balances[users[i]];
        }
        return (users, allBalances);
    }
}
Coding Round
38. Delay function execution

Delay execution using schedule pattern with timestamp checks.

  • Schedule: Store call with execution time
  • Execute: Check if time has passed
  • State: Track execution status
  • Events: Emit on schedule/execute
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Delay function execution in Solidity
contract DelayedExecution {
    struct DelayedCall {
        address target;
        bytes data;
        uint256 delay;
        uint256 executeAt;
        bool executed;
    }
    
    DelayedCall[] public delayedCalls;
    
    event CallScheduled(uint256 indexed id, address target, uint256 delay);
    event CallExecuted(uint256 indexed id);
    
    function scheduleCall(address _target, bytes memory _data, uint256 _delay) public returns (uint256) {
        uint256 id = delayedCalls.length;
        delayedCalls.push(DelayedCall({
            target: _target,
            data: _data,
            delay: _delay,
            executeAt: block.timestamp + _delay,
            executed: false
        }));
        emit CallScheduled(id, _target, _delay);
        return id;
    }
    
    function executeCall(uint256 _id) public {
        require(_id < delayedCalls.length, "Invalid id");
        DelayedCall storage call = delayedCalls[_id];
        require(!call.executed, "Already executed");
        require(block.timestamp >= call.executeAt, "Not ready");
        
        (bool success, ) = call.target.call(call.data);
        require(success, "Call failed");
        call.executed = true;
        emit CallExecuted(_id);
    }
}
Coding Round
39. HTTP GET request

HTTP requests in Solidity are made through oracles like Chainlink.

  • Oracles: Chainlink, API3
  • External data: Fetch off-chain data
  • Trust model: Oracle trust assumptions
  • Implementation: Use oracle contracts
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// HTTP GET request (using Oracles)
// Note: Solidity cannot make HTTP requests directly
contract HttpRequest {
    // This is a simplified example using Chainlink
    // In practice, you would use Chainlink oracles
}
Coding Round
40. Promise-like Deferred pattern

Create a promise-like pattern using structs for deferred execution.

  • Struct: Store resolved/rejected state
  • Functions: resolve, reject, check status
  • Events: Emit on resolution/rejection
  • State: Track in contract storage
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Promise-like pattern in Solidity
contract DeferredPattern {
    struct Deferred {
        bool resolved;
        bool rejected;
        bytes result;
        bytes error;
    }
    
    mapping(uint256 => Deferred) public deferreds;
    uint256 public deferredCount;
    
    event DeferredCreated(uint256 indexed id);
    event DeferredResolved(uint256 indexed id, bytes result);
    event DeferredRejected(uint256 indexed id, bytes error);
    
    function createDeferred() public returns (uint256) {
        uint256 id = deferredCount++;
        deferreds[id] = Deferred(false, false, "", "");
        emit DeferredCreated(id);
        return id;
    }
    
    function resolve(uint256 _id, bytes memory _result) public {
        require(!deferreds[_id].resolved && !deferreds[_id].rejected, "Already resolved");
        deferreds[_id].resolved = true;
        deferreds[_id].result = _result;
        emit DeferredResolved(_id, _result);
    }
    
    function reject(uint256 _id, bytes memory _error) public {
        require(!deferreds[_id].resolved && !deferreds[_id].rejected, "Already resolved");
        deferreds[_id].rejected = true;
        deferreds[_id].error = _error;
        emit DeferredRejected(_id, _error);
    }
    
    function getStatus(uint256 _id) public view returns (bool resolved, bool rejected, bytes memory result, bytes memory error) {
        Deferred storage d = deferreds[_id];
        return (d.resolved, d.rejected, d.result, d.error);
    }
}
Coding Round
41. Factorial

Calculate factorial using recursion.

  • Recursive: n * factorial(n-1)
  • Base case: n <= 1
  • Gas: Recursion can be gas intensive
  • Edge cases: 0! = 1
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Factorial in Solidity
contract Factorial {
    function factorial(uint256 n) public pure returns (uint256) {
        if (n <= 1) {
            return 1;
        }
        return n * factorial(n - 1);
    }
}
Coding Round
42. Fibonacci

Calculate Fibonacci using recursion or iteration.

  • Recursive: fib(n-1) + fib(n-2)
  • Iterative: Loop with variables
  • Gas: Iterative is more gas efficient
  • Complexity: O(n) iterative
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Fibonacci in Solidity
contract Fibonacci {
    function fibonacci(uint256 n) public pure returns (uint256) {
        if (n <= 1) {
            return n;
        }
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
    
    function fibonacciIterative(uint256 n) public pure returns (uint256) {
        if (n <= 1) {
            return n;
        }
        uint256 a = 0;
        uint256 b = 1;
        for (uint256 i = 2; i <= n; i++) {
            uint256 c = a + b;
            a = b;
            b = c;
        }
        return b;
    }
}
Coding Round
43. FizzBuzz

FizzBuzz using if-else with modulo operations.

  • Modulo: Check divisibility by 3, 5, 15
  • Order: Check 15 first
  • Return: Array of strings
  • Helper: Convert uint to string
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// FizzBuzz in Solidity
contract FizzBuzz {
    function fizzbuzz(uint256 n) public pure returns (string[] memory) {
        string[] memory result = new string[](n);
        for (uint256 i = 1; i <= n; i++) {
            if (i % 15 == 0) {
                result[i-1] = "FizzBuzz";
            } else if (i % 3 == 0) {
                result[i-1] = "Fizz";
            } else if (i % 5 == 0) {
                result[i-1] = "Buzz";
            } else {
                result[i-1] = uint2str(i);
            }
        }
        return result;
    }
    
    function uint2str(uint256 _i) internal pure returns (string memory) {
        if (_i == 0) return "0";
        uint256 j = _i;
        uint256 len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint256 k = len;
        while (_i != 0) {
            k = k - 1;
            uint8 temp = (48 + uint8(_i - _i / 10 * 10));
            bytes1 b1 = bytes1(temp);
            bstr[k] = b1;
            _i /= 10;
        }
        return string(bstr);
    }
}
Coding Round
44. Find missing number

Find missing number using formula n*(n+1)/2 - sum.

  • Formula: total - sum
  • Edge cases: Empty array, missing first or last
  • Complexity: O(n) time
  • Return: Missing number
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Find missing number in Solidity
contract MissingNumber {
    function findMissing(uint256[] memory _arr) public pure returns (uint256) {
        uint256 n = _arr.length + 1;
        uint256 total = n * (n + 1) / 2;
        uint256 sum = 0;
        for (uint256 i = 0; i < _arr.length; i++) {
            sum += _arr[i];
        }
        return total - sum;
    }
}
Coding Round
45. Find duplicates

Find duplicates using nested loops.

  • Nested loops: Compare each element
  • Dedup: Avoid adding duplicates multiple times
  • Complexity: O(n²) time
  • Return: Array of duplicates
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Find duplicates in Solidity
contract FindDuplicates {
    function findDuplicates(uint256[] memory _arr) public pure returns (uint256[] memory) {
        uint256[] memory duplicates = new uint256[](_arr.length);
        uint256 count = 0;
        for (uint256 i = 0; i < _arr.length; i++) {
            bool isDuplicate = false;
            for (uint256 j = i + 1; j < _arr.length; j++) {
                if (_arr[i] == _arr[j]) {
                    isDuplicate = true;
                    break;
                }
            }
            if (isDuplicate) {
                bool alreadyAdded = false;
                for (uint256 k = 0; k < count; k++) {
                    if (duplicates[k] == _arr[i]) {
                        alreadyAdded = true;
                        break;
                    }
                }
                if (!alreadyAdded) {
                    duplicates[count] = _arr[i];
                    count++;
                }
            }
        }
        // Truncate array
        uint256[] memory result = new uint256[](count);
        for (uint256 i = 0; i < count; i++) {
            result[i] = duplicates[i];
        }
        return result;
    }
}
Coding Round
46. Sum of array

Calculate sum using loop iteration.

  • Loop: Iterate and accumulate
  • Complexity: O(n) time
  • Return: Sum value
  • Gas: Memory vs storage consideration
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Sum of array in Solidity
contract SumArray {
    function sumArray(uint256[] memory _arr) public pure returns (uint256) {
        uint256 sum = 0;
        for (uint256 i = 0; i < _arr.length; i++) {
            sum += _arr[i];
        }
        return sum;
    }
}
Coding Round
47. Average of array

Calculate average using sum divided by length.

  • Method: sum / length
  • Empty array: Use require check
  • Precision: Integer division truncates
  • Return: Average value
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Average of array in Solidity
contract AverageArray {
    function averageArray(uint256[] memory _arr) public pure returns (uint256) {
        require(_arr.length > 0, "Array is empty");
        uint256 sum = 0;
        for (uint256 i = 0; i < _arr.length; i++) {
            sum += _arr[i];
        }
        return sum / _arr.length;
    }
}
Coding Round
48. Sort array ascending

Sort ascending using bubble sort.

  • Bubble sort: Compare adjacent, swap
  • Complexity: O(n²) time
  • In-place: Modifies array in memory
  • Return: Sorted array
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Sort array ascending in Solidity
contract SortArray {
    function sortAscending(uint256[] memory _arr) public pure returns (uint256[] memory) {
        uint256[] memory sorted = new uint256[](_arr.length);
        for (uint256 i = 0; i < _arr.length; i++) {
            sorted[i] = _arr[i];
        }
        for (uint256 i = 0; i < sorted.length - 1; i++) {
            for (uint256 j = 0; j < sorted.length - i - 1; j++) {
                if (sorted[j] > sorted[j + 1]) {
                    uint256 temp = sorted[j];
                    sorted[j] = sorted[j + 1];
                    sorted[j + 1] = temp;
                }
            }
        }
        return sorted;
    }
}
Coding Round
49. Sort array descending

Sort descending using bubble sort with reversed comparison.

  • Bubble sort: Compare adjacent, swap if less
  • Complexity: O(n²) time
  • In-place: Modifies array in memory
  • Return: Sorted array
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Sort array descending in Solidity
contract SortArrayDescending {
    function sortDescending(uint256[] memory _arr) public pure returns (uint256[] memory) {
        uint256[] memory sorted = new uint256[](_arr.length);
        for (uint256 i = 0; i < _arr.length; i++) {
            sorted[i] = _arr[i];
        }
        for (uint256 i = 0; i < sorted.length - 1; i++) {
            for (uint256 j = 0; j < sorted.length - i - 1; j++) {
                if (sorted[j] < sorted[j + 1]) {
                    uint256 temp = sorted[j];
                    sorted[j] = sorted[j + 1];
                    sorted[j + 1] = temp;
                }
            }
        }
        return sorted;
    }
}
Coding Round
50. Flatten nested array

Flatten a 2D array using nested loops.

  • Nested loops: Iterate through sub-arrays
  • Length: Calculate total length first
  • Complexity: O(n) time
  • Return: Flattened array
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Flatten nested array in Solidity
contract FlattenArray {
    function flattenArray(uint256[][] memory _arr) public pure returns (uint256[] memory) {
        uint256 totalLength = 0;
        for (uint256 i = 0; i < _arr.length; i++) {
            totalLength += _arr[i].length;
        }
        uint256[] memory result = new uint256[](totalLength);
        uint256 index = 0;
        for (uint256 i = 0; i < _arr.length; i++) {
            for (uint256 j = 0; j < _arr[i].length; j++) {
                result[index] = _arr[i][j];
                index++;
            }
        }
        return result;
    }
}
Coding Round
51. Chunk array

Split array into chunks of given size.

  • Loop: Iterate with step size
  • Slicing: Copy elements per chunk
  • Edge case: Handle last chunk size
  • Return: 2D array of chunks
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Chunk array in Solidity
contract ChunkArray {
    function chunkArray(uint256[] memory _arr, uint256 _size) public pure returns (uint256[][] memory) {
        require(_size > 0, "Size must be > 0");
        uint256 chunks = (_arr.length + _size - 1) / _size;
        uint256[][] memory result = new uint256[][](chunks);
        for (uint256 i = 0; i < chunks; i++) {
            uint256 start = i * _size;
            uint256 end = start + _size;
            if (end > _arr.length) {
                end = _arr.length;
            }
            uint256[] memory chunk = new uint256[](end - start);
            for (uint256 j = start; j < end; j++) {
                chunk[j - start] = _arr[j];
            }
            result[i] = chunk;
        }
        return result;
    }
}
Coding Round
53. Quick sort

Quick sort using recursion and partitioning.

  • Algorithm: Choose pivot, partition, recurse
  • Time: O(n log n) average
  • Memory: Creates new arrays
  • Return: Sorted array
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Quick sort in Solidity
contract QuickSort {
    function quickSort(uint256[] memory _arr) public pure returns (uint256[] memory) {
        if (_arr.length <= 1) {
            return _arr;
        }
        uint256 pivot = _arr[0];
        uint256[] memory left = new uint256[](_arr.length);
        uint256[] memory right = new uint256[](_arr.length);
        uint256 leftCount = 0;
        uint256 rightCount = 0;
        for (uint256 i = 1; i < _arr.length; i++) {
            if (_arr[i] < pivot) {
                left[leftCount] = _arr[i];
                leftCount++;
            } else {
                right[rightCount] = _arr[i];
                rightCount++;
            }
        }
        // Trim arrays
        uint256[] memory leftTrimmed = new uint256[](leftCount);
        for (uint256 i = 0; i < leftCount; i++) {
            leftTrimmed[i] = left[i];
        }
        uint256[] memory rightTrimmed = new uint256[](rightCount);
        for (uint256 i = 0; i < rightCount; i++) {
            rightTrimmed[i] = right[i];
        }
        
        uint256[] memory leftSorted = quickSort(leftTrimmed);
        uint256[] memory rightSorted = quickSort(rightTrimmed);
        
        uint256[] memory result = new uint256[](leftCount + 1 + rightCount);
        for (uint256 i = 0; i < leftCount; i++) {
            result[i] = leftSorted[i];
        }
        result[leftCount] = pivot;
        for (uint256 i = 0; i < rightCount; i++) {
            result[leftCount + 1 + i] = rightSorted[i];
        }
        return result;
    }
}
Coding Round
54. Merge sort

Merge sort using divide-and-conquer and merging.

  • Algorithm: Divide, sort, merge
  • Time: O(n log n)
  • Space: O(n) auxiliary space
  • Return: Sorted array
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Merge sort in Solidity
contract MergeSort {
    function mergeSort(uint256[] memory _arr) public pure returns (uint256[] memory) {
        if (_arr.length <= 1) {
            return _arr;
        }
        uint256 mid = _arr.length / 2;
        uint256[] memory left = new uint256[](mid);
        uint256[] memory right = new uint256[](_arr.length - mid);
        for (uint256 i = 0; i < mid; i++) {
            left[i] = _arr[i];
        }
        for (uint256 i = mid; i < _arr.length; i++) {
            right[i - mid] = _arr[i];
        }
        uint256[] memory leftSorted = mergeSort(left);
        uint256[] memory rightSorted = mergeSort(right);
        return merge(leftSorted, rightSorted);
    }
    
    function merge(uint256[] memory _left, uint256[] memory _right) public pure returns (uint256[] memory) {
        uint256[] memory result = new uint256[](_left.length + _right.length);
        uint256 i = 0;
        uint256 j = 0;
        uint256 k = 0;
        while (i < _left.length && j < _right.length) {
            if (_left[i] <= _right[j]) {
                result[k] = _left[i];
                i++;
            } else {
                result[k] = _right[j];
                j++;
            }
            k++;
        }
        while (i < _left.length) {
            result[k] = _left[i];
            i++;
            k++;
        }
        while (j < _right.length) {
            result[k] = _right[j];
            j++;
            k++;
        }
        return result;
    }
}
Coding Round
55. Bubble sort

Bubble sort with early termination.

  • Algorithm: Compare adjacent, swap
  • Time: O(n²) worst case
  • Optimization: Stop if no swaps
  • Return: Sorted array
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Bubble sort in Solidity
contract BubbleSort {
    function bubbleSort(uint256[] memory _arr) public pure returns (uint256[] memory) {
        uint256[] memory sorted = new uint256[](_arr.length);
        for (uint256 i = 0; i < _arr.length; i++) {
            sorted[i] = _arr[i];
        }
        for (uint256 i = 0; i < sorted.length - 1; i++) {
            bool swapped = false;
            for (uint256 j = 0; j < sorted.length - i - 1; j++) {
                if (sorted[j] > sorted[j + 1]) {
                    uint256 temp = sorted[j];
                    sorted[j] = sorted[j + 1];
                    sorted[j + 1] = temp;
                    swapped = true;
                }
            }
            if (!swapped) {
                break;
            }
        }
        return sorted;
    }
}
Coding Round
56. Intersection of arrays

Find common elements using nested loops.

  • Nested loops: Compare elements
  • Dedup: Avoid adding duplicates
  • Complexity: O(n*m) time
  • Return: Array of common elements
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Intersection of arrays in Solidity
contract ArrayIntersection {
    function intersection(uint256[] memory _arr1, uint256[] memory _arr2) public pure returns (uint256[] memory) {
        uint256[] memory temp = new uint256[](_arr1.length);
        uint256 count = 0;
        for (uint256 i = 0; i < _arr1.length; i++) {
            bool found = false;
            for (uint256 j = 0; j < _arr2.length; j++) {
                if (_arr1[i] == _arr2[j]) {
                    found = true;
                    break;
                }
            }
            if (found) {
                bool duplicate = false;
                for (uint256 k = 0; k < count; k++) {
                    if (temp[k] == _arr1[i]) {
                        duplicate = true;
                        break;
                    }
                }
                if (!duplicate) {
                    temp[count] = _arr1[i];
                    count++;
                }
            }
        }
        uint256[] memory result = new uint256[](count);
        for (uint256 i = 0; i < count; i++) {
            result[i] = temp[i];
        }
        return result;
    }
}
Coding Round
57. Union of arrays

Combine arrays with unique elements.

  • Merge: Combine both arrays
  • Dedup: Remove duplicates
  • Complexity: O(n*m) time
  • Return: Array of unique elements
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Union of arrays in Solidity
contract ArrayUnion {
    function union(uint256[] memory _arr1, uint256[] memory _arr2) public pure returns (uint256[] memory) {
        uint256[] memory temp = new uint256[](_arr1.length + _arr2.length);
        uint256 count = 0;
        for (uint256 i = 0; i < _arr1.length; i++) {
            bool duplicate = false;
            for (uint256 j = 0; j < count; j++) {
                if (temp[j] == _arr1[i]) {
                    duplicate = true;
                    break;
                }
            }
            if (!duplicate) {
                temp[count] = _arr1[i];
                count++;
            }
        }
        for (uint256 i = 0; i < _arr2.length; i++) {
            bool duplicate = false;
            for (uint256 j = 0; j < count; j++) {
                if (temp[j] == _arr2[i]) {
                    duplicate = true;
                    break;
                }
            }
            if (!duplicate) {
                temp[count] = _arr2[i];
                count++;
            }
        }
        uint256[] memory result = new uint256[](count);
        for (uint256 i = 0; i < count; i++) {
            result[i] = temp[i];
        }
        return result;
    }
}
Coding Round
58. Difference of arrays

Find elements in first array not in second.

  • Filter: Check if in second array
  • Dedup: Avoid duplicates
  • Complexity: O(n*m) time
  • Return: Array of differences
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Difference of arrays in Solidity
contract ArrayDifference {
    function difference(uint256[] memory _arr1, uint256[] memory _arr2) public pure returns (uint256[] memory) {
        uint256[] memory temp = new uint256[](_arr1.length);
        uint256 count = 0;
        for (uint256 i = 0; i < _arr1.length; i++) {
            bool found = false;
            for (uint256 j = 0; j < _arr2.length; j++) {
                if (_arr1[i] == _arr2[j]) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                bool duplicate = false;
                for (uint256 k = 0; k < count; k++) {
                    if (temp[k] == _arr1[i]) {
                        duplicate = true;
                        break;
                    }
                }
                if (!duplicate) {
                    temp[count] = _arr1[i];
                    count++;
                }
            }
        }
        uint256[] memory result = new uint256[](count);
        for (uint256 i = 0; i < count; i++) {
            result[i] = temp[i];
        }
        return result;
    }
}
Coding Round
59. Group by property

Group items by type using structs and arrays.

  • Structs: Define Item and Group
  • Loop: Iterate and group by type
  • Return: Array of groups
  • Complexity: O(n²) time
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Group by property in Solidity
contract GroupByProperty {
    struct Item {
        string type_;
        string name;
    }
    
    struct Group {
        string type_;
        Item[] items;
    }
    
    function groupByType(Item[] memory _items) public pure returns (Group[] memory) {
        Group[] memory groups = new Group[](_items.length);
        uint256 groupCount = 0;
        for (uint256 i = 0; i < _items.length; i++) {
            bool found = false;
            for (uint256 j = 0; j < groupCount; j++) {
                if (keccak256(abi.encodePacked(groups[j].type_)) == keccak256(abi.encodePacked(_items[i].type_))) {
                    groups[j].items.push(_items[i]);
                    found = true;
                    break;
                }
            }
            if (!found) {
                groups[groupCount].type_ = _items[i].type_;
                groups[groupCount].items.push(_items[i]);
                groupCount++;
            }
        }
        Group[] memory result = new Group[](groupCount);
        for (uint256 i = 0; i < groupCount; i++) {
            result[i] = groups[i];
        }
        return result;
    }
}
Coding Round
60. Deep clone object

Deep clone using struct copy with nested structs.

  • Struct copy: Create new struct instance
  • Nested: Copy nested struct fields
  • Memory: Uses memory storage
  • Return: Independent copy
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Deep clone in Solidity
contract DeepClone {
    struct Address {
        string city;
        string zip;
    }
    
    struct User {
        string name;
        Address address;
    }
    
    function cloneUser(User memory _user) public pure returns (User memory) {
        return User({
            name: _user.name,
            address: Address({
                city: _user.address.city,
                zip: _user.address.zip
            })
        });
    }
}
Coding Round
61. Immutable update

Perform immutable update by copying struct and modifying.

  • Copy: Create new struct from old
  • Modify: Update field values
  • Return: New struct instance
  • Immutability: Original unchanged
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Immutable update in Solidity
contract ImmutableUpdate {
    struct User {
        string name;
        uint256 age;
    }
    
    function updateUser(User memory _user, uint256 _newAge) public pure returns (User memory) {
        User memory newUser = _user;
        newUser.age = _newAge;
        return newUser;
    }
}
Coding Round
62. Pipe function

Pipe composes functions from left to right.

  • Composition: Chain function calls
  • Direction: Left to right
  • Implementation: Nested function calls
  • Return: Final result
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Pipe function in Solidity
contract Pipe {
    function double(uint256 x) public pure returns (uint256) {
        return x * 2;
    }
    
    function addTen(uint256 x) public pure returns (uint256) {
        return x + 10;
    }
    
    function square(uint256 x) public pure returns (uint256) {
        return x * x;
    }
    
    function pipe(uint256 x) public pure returns (uint256) {
        return square(addTen(double(x)));
    }
}
Coding Round
63. Compose function

Compose functions from right to left.

  • Composition: Chain function calls
  • Direction: Right to left
  • Implementation: Nested function calls
  • Return: Final result
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Compose function in Solidity
contract Compose {
    function double(uint256 x) public pure returns (uint256) {
        return x * 2;
    }
    
    function addTen(uint256 x) public pure returns (uint256) {
        return x + 10;
    }
    
    function square(uint256 x) public pure returns (uint256) {
        return x * x;
    }
    
    function compose(uint256 x) public pure returns (uint256) {
        return double(addTen(square(x)));
    }
}
Coding Round
64. Memoization

Cache function results using mapping.

  • Mapping: Store cached results
  • Key: Function arguments
  • Return: Cached or computed result
  • Gas: Cache saves computation
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Memoization in Solidity
contract Memoization {
    mapping(uint256 => uint256) public fibCache;
    
    function fibonacci(uint256 n) public returns (uint256) {
        if (n <= 1) {
            return n;
        }
        if (fibCache[n] != 0) {
            return fibCache[n];
        }
        uint256 result = fibonacci(n - 1) + fibonacci(n - 2);
        fibCache[n] = result;
        return result;
    }
}
Coding Round
65. Once function

Execute function only once using initialization flag.

  • Flag: Track if initialized
  • Result: Store computed value
  • Guard: Check flag before execution
  • Use case: One-time initialization
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Once function in Solidity
contract Once {
    bool private initialized;
    uint256 private result;
    
    function initialize() public returns (uint256) {
        if (!initialized) {
            initialized = true;
            result = 42;
            return result;
        }
        return result;
    }
}
Coding Round
66. Debounce with leading edge

Debounce pattern using timestamp checks.

  • Timestamp: Track last call time
  • Leading edge: Execute immediately
  • Delay: Wait before next execution
  • Use case: Rate limiting
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Debounce pattern in Solidity
contract Debounce {
    uint256 public lastCallTime;
    uint256 public constant DEBOUNCE_DELAY = 1 hours;
    
    event Executed();
    
    function debouncedFunction() public {
        require(block.timestamp >= lastCallTime + DEBOUNCE_DELAY, "Too soon");
        lastCallTime = block.timestamp;
        emit Executed();
        // Function logic here
    }
}
Coding Round
67. Throttle with leading edge

Throttle pattern using timestamp tracking.

  • Timestamp: Track last execution
  • Leading edge: Execute if enough time passed
  • Rate limiting: At most once per period
  • Use case: Rate limiting, API calls
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Throttle pattern in Solidity
contract Throttle {
    uint256 public lastCallTime;
    uint256 public constant THROTTLE_DELAY = 1 minutes;
    
    event Executed();
    
    function throttledFunction() public {
        require(block.timestamp >= lastCallTime + THROTTLE_DELAY, "Too many requests");
        lastCallTime = block.timestamp;
        emit Executed();
        // Function logic here
    }
}
Coding Round
68. Deep equal

Deep equality comparison using struct field comparison.

  • Struct comparison: Compare field by field
  • String comparison: Compare bytes hash
  • Return: Boolean result
  • Complexity: O(n) time
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Deep equal in Solidity
contract DeepEqual {
    struct Address {
        string city;
        string zip;
    }
    
    struct User {
        string name;
        Address address;
    }
    
    function deepEqual(User memory _a, User memory _b) public pure returns (bool) {
        if (keccak256(abi.encodePacked(_a.name)) != keccak256(abi.encodePacked(_b.name))) {
            return false;
        }
        if (keccak256(abi.encodePacked(_a.address.city)) != keccak256(abi.encodePacked(_b.address.city))) {
            return false;
        }
        if (keccak256(abi.encodePacked(_a.address.zip)) != keccak256(abi.encodePacked(_b.address.zip))) {
            return false;
        }
        return true;
    }
}
Coding Round
69. Observable pattern

Observer pattern using events and observer list.

  • Observers: List of observer addresses
  • Events: Emit notifications
  • Add/Remove: Manage observer list
  • Notify: Emit event to all
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Observable pattern in Solidity
contract Observable {
    address[] public observers;
    mapping(address => bool) public isObserver;
    
    event StateChanged(string state);
    event ObserverAdded(address observer);
    event ObserverRemoved(address observer);
    
    function addObserver(address _observer) public {
        require(!isObserver[_observer], "Already observer");
        isObserver[_observer] = true;
        observers.push(_observer);
        emit ObserverAdded(_observer);
    }
    
    function removeObserver(address _observer) public {
        require(isObserver[_observer], "Not observer");
        isObserver[_observer] = false;
        emit ObserverRemoved(_observer);
    }
    
    function notifyObservers(string memory _state) internal {
        emit StateChanged(_state);
        for (uint256 i = 0; i < observers.length; i++) {
            if (isObserver[observers[i]]) {
                // In practice, call observer callback
            }
        }
    }
}
Coding Round
70. Singleton pattern

Singleton pattern using contract address.

  • Single instance: Contract itself is singleton
  • Owner: Set owner in constructor
  • State: Store state in contract
  • Access: Control via modifiers
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Singleton pattern in Solidity
contract Singleton {
    address public owner;
    uint256 public value;
    
    // Private constructor
    constructor() {
        owner = msg.sender;
    }
    
    // Singleton instance
    function getInstance() public pure returns (Singleton) {
        return Singleton(address(this));
    }
    
    function setValue(uint256 _value) public {
        require(msg.sender == owner, "Not owner");
        value = _value;
    }
}
Coding Round
71. Factory pattern

Factory pattern using contract that creates new contracts.

  • Factory: Contract that creates instances
  • Create: Use new keyword
  • Store: Track created instances
  • Return: Address of new contract
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Factory pattern in Solidity
contract UserFactory {
    struct User {
        string name;
        address wallet;
    }
    
    User[] public users;
    
    function createUser(string memory _name) public returns (User memory) {
        User memory newUser = User({
            name: _name,
            wallet: msg.sender
        });
        users.push(newUser);
        return newUser;
    }
}
Coding Round
72. Strategy pattern

Strategy pattern using interfaces and dynamic dispatch.

  • Interface: Define strategy interface
  • Strategies: Different implementations
  • Context: Uses current strategy
  • Switch: Change strategy at runtime
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Strategy pattern in Solidity
interface IStrategy {
    function execute(uint256 _value) external returns (uint256);
}

contract StrategyA is IStrategy {
    function execute(uint256 _value) external pure override returns (uint256) {
        return _value * 2;
    }
}

contract StrategyB is IStrategy {
    function execute(uint256 _value) external pure override returns (uint256) {
        return _value + 10;
    }
}

contract StrategyContext {
    address public strategy;
    
    function setStrategy(address _strategy) public {
        strategy = _strategy;
    }
    
    function execute(uint256 _value) public returns (uint256) {
        require(strategy != address(0), "Strategy not set");
        return IStrategy(strategy).execute(_value);
    }
}
Coding Round
73. Observer pattern

Observer pattern using events and observer management.

  • Subject: Maintains observers
  • Events: Emit state changes
  • Add/Remove: Manage observer list
  • Notify: Emit event to all
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Observer pattern in Solidity
contract Subject {
    address[] public observers;
    mapping(address => bool) public isObserver;
    
    event StateChanged(string state);
    
    function addObserver(address _observer) public {
        require(!isObserver[_observer], "Already observer");
        isObserver[_observer] = true;
        observers.push(_observer);
    }
    
    function removeObserver(address _observer) public {
        require(isObserver[_observer], "Not observer");
        isObserver[_observer] = false;
    }
    
    function setState(string memory _state) internal {
        emit StateChanged(_state);
        for (uint256 i = 0; i < observers.length; i++) {
            if (isObserver[observers[i]]) {
                // Notify observer
            }
        }
    }
}
Coding Round
74. Decorator pattern

Decorator pattern using wrapper contracts.

  • Component: Base contract
  • Decorator: Wraps component
  • Chaining: Multiple decorators
  • Benefits: Add behavior dynamically
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Decorator pattern in Solidity
contract Coffee {
    function cost() public pure returns (uint256) {
        return 5;
    }
    
    function description() public pure returns (string memory) {
        return "Coffee";
    }
}

contract MilkDecorator {
    Coffee private _coffee;
    
    constructor(Coffee coffee) {
        _coffee = coffee;
    }
    
    function cost() public view returns (uint256) {
        return _coffee.cost() + 2;
    }
    
    function description() public view returns (string memory) {
        return string(abi.encodePacked(_coffee.description(), ", Milk"));
    }
}
Coding Round
75. Command pattern

Command pattern with execute and undo using interfaces.

  • Interface: ICommand with execute/undo
  • Command: Implements interface
  • Receiver: Performs work
  • Undo/Redo: Track history
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Command pattern in Solidity
interface ICommand {
    function execute() external;
    function undo() external;
}

contract AddCommand is ICommand {
    uint256[] public data;
    uint256 public value;
    
    constructor(uint256[] memory _data, uint256 _value) {
        data = _data;
        value = _value;
    }
    
    function execute() external override {
        data.push(value);
    }
    
    function undo() external override {
        // Remove last element if it matches value
        if (data.length > 0 && data[data.length - 1] == value) {
            data.pop();
        }
    }
}
Coding Round
76. Memento pattern

Memento pattern using history of states.

  • Originator: Creates/restores mementos
  • History: Array of states
  • Restore: Revert to previous state
  • Undo: State history management
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Memento pattern in Solidity
contract Memento {
    struct State {
        string state;
        uint256 timestamp;
    }
    
    State[] public history;
    string public currentState;
    
    function saveState() public {
        history.push(State(currentState, block.timestamp));
    }
    
    function restoreState(uint256 _index) public {
        require(_index < history.length, "Invalid index");
        currentState = history[_index].state;
    }
}
Coding Round
77. Mediator pattern

Mediator pattern for centralized communication.

  • Mediator: Central coordinator
  • Participants: Register with mediator
  • Messages: Send through mediator
  • Events: Emit messages
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Mediator pattern in Solidity
contract Mediator {
    address[] public participants;
    mapping(address => bool) public isParticipant;
    
    function register(address _participant) public {
        require(!isParticipant[_participant], "Already registered");
        isParticipant[_participant] = true;
        participants.push(_participant);
    }
    
    function sendMessage(address _from, address _to, string memory _message) public {
        require(isParticipant[_from] && isParticipant[_to], "Invalid participant");
        // In practice, implement message passing
        emit Message(_from, _to, _message);
    }
    
    event Message(address indexed from, address indexed to, string message);
}
Coding Round
78. Chain of Responsibility

Chain of Responsibility using abstract contract.

  • Handler: Abstract with next handler
  • Chain: Link handlers together
  • Process: Pass request along chain
  • Events: Log processing
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Chain of Responsibility in Solidity
abstract contract Handler {
    Handler public nextHandler;
    
    function setNext(Handler _next) public {
        nextHandler = _next;
    }
    
    function handle(uint256 _request) public virtual returns (bool) {
        if (nextHandler != Handler(address(0))) {
            return nextHandler.handle(_request);
        }
        return false;
    }
}

contract AuthHandler is Handler {
    function handle(uint256 _request) public override returns (bool) {
        // Authentication logic
        if (_request >= 100) {
            return true;
        }
        return super.handle(_request);
    }
}

contract LoggerHandler is Handler {
    function handle(uint256 _request) public override returns (bool) {
        // Logging logic
        emit Logged(_request);
        return super.handle(_request);
    }
    
    event Logged(uint256 request);
}
Coding Round
79. State pattern

State pattern using enum states.

  • States: Define as enum
  • Transitions: Move between states
  • Validation: Check current state
  • Events: Emit state changes
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// State pattern in Solidity
contract StateMachine {
    enum State { Idle, Processing, Completed }
    State public currentState = State.Idle;
    
    function start() public {
        require(currentState == State.Idle, "Invalid state");
        currentState = State.Processing;
        emit StateChanged("Processing");
    }
    
    function complete() public {
        require(currentState == State.Processing, "Invalid state");
        currentState = State.Completed;
        emit StateChanged("Completed");
    }
    
    event StateChanged(string state);
}
Coding Round
80. Proxy pattern

Proxy pattern for access control.

  • Subject: Real implementation
  • Proxy: Controls access
  • Authorization: Check caller
  • Delegation: Forward calls
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Proxy pattern in Solidity
contract RealSubject {
    function request() public pure returns (string memory) {
        return "RealSubject: Handling request";
    }
}

contract Proxy {
    RealSubject public realSubject;
    address public owner;
    
    constructor() {
        owner = msg.sender;
        realSubject = new RealSubject();
    }
    
    function request() public view returns (string memory) {
        require(msg.sender == owner, "Not authorized");
        return realSubject.request();
    }
}
Coding Round
81. Flyweight pattern

Flyweight pattern using mapping for shared state.

  • Flyweight: Shared state object
  • Factory: Manages flyweights
  • Cache: Store shared instances
  • Memory: Optimize storage
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Flyweight pattern in Solidity
contract Flyweight {
    struct SharedState {
        string state;
    }
    
    mapping(string => SharedState) public flyweights;
    
    function getFlyweight(string memory _state) public returns (SharedState memory) {
        if (bytes(flyweights[_state].state).length == 0) {
            flyweights[_state] = SharedState(_state);
        }
        return flyweights[_state];
    }
}
Coding Round
82. Bridge pattern

Bridge pattern for separating abstraction from implementation.

  • Abstraction: High-level interface
  • Implementation: Low-level operations
  • Separation: Decouple interface/implementation
  • Flexibility: Change implementation independently
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Bridge pattern in Solidity
interface IImplementation {
    function operationImpl() external returns (string memory);
}

contract ImplementationA is IImplementation {
    function operationImpl() external pure override returns (string memory) {
        return "ImplementationA";
    }
}

contract ImplementationB is IImplementation {
    function operationImpl() external pure override returns (string memory) {
        return "ImplementationB";
    }
}

contract Abstraction {
    IImplementation public impl;
    
    function setImpl(address _impl) public {
        impl = IImplementation(_impl);
    }
    
    function operation() public view returns (string memory) {
        return impl.operationImpl();
    }
}
Coding Round
83. Adapter pattern

Adapter pattern for converting interfaces.

  • Target: Expected interface
  • Adaptee: Existing interface
  • Adapter: Bridges interfaces
  • Compatibility: Make incompatible classes work
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Adapter pattern in Solidity
interface ITarget {
    function request() external returns (string memory);
}

contract Adaptee {
    function specificRequest() public pure returns (string memory) {
        return "Specific Request";
    }
}

contract Adapter is ITarget {
    Adaptee public adaptee;
    
    constructor() {
        adaptee = new Adaptee();
    }
    
    function request() external override returns (string memory) {
        return adaptee.specificRequest();
    }
}
Coding Round
84. Facade pattern

Facade pattern for simplifying complex subsystems.

  • Facade: Simplified interface
  • Subsystem: Complex components
  • Simplification: Hide complexity
  • Use case: Library APIs
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Facade pattern in Solidity
contract SubsystemA {
    function operationA() public pure returns (string memory) {
        return "SubsystemA";
    }
}

contract SubsystemB {
    function operationB() public pure returns (string memory) {
        return "SubsystemB";
    }
}

contract Facade {
    SubsystemA public a;
    SubsystemB public b;
    
    constructor() {
        a = new SubsystemA();
        b = new SubsystemB();
    }
    
    function operation() public view returns (string memory) {
        return string(abi.encodePacked(a.operationA(), " + ", b.operationB()));
    }
}
Coding Round
85. Composite pattern

Composite pattern for tree structures.

  • Component: Interface for all
  • Leaf: Individual object
  • Composite: Container
  • Uniform: Treat leaf and composite uniformly
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Composite pattern in Solidity
interface IComponent {
    function operation() external returns (string memory);
}

contract Leaf is IComponent {
    string public name;
    
    constructor(string memory _name) {
        name = _name;
    }
    
    function operation() external override returns (string memory) {
        return name;
    }
}

contract Composite is IComponent {
    IComponent[] public children;
    string public name;
    
    constructor(string memory _name) {
        name = _name;
    }
    
    function add(IComponent _child) public {
        children.push(_child);
    }
    
    function operation() external override returns (string memory) {
        string memory result = name;
        for (uint256 i = 0; i < children.length; i++) {
            result = string(abi.encodePacked(result, " + ", children[i].operation()));
        }
        return result;
    }
}
Coding Round
86. Visitor pattern

Visitor pattern for adding operations without modifying elements.

  • Visitor: Defines operations
  • Element: Accepts visitors
  • Extensibility: Add operations easily
  • Double dispatch: Determine operation
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Visitor pattern in Solidity
interface IVisitor {
    function visitElementA(address _element) external returns (string memory);
    function visitElementB(address _element) external returns (string memory);
}

contract ElementA {
    function accept(IVisitor _visitor) external returns (string memory) {
        return _visitor.visitElementA(address(this));
    }
}

contract ElementB {
    function accept(IVisitor _visitor) external returns (string memory) {
        return _visitor.visitElementB(address(this));
    }
}

contract ConcreteVisitor is IVisitor {
    function visitElementA(address _element) external pure override returns (string memory) {
        return "Visiting ElementA";
    }
    
    function visitElementB(address _element) external pure override returns (string memory) {
        return "Visiting ElementB";
    }
}
Coding Round
87. Iterator pattern

Iterator pattern for sequential access.

  • Iterator: Traverses collection
  • Index: Track current position
  • hasNext: Check for more items
  • next: Return next item
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Iterator pattern in Solidity
contract Iterator {
    uint256[] public collection;
    uint256 public index;
    
    function add(uint256 _value) public {
        collection.push(_value);
    }
    
    function next() public returns (uint256) {
        require(hasNext(), "No more items");
        uint256 value = collection[index];
        index++;
        return value;
    }
    
    function hasNext() public view returns (bool) {
        return index < collection.length;
    }
}
Coding Round
88. Template Method pattern

Template Method for algorithm skeletons.

  • AbstractClass: Defines template
  • ConcreteClass: Implements steps
  • Reuse: Code reuse
  • Frameworks: Common in frameworks
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Template Method pattern in Solidity
abstract contract AbstractClass {
    function templateMethod() public returns (string memory) {
        string memory result = step1();
        result = string(abi.encodePacked(result, step2()));
        result = string(abi.encodePacked(result, step3()));
        return result;
    }
    
    function step1() internal pure returns (string memory) {
        return "Step1";
    }
    
    function step2() internal virtual returns (string memory);
    
    function step3() internal pure returns (string memory) {
        return "Step3";
    }
}

contract ConcreteClass is AbstractClass {
    function step2() internal pure override returns (string memory) {
        return "ConcreteStep2";
    }
}
Coding Round
89. Builder pattern

Builder pattern for constructing complex objects.

  • Builder: Constructs parts
  • Director: Orchestrates construction
  • Product: Constructed object
  • Step-by-step: Build incrementally
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Builder pattern in Solidity
contract Product {
    string[] public parts;
    
    function addPart(string memory _part) public {
        parts.push(_part);
    }
}

contract Builder {
    Product public product;
    
    constructor() {
        product = new Product();
    }
    
    function buildStepA() public {
        product.addPart("Part A");
    }
    
    function buildStepB() public {
        product.addPart("Part B");
    }
    
    function getResult() public view returns (Product) {
        return product;
    }
}
Coding Round
90. Prototype pattern

Prototype pattern for cloning objects.

  • Prototype: Cloneable object
  • Clone: Creates a copy
  • Contract: New contract instance
  • Performance: Object reuse
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Prototype pattern in Solidity
contract Prototype {
    struct Data {
        string name;
        uint256 value;
    }
    
    Data public data;
    
    constructor(string memory _name, uint256 _value) {
        data = Data(_name, _value);
    }
    
    function clone() public returns (Prototype) {
        return new Prototype(data.name, data.value);
    }
}
Coding Round
91. Custom errors

Custom errors for gas-efficient error handling.

  • Custom errors: Define with error
  • Revert: Use revert with custom error
  • Gas: More gas efficient than require
  • Parameters: Can include parameters
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Error handling with custom errors
contract CustomErrors {
    error InsufficientBalance(uint256 balance, uint256 requested);
    error Unauthorized(address caller);
    
    mapping(address => uint256) public balances;
    
    function withdraw(uint256 _amount) public {
        if (balances[msg.sender] < _amount) {
            revert InsufficientBalance(balances[msg.sender], _amount);
        }
        if (msg.sender != address(this)) {
            revert Unauthorized(msg.sender);
        }
        balances[msg.sender] -= _amount;
        payable(msg.sender).transfer(_amount);
    }
}
Coding Round
92. Events and logging

Events for logging and off-chain communication.

  • Events: Define with event
  • Emit: Emit with emit
  • Indexed: indexed for filtering
  • Gas: Events are gas efficient
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Events and logging
contract EventsLogging {
    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);
    event Log(string message, uint256 value);
    
    mapping(address => uint256) public balances;
    mapping(address => mapping(address => uint256)) public allowances;
    
    function transfer(address _to, uint256 _amount) public {
        require(balances[msg.sender] >= _amount, "Insufficient balance");
        balances[msg.sender] -= _amount;
        balances[_to] += _amount;
        emit Transfer(msg.sender, _to, _amount);
    }
}
Coding Round
93. Modifiers and guards

Modifiers for reusable access control and validation.

  • Modifiers: Define with modifier
  • Access control: onlyOwner
  • State checks: whenNotPaused
  • Reuse: Apply to multiple functions
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Modifiers and guards
contract Modifiers {
    address public owner;
    bool public paused;
    
    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }
    
    modifier whenNotPaused() {
        require(!paused, "Paused");
        _;
    }
    
    constructor() {
        owner = msg.sender;
    }
    
    function pause() public onlyOwner {
        paused = true;
    }
    
    function unpause() public onlyOwner {
        paused = false;
    }
    
    function doSomething() public whenNotPaused {
        // Logic
    }
}
Coding Round
94. Libraries

Libraries for reusable utility functions.

  • Libraries: Define with library
  • Functions: Internal functions
  • Using For: Attach library to types
  • Gas: Libraries are gas efficient
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Libraries
library Math {
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }
    
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "Subtraction overflow");
        return a - b;
    }
}

contract UsingLibrary {
    using Math for uint256;
    
    function calculate(uint256 a, uint256 b) public pure returns (uint256) {
        return a.add(b);
    }
}
Coding Round
95. Inheritance

Inheritance for code reuse and extension.

  • Inheritance: contract Child is Parent
  • Constructor: Call parent constructor
  • Override: virtual and override
  • Multiple: Multiple inheritance supported
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Inheritance
contract Parent {
    string public name;
    
    constructor(string memory _name) {
        name = _name;
    }
    
    function getName() public view returns (string memory) {
        return name;
    }
}

contract Child is Parent {
    uint256 public age;
    
    constructor(string memory _name, uint256 _age) Parent(_name) {
        age = _age;
    }
    
    function getInfo() public view returns (string memory, uint256) {
        return (name, age);
    }
}
Coding Round
96. Interfaces

Interfaces for contract interaction and standardization.

  • Interface: Define with interface
  • Functions: External functions only
  • Implementation: Contract implements interface
  • Standards: ERC-20, ERC-721, etc.
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Interfaces
interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
}

contract MyToken is IERC20 {
    uint256 private _totalSupply;
    mapping(address => uint256) private _balances;
    
    constructor(uint256 initialSupply) {
        _totalSupply = initialSupply;
        _balances[msg.sender] = initialSupply;
    }
    
    function totalSupply() external view override returns (uint256) {
        return _totalSupply;
    }
    
    function balanceOf(address account) external view override returns (uint256) {
        return _balances[account];
    }
    
    function transfer(address recipient, uint256 amount) external override returns (bool) {
        require(_balances[msg.sender] >= amount, "Insufficient balance");
        _balances[msg.sender] -= amount;
        _balances[recipient] += amount;
        return true;
    }
}
Coding Round
97. Arrays and loops

Arrays and loops for data processing.

  • Arrays: Dynamic and fixed size
  • Loops: for loops for iteration
  • Gas: Be mindful of gas costs
  • Return: Processed data
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Arrays and loops
contract ArrayOperations {
    uint256[] public numbers;
    
    function add(uint256 _num) public {
        numbers.push(_num);
    }
    
    function sum() public view returns (uint256) {
        uint256 total = 0;
        for (uint256 i = 0; i < numbers.length; i++) {
            total += numbers[i];
        }
        return total;
    }
    
    function average() public view returns (uint256) {
        require(numbers.length > 0, "Empty array");
        return sum() / numbers.length;
    }
}
Coding Round
98. Mapping and structs

Mappings and structs for complex data storage.

  • Mapping: Key-value storage
  • Structs: Custom data types
  • Combined: Mapping to struct
  • Iteration: Use separate key array
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Mapping and structs
contract MappingStructs {
    struct User {
        string name;
        uint256 age;
        bool active;
    }
    
    mapping(address => User) public users;
    address[] public userList;
    
    function addUser(string memory _name, uint256 _age) public {
        require(bytes(users[msg.sender].name).length == 0, "User exists");
        users[msg.sender] = User(_name, _age, true);
        userList.push(msg.sender);
    }
    
    function getUser(address _addr) public view returns (string memory, uint256, bool) {
        User memory user = users[_addr];
        return (user.name, user.age, user.active);
    }
}
Coding Round
99. Security best practices

Security best practices for smart contracts.

  • Checks-effects-interactions: Order of operations
  • Reentrancy: Protect against reentrancy attacks
  • Pull over push: Withdraw pattern
  • Access control: Use modifiers
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Security best practices
contract Security {
    address public owner;
    uint256 public value;
    
    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }
    
    constructor() {
        owner = msg.sender;
    }
    
    // Use checks-effects-interactions pattern
    function withdraw(uint256 _amount) public onlyOwner {
        require(_amount <= value, "Insufficient balance");
        // Effects
        value -= _amount;
        // Interactions
        payable(msg.sender).transfer(_amount);
    }
    
    // Use pull over push for payments
    mapping(address => uint256) public pendingWithdrawals;
    
    function requestWithdrawal(uint256 _amount) public {
        pendingWithdrawals[msg.sender] += _amount;
    }
    
    function withdrawPending() public {
        uint256 amount = pendingWithdrawals[msg.sender];
        require(amount > 0, "No pending withdrawal");
        pendingWithdrawals[msg.sender] = 0;
        payable(msg.sender).transfer(amount);
    }
}
Coding Round
100. Gas optimization

Gas optimization techniques for efficient contracts.

  • uint256: Use efficient data types
  • Mappings: Prefer mappings over arrays
  • External: Use external over public
  • Calldata: Use calldata for parameters
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Gas optimization
contract GasOptimization {
    // Use uint256 for efficiency
    uint256 public value;
    
    // Use mappings over arrays when possible
    mapping(address => uint256) public balances;
    
    // Use external over public when possible
    function getBalance(address _addr) external view returns (uint256) {
        return balances[_addr];
    }
    
    // Use short-circuit evaluation
    function check(address _addr, uint256 _amount) external view returns (bool) {
        require(_addr != address(0), "Invalid address");
        return balances[_addr] >= _amount;
    }
    
    // Use calldata over memory for parameters
    function process(string calldata _data) external pure returns (string memory) {
        return _data;
    }
}