[Part 1] Day 2 of #30DaysOfWeb3 : Lets solidify Solidity
Lets start understanding solidity and build a cool smart contract with it.
Photo by Milad Fakurian on Unsplash
We will be building a cool shopping store with solidity in this blog.
Solidity is used to write smart contracts for EVM based blockchains. Its a statically typed language. Its syntax is very similar to Javascript and C.
Basic Syntax
First we have to specify the license and then the Solidity version we want to use using pragma keyword. After that name the contract. All code goes inside the contract scope block.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract Store {
}
Data Types
Solidity provides below data types :
Type | Description |
bool | can store either true or false. Its default value is false. |
uint | Unsigned integers can be positive or zero and range from 8 bits to 256 bits. Its default value is 0. |
int | Integers can be positive, negative, or zero and range from 8 bits to 256 bits. Its default value is 0 |
address | use to store ethereum addresses which holds 20 byte value. Its default value is 0x0000000000000000000000000000000000000000 |
string | series of characters/symbol/digits enclosed using quotes. |
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract LearnPrimitiveTypes {
string public greet = "Hello World!";
bool public boo = true;
/* uint8 ranges from 0 to 2^8 - 1
uint16 ranges from 0 to 2^16 - 1 ...
uint256 ranges from 0 to 2^256 - 1 */
uint8 public u8 = 1;
uint public u256 = 456;
uint public u = 123; // uint is an alias for uint256
/* Like uint, different ranges are available from int8 to int256 */
int8 public i8 = -1;
int public i = -123; // int is same as int256
address public addr = 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c;
}
Variables
Solidity supports 3 types of variables :
Variable Type | Description |
State Variables | State Variables are stored in the contract storage i.e on blockchain. |
Local Variables | Local Variables are stored in the memory and their values are only accessible within the function. |
Global Variables | These are special variables in global namespace used to retrieve information about the blockchain, particular addresses, contracts, and transactions. |
Variables in solidity have 3 different places to store data :
- Memory: Variables that are only available within a function and are destroyed after function execution. Local variables are stored in memory.
- Storage: Variables of this type are permanently stored and are also called state variables. Storage is expensive on the Ethereum blockchain. 1 MB of storage will cost you many bucks.
- Call data : Same as memory but there value cannot be modified.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract LearnVariables {
// State variables are stored on the blockchain.
string public text = "Hello";
uint public num = 123;
uint public blockNumber;
function doSomething(string memory _name, uint _num) public {
// Local variables are not saved to the blockchain.
uint i = 456;
string memory greet = "Hello";
// Here are some global variables
uint blockNumber = block.number;
uint timestamp = block.timestamp; // Current block timestamp
address sender = msg.sender; // address of the caller
}
}
Lets now apply our above knowledge in building our Shopping Store.
- We defined storeName as string to give a name to our shopping store.
- We also defined totalItemsSold and totalSales to keep track of our store statistics.
- We will store our shopping store's owner address into merchant variable.
- The variable isSaleOn specifies if discounted rates are available on items or not. Only Owner can either start a sale or end the sale.
- Variable discountPercentage will hold the discount percentage that is to be given on total bill during the sale period.
Refer Solidity documentation for other types.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract Store {
string public storeName = "My Awesome Store";
address public merchant;
bool public isSaleOn = false;
uint public discountPercentage = 10;
uint private totalSales;
uint private totalItemsSold;
uint private discountsGiven;
}
Data Structures
Arrays, mappings and structs are all reference types i.e they store the address instead of value directly. Multiple reference type variables could reference the same location, and a change in one variable would affect the others.
Data Structure | Description |
Arrays | There are two types of arrays, compile-time fixed-size and dynamic arrays. For fixed-size arrays, we need to declare the size of the array before it is compiled. The size of dynamic arrays can be changed after the contract has been compiled. |
Structs | Structs are a collection of variables that can consist of different data types. We can define custom data types in the form of structs. |
Mappings | Mappings are a collection of key-value pairs. Mappings cannot be iterated like an array. If we don't know a key we won't be able to access its value. By Default all unknown/known key's value will be 0 |
Enums | Enums are custom data types consisting of a limited set of constant values. We use enums when our variables should only get assigned a value from a predefined set of values. |
Structs
Operations on Structs | Description |
---|---|
Declaring a Struct |
struct Item { string name; bool isAvailable; }
|
Initializing structs |
Way 1 : Passing Positional parametersItem storage myItem = Item("Gaming Mouse", true); Way 2 : Key-value Pair Style Item storage myItem = Item({name : "Gaming Mouse", isAvailable: true}); Way 3 : Initialize empty struct and update its members Item storage myItem; myItem.name = "Gaming Mouse"; myItem.isAvailable: true; |
Accessing structs |
// Access struct member using dot operator
string myStructName = myItem.name;
|
Updating struct |
// Use the dot operator and assign it a new valuemyItem.name = "RedGear Mouse";
|
Lets define our shopping store's structs that we will need.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract Store {
// Item Struct
struct Item {
uint itemId;
string itemDetailsURI; // IPFS Hash for retrieving item details
uint price;
uint availableQty;
}
// Order Struct. itemId and qty are arrays which are co-related.
// Item at index in itemId will have its quantity at same index in qty.
struct Order {
uint orderId;
uint[] itemId;
uint[] qty;
uint grossTotal;
uint discount;
uint netTotal;
uint orderCreatedTimestamp;
Status shippingStatus;
address placedBy;
}
}
Arrays
Operations on Arrays | Description |
---|---|
Declaring an Array |
uint[5] public fixedArr; // Fixed Size Arrays
uint[] public dynamicArr; // Dynamic Arrays
|
Initializing an Array |
uint[] public arrInit = [1, 2, 3]; // Initializing all at once
uint[3] public arrInit2; // Initializing one by one arrInit2[0] = 1; arrInit2[1] = 2; // If not initialized the default value of all elements is zero uint[5] public arrNotInit;
|
Add/Remove from Dynamic Array |
// Adds in the end and increase length by 1
arr.push(i); // Removes last element and decrease length by 1 arr.pop();
|
Delete an Element |
// This will just make the 5th element 0 but will not remove it
delete arr[4];
|
Get Array Length |
//Returns the length of array arr uint len = arr.length;
|
Lets define our shopping store arrays that we will need.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract Store {
// An array of 'Order' structs
Order[] public orders;
// An array of 'Item' structs
Item[] public items;
}
Mappings
Operations On Mappings | Description |
---|---|
Create Mapping |
// Syntax mapping(KeyType => ValueType) <visibility> <mapname>; The key can be any built-in value type or any contract, but not a reference type. The value type can be of any type. mapping(uint => address) public numberToAddress;
|
Accessing values |
// Just like arrays, provide the name of the mapping and the key in brackets // No error if we query a non-existing key. Because by default all possible key will have a value 0 uint value = numberToAddress[i];
|
Setting values |
// Mapping’s name and key in brackets and assigning it a new value myMap[_key] = 456;
|
Removing values |
// This will just make the specified key's value to 0 but will not remove it
delete myMap[_key];
|
Nested Mapping |
mapping(address => mapping(uint => string)) public nm; Declare nm[_outerKey][_innerKey] = "Yuhuu! Solidity Rocks!! "; Assign string value = nm[_outerKey][_innerKey] ; Accessdelete nm[_outerKey][_innerKey]; Delete i.e Reset it to 0
|
Lets define our shopping store's mappings that we will need.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract Store {
// Address as key will return all orderIds of that user as value.
// We can then run a loop and gets all order details
mapping(address => Order[]) private customerOrders;
mapping(address => string) private shippingAddress;
mapping(uint => string) private orderShipping;
}
Enums
Operations on enums | Description |
---|---|
Defining enums |
// Enums are stored as consecutive unsigned integers starting from 0 rather than strings.enum Status { Created, // Element 0 Attended, // Element 1 Cancelled // Element 2 }
|
Initializing a enum |
// By Default eventStatus will be 0(Pending) if not initialized.Status public eventStatus; eventStatus = Status.Attended; OR
eventStatus = 1;
|
Accessing an enum value |
// Simple. Name of variable will return the value
uint getStatus = eventStatus; // Returns 1 Status getStatusString = eventStatus; // Returns "Attended"
|
Updating an enum value |
eventStatus = Status.Cancelled; OR
eventStatus = 2;
|
Removing an enum value |
// Deleting will set the eventStatus variable value to 0(Created) delete eventStatus;
|
Lets define our shopping store's enums that we will need.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract Store {
// We are using this enum in our Order struct
enum Status {
"Accepted",
"Dispatched",
"Delivered",
"Cancelled"
}
}
Hope you enjoyed it and found it useful.
We will covert Functions, Inheritance, Modifiers and more in Part 2. I will share the link to my github repo to view the full source code of my shopping store contract there. Stay Tuned. :)
Sources : Learn ETH by dacade.org and remix.ethereum.org