In Solidity, manage structures are fundamental for implementing choice-making and iteration in clever contracts.Conditional Statements like if
, else if
, and else
execute code blocks based on specific conditions. Loops such as for
, while
, and do-while
facilitate repetitive actions, though they should be used cautiously to avoid high gas costs. Break and continue are used to control loop execution by terminating or skipping iterations. Solidity also supports inline assembly for low-level control. These structures enable the implementation of complex logic securely and efficiently.
Table of Contents
Solidity – Operators
1. Arithmetic Operators
These are used for mathematical calculations.
Operator | Description | Example (a = 10, b = 5) | Result |
---|---|---|---|
+ | Addition | a + b | 15 |
– | Subtraction | a – b | 5 |
* | Multiplication | a * b | 50 |
/ | Division | a / b | 2 |
% | Modulus (remainder) | a % b | 0 |
2. Comparison Operators
These compare two values and return true
or false
.
Operator | Description | Example (a = 10, b = 5) | Result |
---|---|---|---|
== | Equal to | a == b | false |
!= | Not equal to | a != b | true |
> | Greater than | a > b | true |
< | Less than | a < b | false |
>= | Greater or equal | a >= b | true |
<= | Less or equal | a <= b | false |
3. Logical Operators
These are used to combine multiple conditions.
Operator | Description | Example (x = true, y = false) | Result |
---|---|---|---|
&& | Logical AND | x && y | false |
|| | Logical OR | x || y | true |
! | Logical NOT | !x | false |
4. Bitwise Operators
These perform operations on the binary representation of numbers.
Operator | Description | Example (a = 10, b = 4) | Result (Binary) | Result (Decimal) |
---|---|---|---|---|
& | AND | a & b | 0000 0100 | 4 |
| | OR | a | b | 0000 1110 | 14 |
^ | XOR | a ^ b | 0000 1010 | 10 |
<< | Left shift | a << 1 | 0001 0100 | 20 |
>> | Right shift | a >> 1 | 0000 0101 | 5 |
5. Assignment Operators
These assign values to variables and can perform operations simultaneously.
Operator | Description | Example (a = 10) | Result |
---|---|---|---|
= | Assign | a = 5 | 5 |
+= | Add and assign | a += 5 | 15 |
-= | Subtract and assign | a -= 5 | 5 |
*= | Multiply and assign | a *= 5 | 50 |
/= | Divide and assign | a /= 5 | 2 |
%= | Modulus and assign | a %= 5 | 0 |
6. Unary Operators
Operate on a single value.
Operator | Description | Example (a = 10) | Result |
---|---|---|---|
++ | Increment (adds 1) | a++ | 11 |
— | Decrement (subtracts 1) | a– | 9 |
7. Special Operators in Solidity
delete
: Resets a variable to its default value.
uint x = 10;
delete x; // x becomes 0
- Ternary Operator (
condition ? ifTrue : ifFalse
): A shorthand for if-else.
uint a = 10;
uint b = 20;
uint result = (a > b) ? a : b; // result is 20
Solidity – Loops
In Solidity, loops are used to repeat a block of code multiple times. Solidity supports three types of loops:
for
loopwhile
loopdo...while
loop
1. for
Loop
The for
loop runs a block of code a specific number of times.
Syntax:
for (initialization; condition; update) {
// Code to run
}
Example:
pragma solidity >=0.8.0 <0.9.0;
contract ForLoopExample {
function sumNumbers() public pure returns (uint) {
uint sum = 0;
for (uint i = 1; i <= 5; i++) {
sum += i; // Add i to sum
}
return sum; // Output: 15
}
}
2. while
Loop
The while
loop runs a block of code as long as a condition is true
.
Syntax:
while (condition) {
// Code to run
}
Example:
pragma solidity >=0.8.0 <0.9.0;
contract WhileLoopExample {
function countNumbers() public pure returns (uint) {
uint count = 0;
uint i = 1;
while (i <= 5) {
count += i; // Add i to count
i++; // Increment i
}
return count; // Output: 15
}
}
3. do...while
Loop
The do...while
loop runs the block of code at least once, then repeats it as long as the condition is true
.
Syntax:
do {
// Code to run
} while (condition);
Example:
pragma solidity >=0.8.0 <0.9.0;
contract DoWhileLoopExample {
function sumNumbers() public pure returns (uint) {
uint sum = 0;
uint i = 1;
do {
sum += i; // Add i to sum
i++; // Increment i
} while (i <= 5);
return sum; // Output: 15
}
}
Key Points to Remember
- Gas Costs: Loops in Solidity can be expensive in terms of gas usage, especially if they run for many iterations. Avoid unbounded loops (e.g., loops that depend on user input or data size).
- Break: Use
break
to exit a loop early if a condition is met.
for (uint i = 0; i < 10; i++) { if (i == 5) { break; // Exit loop when i is 5 } }
Continue: Use continue
to skip the rest of the loop for the current iteration and move to the next one.v
for (uint i = 0; i < 10; i++) { if (i % 2 == 0) { continue; // Skip even numbers } }
Summary
- Use
for
loops when the number of iterations is known. - Use
while
loops when the condition needs to be checked before running the loop. - Use
do...while
loops when the block of code must run at least once.
Solidity – Decision Making Statements
In Solidity, decision-making statements are used to control the flow of execution based on conditions. They allow you to perform different actions based on whether certain conditions are true or false.
1. if
Statement
The if
statement runs a block of code only if a specified condition is true.
Syntax:
if (condition) {
// Code to run if the condition is true
}
Example:
pragma solidity >=0.8.0 <0.9.0;
contract IfExample {
function checkNumber(uint num) public pure returns (string memory) {
if (num > 10) {
return "Number is greater than 10";
}
return "Number is 10 or less";
}
}
2. if...else
Statement
The if...else
statement runs one block of code if a condition is true and another block if it is false.
Syntax:
if (condition) {
// Code to run if the condition is true
} else {
// Code to run if the condition is false
}
Example:
pragma solidity >=0.8.0 <0.9.0;
contract IfElseExample {
function checkEvenOdd(uint num) public pure returns (string memory) {
if (num % 2 == 0) {
return "Number is even";
} else {
return "Number is odd";
}
}
}
3. if...else if...else
Statement
This statement checks multiple conditions. It runs the first block of code with a true condition; otherwise, it moves to the next condition.
Syntax:
if (condition1) {
// Code to run if condition1 is true
} else if (condition2) {
// Code to run if condition2 is true
} else {
// Code to run if none of the conditions are true
}
Example:
pragma solidity >=0.8.0 <0.9.0;
contract ElseIfExample {
function grade(uint marks) public pure returns (string memory) {
if (marks >= 90) {
return "A";
} else if (marks >= 75) {
return "B";
} else if (marks >= 50) {
return "C";
} else {
return "Fail";
}
}
}
4. require
Statement
The require
statement is used to check a condition. If the condition is false, it reverts the transaction with an error message.
Syntax:
require(condition, "Error message");
Example:
pragma solidity >=0.8.0 <0.9.0;
contract RequireExample {
function transfer(uint amount) public pure {
require(amount > 0, "Amount must be greater than zero");
// Code to transfer funds
}
}
5. assert
Statement
The assert
statement checks a condition and should only be used to detect bugs. If the condition is false, it reverts the transaction with an error and consumes all gas.
Syntax:
assert(condition);
Example:
pragma solidity >=0.8.0 <0.9.0;
contract AssertExample {
function testAssert(uint num) public pure {
assert(num != 0); // Ensure num is not zero
// Code to execute if num is not zero
}
}
6. revert
Statement
The revert
statement stops the execution and reverts the transaction with an optional error message. It is often used with complex conditions.
Syntax:
revert("Error message");
Example:
pragma solidity >=0.8.0 <0.9.0;
contract RevertExample {
function withdraw(uint balance, uint amount) public pure {
if (amount > balance) {
revert("Insufficient balance");
}
// Code to withdraw funds
}
}
Key Points
- Gas Efficiency: Use decision-making statements judiciously as complex logic can increase gas costs.
require
vsassert
:- Use
require
for user input validation or conditions external to the contract. - Use
assert
for internal checks and invariants.
- Use
- Fallback and Recovery: Always provide meaningful error messages to make debugging easier.
Summary
- Use
if
statements for simple conditional checks. - Use
require
for input validation. - Use
assert
to verify internal logic and detect bugs. - Use
revert
to handle complex failure conditions.
Solidity – Strings
In Solidity, strings are used to handle text data. They represent a sequence of characters, such as "Hello, world!"
.
Key Features of Strings
- Dynamic Size: Strings can store text of variable length (unlike fixed-size arrays).
- Stored in Memory or Storage:
- Memory: Temporary data used during function execution.
- Storage: Persistent data stored on the blockchain.
- Immutable by Default: Once deployed, string data cannot be changed directly; instead, you assign new values.
How to Use Strings
Declaring and Assigning
string public greeting = "Hello, Solidity!";
Reading the String
You can access the greeting
value since it’s marked as public
.
String Concatenation
Solidity does not directly support concatenation with operators like +
. Instead, use libraries like Strings from OpenZeppelin or write your custom function.
Limitations
- No Indexing: You can’t directly access characters like
string[0]
. - Expensive Gas: Storing and manipulating strings on-chain is costly due to the high gas fees.
Common Use Cases
- Store names, messages, or descriptions.
- Use in off-chain applications where the string data is sent via events.
Example Contract
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
contract StringExample {
string public message; // A public string variable
// Function to set a new message
function setMessage(string memory newMessage) public {
message = newMessage;
}
// Function to get the length of the string
function getMessageLength() public view returns (uint) {
return bytes(message).length; // Convert to bytes to calculate length
}
}
Key Notes
bytes
vs. string
:
bytes
is a lower-level type, more efficient for certain operations.- Use
bytes
for fixed-length operations andstring
for user-readable text.
Solidity – Arrays
In Solidity, arrays are used to store multiple values of the same type. Arrays can be fixed-size or dynamic.
Key Features of Arrays
- Fixed-Size Arrays: Size is defined during declaration and cannot change.
Example:uint[3] fixedArray;
- Dynamic Arrays: Can grow or shrink in size.
Example:uint[] dynamicArray;
- Array Storage:
- Memory: Temporary during function execution.
- Storage: Persistent on the blockchain.
How to Use Arrays
Declaring Arrays
// Fixed-size array
uint[3] numbers = [1, 2, 3];
// Dynamic array
uint[] numbers;
Accessing Elements
uint firstNumber = numbers[0]; // Accesses the first element
Adding Elements (Dynamic Arrays)
numbers.push(4); // Adds 4 to the array
Getting Length
uint length = numbers.length;
Example Contract
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
contract ArrayExample {
uint[] public numbers; // A dynamic array
// Add a number to the array
function addNumber(uint num) public {
numbers.push(num);
}
// Get a number at a specific index
function getNumber(uint index) public view returns (uint) {
require(index < numbers.length, "Index out of bounds");
return numbers[index];
}
// Get the length of the array
function getArrayLength() public view returns (uint) {
return numbers.length;
}
}
Limitations
- Expensive Gas: Storing large arrays is costly.
- No Built-in Remove: You can only remove by overwriting or shifting manually.
Solidity – Enums
In Solidity, enums are user-defined types used to create a list of named constants. They help make the code more readable and maintainable by replacing magic numbers with meaningful names.
Key Features of Enums
- Fixed Values: Enums define a fixed set of possible values.
- Internally Represented as Integers: The first value is assigned
0
, the second is1
, and so on. - Useful for States: Often used to represent the state of a contract (e.g.,
Active
,Inactive
,Completed
).
How to Use Enums
Declaring an Enum
enum Status { Pending, Shipped, Delivered }
Accessing Enum Values
Status public currentStatus = Status.Pending;
Updating Enum Values
currentStatus = Status.Shipped;
Getting the Integer Value of an Enum
uint statusIndex = uint(currentStatus); // Converts enum to integer
Example Contract
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
contract EnumExample {
// Declare an enum
enum Status { Pending, Shipped, Delivered }
// Use the enum
Status public currentStatus;
// Set the initial status
constructor() {
currentStatus = Status.Pending;
}
// Update the status
function setStatus(Status newStatus) public {
currentStatus = newStatus;
}
// Get the status as an integer
function getStatusIndex() public view returns (uint) {
return uint(currentStatus);
}
}
Benefits
- Improves code readability.
- Prevents invalid states (e.g., you can’t assign a value outside the defined enum options).
Limitations
- Cannot Add New Values: Once deployed, enums cannot be modified.
- No String Representation: Internally, enums are stored as integers.
Solidity – Structs
In Solidity, structs are custom data types used to group related variables. They allow you to create complex types that are easy to work with and maintain.
Key Features of Structs
- Custom Data Types: Combine variables of different types into a single unit.
- Flexibility: Useful for storing detailed data like user profiles or transaction records.
- Defined Once: Define a struct once and reuse it multiple times.
How to Use Structs
Declaring a Struct
struct User {
uint id;
string name;
bool isActive;
}
Initializing a Struct
// By setting each field
user1 = User(1, "Alice", true);
// Using named assignment
user1 = User({id: 1, name: "Alice", isActive: true});
Accessing Struct Fields
uint userId = user1.id; // Access the `id` field
Structs in Arrays
User[] public users;
users.push(User(1, "Alice", true));
Example Contract
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
contract StructExample {
// Define a struct
struct User {
uint id;
string name;
bool isActive;
}
// Store users in an array
User[] public users;
// Add a new user
function addUser(uint id, string memory name, bool isActive) public {
users.push(User(id, name, isActive));
}
// Get a user by index
function getUser(uint index) public view returns (uint, string memory, bool) {
User memory user = users[index];
return (user.id, user.name, user.isActive);
}
}
Benefits
- Simplifies code by grouping related data.
- Useful for complex applications (e.g., tracking users, orders, or products).
Limitations
- Structs cannot contain mappings or dynamic arrays directly if used in public state variables.
- High gas costs when used in large quantities.
Solidity – Mappings
In Solidity, mappings are data structures that store key-value pairs. They are like hash tables in other programming languages and are very efficient for storing and retrieving data based on a key.
Key Features of Mappings
- Key-Value Storage: A mapping links a unique key to a value.
- Uninitialized Keys Return Default Values: If a key has not been assigned a value, it will return the default value of the value type (e.g.,
0
for integers,false
for booleans, and""
for strings). - Efficient Lookup: Optimized for constant-time retrieval of values.
- Cannot Iterate: Mappings do not support iteration, so you cannot directly loop through them.
How to Use Mappings
Declaring a Mapping
mapping(address => uint) public balances;
Storing Data in a Mapping
balances[msg.sender] = 100;
Retrieving Data from a Mapping
uint balance = balances[msg.sender];
Deleting Data in a Mapping
delete balances[msg.sender];
Example Contract
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
contract MappingExample {
// Define a mapping
mapping(address => uint) public balances;
// Set a balance for an address
function setBalance(uint amount) public {
balances[msg.sender] = amount;
}
// Get a balance for an address
function getBalance(address account) public view returns (uint) {
return balances[account];
}
// Delete a balance
function deleteBalance() public {
delete balances[msg.sender];
}
}
Benefits
- Efficient Data Access: Fast access to stored data.
- Custom Keys: Keys can be of types like
address
,uint
, etc. - Simplicity: Easy to implement and use.
Limitations
- No Iteration: Mappings cannot be looped over to access all keys or values.
- No Length Property: Unlike arrays, mappings do not have a size or length property.
- One-Way Relationship: Cannot retrieve keys based on values.
Solidity – Conversions
In Solidity, conversions allow you to change data from one type to another. This includes conversions between integers, addresses, bytes, and strings.
Key Concepts
- Implicit Conversion: Automatic conversion when no data loss is possible.
- Explicit Conversion: Manual type casting required when data loss might occur.
- Restrictions: Direct conversion between incompatible types (e.g.,
string
touint
) is not allowed.
Examples
Implicit Conversion
uint8 smallNumber = 42;
uint256 largeNumber = smallNumber; // Implicit conversion
Explicit Conversion
uint256 bigNumber = 1000;
uint8 smallNumber = uint8(bigNumber); // Explicit conversion
Address and uint160 Conversion
address addr = msg.sender;
uint160 addrNumber = uint160(addr); // Address to uint160
address newAddr = address(addrNumber); // uint160 to address
String to Bytes
string memory str = "Hello, Solidity!";
bytes memory b = bytes(str); // Convert string to bytes
Bytes to String
bytes memory b = bytes("Hello");
string memory str = string(b); // Convert bytes to string
Example Contract
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
contract ConversionExample {
function convertNumbers() public pure returns (uint8, uint256) {
uint256 bigNumber = 1000;
uint8 smallNumber = uint8(bigNumber); // Explicit conversion
uint256 backToBig = smallNumber; // Implicit conversion
return (smallNumber, backToBig);
}
function convertAddress() public view returns (address, uint160) {
address addr = msg.sender;
uint160 addrNumber = uint160(addr); // Address to uint160
address newAddr = address(addrNumber); // uint160 to address
return (newAddr, addrNumber);
}
function stringToBytes(string memory input) public pure returns (bytes memory) {
return bytes(input);
}
function bytesToString(bytes memory input) public pure returns (string memory) {
return string(input);
}
}
For further details or examples, feel free to ask!
Pingback: Chapter 3: Solidity Basics-Data Types, Variables and Constants, Comments - BlockSimplifier
Pingback: Chapter 5: Solidity Smart Contract Architecture - BlockSimplifier