Solidity Types and Data: Your Building Blocks Adventure
The Story: Building a Digital Castle
Imagine you want to build an amazing castle in a video game. Before you can build towers, moats, and treasure rooms, you need building blocks. Different blocks do different things:
- Some blocks hold numbers (how many coins?)
- Some blocks hold words (what’s your hero’s name?)
- Some blocks are like filing cabinets (storing lots of stuff organized)
- Some blocks are like storage boxes (keeping items in order)
Solidity data types are exactly like these building blocks! They help you store and organize information in your smart contracts on the blockchain.
1. Solidity Basics: The Foundation
What is Solidity?
Solidity is a special language that tells computers on the blockchain what to do. Think of it like giving instructions to a robot that guards your treasure chest forever.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MyFirstContract {
// Your code lives here!
}
Breaking it down:
pragma solidity ^0.8.0;= “Hey, use Solidity version 0.8 or newer”contract= Your digital treasure chestMyFirstContract= The name you give it
Why Does This Matter?
Every smart contract is like a promise written in stone. Once you put it on the blockchain, it stays there forever. That’s why getting the basics right is super important!
2. Solidity Data Types: The Building Blocks
Data types tell Solidity what kind of information you want to store.
Numbers: uint and int
uint = Unsigned Integer (only positive numbers, like counting toys)
int = Signed Integer (positive AND negative, like temperature)
uint age = 10; // Your age (can't be negative!)
int temperature = -5; // Winter temperature (can be negative!)
uint256 coins = 1000; // Big number storage
Simple Rule:
- Use
uintwhen the number is NEVER negative - Use
intwhen the number CAN be negative
True or False: bool
Like asking “Yes or No?” questions!
bool isHappy = true; // Yes, I'm happy!
bool isSad = false; // No, I'm not sad!
Text: string
For storing words and sentences.
string name = "Hero";
string greeting = "Hello World!";
Wallet Addresses: address
Every person on the blockchain has a unique address, like a home address but for money.
address myWallet = 0x1234...abcd;
address payable treasure = payable(0x5678...);
The payable keyword means this address can RECEIVE money!
Fixed-Size Data: bytes
For storing raw data, like a secret code.
bytes32 secretCode = "abc123...";
bytes1 smallData = 0x42;
Quick Summary Table
| Type | What It Stores | Example |
|---|---|---|
uint |
Positive numbers | uint coins = 100; |
int |
Any numbers | int temp = -10; |
bool |
True/False | bool isOpen = true; |
string |
Text | string name = "Bob"; |
address |
Wallet address | address user = 0x...; |
bytes32 |
Fixed raw data | bytes32 hash = 0x...; |
3. Solidity Mappings: The Magic Dictionary
What is a Mapping?
Imagine a phone book. You look up a name, and you get a phone number. That’s exactly what a mapping does!
Name → Phone Number
Alice → 555-1234
Bob → 555-5678
In Solidity:
mapping(string => uint) phoneBook;
// Set values
phoneBook["Alice"] = 5551234;
phoneBook["Bob"] = 5555678;
// Get values
uint aliceNumber = phoneBook["Alice"];
The Most Common Mapping: Address to Balance
mapping(address => uint) balances;
// Check how many coins someone has
balances[0x123...] = 500;
Think of it as: “For every wallet address, tell me how many coins they have!”
Nested Mappings: A Map Inside a Map!
Like a filing cabinet with folders inside folders.
// Who gave permission to who?
mapping(address => mapping(address => bool)) allowed;
// Alice allows Bob to spend her coins
allowed[aliceAddress][bobAddress] = true;
4. Solidity Arrays: The Organized List
What is an Array?
An array is like a line of boxes, each with a number on it (starting from 0!).
Box 0: Apple
Box 1: Banana
Box 2: Cherry
Fixed-Size Arrays
You decide how many boxes you need forever.
uint[3] scores = [10, 20, 30];
// scores[0] = 10
// scores[1] = 20
// scores[2] = 30
Dynamic Arrays
The line can grow or shrink!
uint[] dynamicScores;
// Add items
dynamicScores.push(100);
dynamicScores.push(200);
// Remove last item
dynamicScores.pop();
// Check how many items
uint count = dynamicScores.length;
Array Example: Storing Players
address[] players;
function join() public {
players.push(msg.sender);
}
function getPlayerCount() public view returns(uint) {
return players.length;
}
5. Solidity Structs: Custom Building Blocks
What is a Struct?
Sometimes the basic blocks aren’t enough. What if you want to describe a whole person? Name, age, and wallet all together?
A struct lets you create your own custom type!
struct Player {
string name;
uint age;
uint score;
address wallet;
}
Using Your Struct
// Create a player
Player memory hero = Player({
name: "Dragon Slayer",
age: 25,
score: 9999,
wallet: 0x123...
});
// Access parts of it
string heroName = hero.name;
uint heroScore = hero.score;
Struct with Mapping: Powerful Combo!
mapping(address => Player) public players;
function registerPlayer(string memory _name) public {
players[msg.sender] = Player({
name: _name,
age: 0,
score: 0,
wallet: msg.sender
});
}
6. Solidity Enums: The Choice Menu
What is an Enum?
An enum is like a menu of choices. Instead of remembering numbers, you use friendly names!
Without enum (confusing):
Status 0 = Waiting
Status 1 = Playing
Status 2 = Finished
With enum (clear!):
enum GameStatus { Waiting, Playing, Finished }
Using Enums
enum OrderStatus {
Pending, // = 0
Shipped, // = 1
Delivered, // = 2
Cancelled // = 3
}
OrderStatus public status = OrderStatus.Pending;
function shipOrder() public {
status = OrderStatus.Shipped;
}
function isDelivered() public view returns(bool) {
return status == OrderStatus.Delivered;
}
Why Use Enums?
- Code is easier to read
- Fewer mistakes (can’t accidentally use
status = 5) - Self-documenting (you know exactly what each state means)
7. Solidity Data Locations: Where Does Data Live?
The Three Homes for Data
In Solidity, data can live in three different places:
graph TD A[Data Location] --> B[Storage] A --> C[Memory] A --> D[Calldata] B --> B1[Permanent<br>Like a hard drive] C --> C1[Temporary<br>Like RAM] D --> D1[Read-only<br>Input only]
Storage: The Permanent Home
Data saved in storage stays forever on the blockchain.
contract MyContract {
uint public savedNumber; // Lives in storage!
function save(uint _num) public {
savedNumber = _num; // Saved permanently
}
}
Use for: Contract state variables that need to persist.
Memory: The Temporary Home
Data in memory exists only during a function call, then disappears.
function processName(string memory _name) public {
string memory greeting = string.concat("Hello, ", _name);
// 'greeting' disappears after function ends
}
Use for: Temporary variables inside functions.
Calldata: The Read-Only Input
calldata is for function inputs that won’t be modified. It’s cheaper than memory!
function readOnly(string calldata _input) external {
// Can read _input, but cannot change it
}
Use for: External function parameters you only need to read.
Quick Reference
| Location | Persistent? | Can Modify? | Cost |
|---|---|---|---|
storage |
Yes | Yes | Expensive |
memory |
No | Yes | Medium |
calldata |
No | No | Cheapest |
Golden Rule
// Contract-level = storage (automatic)
uint public balance;
// Function parameters = memory or calldata
function process(string memory name) public { }
// Local complex types = must specify!
function example() public {
uint[] memory tempArray = new uint[](5);
}
Putting It All Together: A Mini Game Contract
Here’s a real example using everything we learned:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract TreasureGame {
// Enum for game state
enum Status { Open, Closed }
// Struct for player
struct Player {
string name;
uint score;
bool hasJoined;
}
// State variables (storage)
Status public gameStatus;
address[] public playerList;
mapping(address => Player) public players;
// Join the game
function join(string calldata _name) external {
require(!players[msg.sender].hasJoined);
players[msg.sender] = Player({
name: _name,
score: 0,
hasJoined: true
});
playerList.push(msg.sender);
}
// Add score
function addScore(uint _points) external {
require(players[msg.sender].hasJoined);
players[msg.sender].score += _points;
}
// Get player count
function getPlayerCount() external view returns(uint) {
return playerList.length;
}
}
Your Learning Journey Complete!
You now understand:
- Basics: How to write a simple contract
- Data Types: Numbers, booleans, strings, addresses
- Mappings: Key-value lookup tables
- Arrays: Ordered lists of items
- Structs: Custom data types
- Enums: Named choice menus
- Data Locations: Where data lives (storage, memory, calldata)
You’re ready to build amazing smart contracts!
Remember: Every expert was once a beginner. Keep practicing, keep building, and keep learning!