Solidity provides several control structures that are similar to those found in traditional programming languages. Understanding how to use these effectively is crucial for writing efficient and secure smart contracts. This guide will delve into if, else, for, while, and require, providing practical examples to illustrate their usage.

Conditional Statements

If-Else Statement

The if statement is used to execute a block of code based on a condition. If the condition evaluates to true, the code inside the block will execute; otherwise, it can optionally execute an else block.

pragma solidity ^0.8.0;

contract Voting {
    uint public votes;
    
    function vote() public {
        votes++;
    }

    function checkVotes() public view returns (string memory) {
        if (votes > 10) {
            return "More than 10 votes";
        } else {
            return "10 votes or less";
        }
    }
}

Ternary Operator

Solidity also supports the ternary operator, which is a shorthand for simple if-else statements.

function isMajority() public view returns (string memory) {
    return (votes > 10) ? "Majority reached" : "Still counting";
}

Loops

For Loop

The for loop is useful for iterating over a sequence of numbers or elements. It is commonly used when the number of iterations is known beforehand.

pragma solidity ^0.8.0;

contract Counter {
    uint public count;

    function increment(uint times) public {
        for (uint i = 0; i < times; i++) {
            count++;
        }
    }
}

While Loop

The while loop continues to execute as long as a specified condition is true. It is useful when the number of iterations is not known in advance.

pragma solidity ^0.8.0;

contract GuessingGame {
    uint private secretNumber;
    uint public attempts;

    constructor(uint _secretNumber) {
        secretNumber = _secretNumber;
    }

    function guess(uint _guess) public {
        while (_guess != secretNumber) {
            attempts++;
            // Logic to prompt user to guess again can be added here
            break; // Break to avoid infinite loop in this example
        }
    }
}

Error Handling

Require Statement

The require statement is used to validate conditions and revert transactions if the condition is not met. This is crucial for ensuring the integrity of your smart contract.

pragma solidity ^0.8.0;

contract Bank {
    mapping(address => uint) public balances;

    function deposit() public payable {
        require(msg.value > 0, "Deposit must be greater than zero");
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint amount) public {
        require(balances[msg.sender] >= amount, "Insufficient balance");
        balances[msg.sender] -= amount;
        payable(msg.sender).transfer(amount);
    }
}

Assert and Revert

The assert statement is used to check for conditions that should never fail. If an assert fails, it indicates a bug in the contract. The revert function can be used to return an error message and revert the transaction.

function safeWithdraw(uint amount) public {
    require(balances[msg.sender] >= amount, "Insufficient balance");
    balances[msg.sender] -= amount;
    
    // Check for underflow
    assert(balances[msg.sender] >= 0);
    
    payable(msg.sender).transfer(amount);
}

Best Practices

  1. Minimize Gas Usage: Use loops judiciously, as they can lead to high gas costs. Prefer for loops with a known iteration count.
  2. Use require for Input Validation: Always validate inputs using require to prevent unexpected behavior.
  3. Avoid Infinite Loops: Ensure that any loop has a clear exit condition to avoid running out of gas.
  4. Error Messages: Provide clear error messages in require and revert statements to aid in debugging.

Summary of Control Structures

Control StructureDescriptionExample Usage
ifExecutes a block of code based on a conditionVoting checks
elseExecutes an alternative block if the condition is falseVoting checks
forIterates a fixed number of timesIncrementing a counter
whileContinues executing as long as a condition is trueGuessing game logic
requireValidates conditions and reverts on failureEnsuring sufficient balance
assertChecks for conditions that should never failPreventing underflows

Learn more with useful resources