Beginners Guide To Solidity Programming.

Beginners Guide To Solidity Programming.

After learning the basics of Blockchain Technology, I decided to move forward and learn about the Solidity programming language.

IDE

Remix IDE, is a no-setup tool with a GUI for developing smart contracts. Used by experts and beginners alike. It will get you going in double time and plays well with other tools, and allows for a simple deployment process to the chain of your choice. Remix is famous for our visual debugger.

You can visit here. It is written in JavaScript and supports both Solidity and Vyper.

Compilation Process

Mainnet V/S Testnet

Mainnet

Testnet

Used for actual transactions with value.

Used for testing smart contracts and decentralized applications.

Mainnet's network ID is 1.

Testnets have network IDs of 3, 4 and 42.

Example: Ethereum Mainnet.

Example: Rinkeby Test Network.

Metamask

It is a web3/blockchain wallet used to:

  • Store Ether

  • Send Ether

  • Receive Ether

  • Run Dapps

  • Swap Tokens

Contract Deployment Process

  • Contract bytecode is public in a readable form.

  • Contracts don't have to be public.

  • Bytecode is immutable.

  • ABI acts as a bridge between applications and Smart Contracts.

  • ABI and Bytecode cannot be generated without source code.

ByteCode

It is the information that our solidity code gets "translated" into. It contains instructions to the computer in binary.

Opcode

Opcodes are the low-level human-readable instructions of the program. All opcodes have their hexadecimal counterparts.

ABI

The Solidity compiler, also known as solc, compiles Solidity-based smart contracts into EVM understandable bytecode and the Application Binary Interface (ABI). The bytecode and Solidity Contract ABI are the primary components for interacting with Ethereum Smart Contracts.

Solidity

  • Solidity is a high-level statically typed programming language.

  • With Solidity, you can create contracts for uses such as voting, crowdfunding, blind auctions and multi-signature wallets.

  • Case Sensitive.

  • For the latest update - Visit Solidity documentation.

// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.5.0 < 0.9.0;
contract Identify
{
    string name;
    uint age;
    constructor() public{
    name = "Ravi";
    age = "17";
    }
    function getname() view public returns (string memory){
    return name;
    }
    function getAge() view public returns (uint){
    return age;
    }
}

Variables

State Variables

Variables declared in a contract that is not within any function are state variables. It is these state variables that are permanently stored in a blockchain by miners.

// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.5.0 < 0.9.0;
contract State
{
    uint public age; // State variable
    function setAge() public{
    age = 10;
    }
}
  • To change the default values of state variables -

    • using the contract's constructor.

    • Initializing the variable at declaration.

    • Using the setter function.

  • Permanently stored in contract storage.

  • Cost gas (expensive).

  • Storage is not dynamically allocated.

  • An instance of the contract cannot have other state variables besides those already declared.

Local variables

These are variables that are defined within a function in solidity and used to store temporary data that is not stored on the ETH blockchain. Local variables are created when a function is executed and destroyed when the function completes.

// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.5.0 < 0.9.0;
contract Local
{
    function store() pure public returns (uint){
    uint age = 10;
    return age;
    }
}
  • Declared inside functions are kept on the stack, not on storage.

  • Don't cost gas.

  • Some types reference the storage by default.

  • Memory keywords can't be used at the contract level.

Global Variables

These are special variables that exist in the global workspace and provide information about the blockchain and transaction properties.

// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.5.0 < 0.9.0;
contract Local
{
    function getter() public view returns(uint block _no, uint timestamp, address msgSender){
    return(block.number, block.timestamp, msg.sender);
}

Functions

A function is a group of reusable code that can be called anywhere in your program. This eliminates the need of writing the same code again and again. It helps programmers in writing modular codes. Functions allow a programmer to divide a big program into several small and manageable functions.

// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.5.0 < 0.9.0;
contract Test {
   function getResult() public view returns(uint){
      uint a = 1; // local variable
      uint b = 2;
      uint result = a + b;
      return result;
   }
}

There are two types of functions, setter and getter.

  • When you call a setter function, it creates a transaction that needs to be mined and costs gas because it changes the blockchain. Vice versa for the getter function.

  • When you declare a public state variable a getter function is automatically created.

  • By default variable visibility is private.

Constructors

Constructor is a special function declared using the constructor keyword. It is an optional function and is used to initialize the state variables of a contract.

  • A contract can have only one constructor.

  • A constructor code is executed once when a contract is created and it is used to initialize the contract state.

  • After a constructor code is executed, the final code is deployed to the blockchain. This code includes public functions and codes reachable through public functions. Constructor code or any internal method used only by the constructor is not included in the final code.

  • A constructor can be either public or internal.

  • An internal constructor marks the contract as abstract.

  • In case, no constructor is defined, a default constructor is present in the contract.

// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.5.0 < 0.9.0;
contract Base {
   uint data;
   constructor(uint _data) public {
      data = _data;   
   }
}
contract Derived is Base (5) {
   constructor() public {}
}

Data-Types

While writing programs in any language, you need to use various variables to store various information. Variables are nothing but reserved memory locations to store values. This means that when you create a variable you reserve some space in memory.

Solidity offers the programmer a rich assortment of built-in as well as user-defined data types.

TypesKeywordValues
Booleanbooltrue/false
Integerint/uintSigned and unsigned integers of varying sizes.
Integerint8 to int256Signed int from 8 bits to 256 bits. int256 is the same as int.
Integeruint8 to uint256Unsigned int from 8 bits to 256 bits. uint256 is the same as uint.
Fixed Point Numbersfixed/unfixedSigned and unsigned fixed point numbers of varying sizes.
Fixed Point Numbersfixed/unfixedSigned and unsigned fixed point numbers of varying sizes.
Fixed Point NumbersfixedMxNSigned fixed-point number where M represents the number of bits taken by type and N represents the decimal points. M should be divisible by 8 and goes from 8 to 256. N can be from 0 to 80. fixed is the same as fixed128x18.
Fixed Point NumbersufixedMxNUnsigned fixed point number where M represents several bits taken by type and N represents the decimal points. M should be divisible by 8 and goes from 8 to 256. N can be from 0 to 80. fixed is the same as ufixed128x18.

Overflow & Underflow

Simply put, overflow and underflow happen when we assign a value that is out of range of the declared data type of the variable. If the (absolute) value is too big, we call it overflow, if the value is too small, we call it underflow.

Array

An array is a data structure, which stores a fixed-size sequential collection of elements of the same type. An array is used to store a collection of data, but it is often more useful to think of an array as a collection of variables of the same type.

// Declaring Array
type arrayName [ arraySize ];

//Initializing Array
uint balance[3] = [1, 2, 3];

//Creating Dynamic Memory Arrays
uint size = 3;
uint balance[] = new uint[](size);

// Accessing Array Elements
uint salary = balance[2];
// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.5.0 < 0.9.0;

contract test {
   function testArray() public pure{
      uint len = 7; 

      //dynamic array
      uint[] memory a = new uint[](7);

      //bytes is same as byte[]
      bytes memory b = new bytes(len);

      assert(a.length == 7);
      assert(b.length == len);

      //access array variable
      a[6] = 8;

      //test array variable
      assert(a[6] == 8);

      //static array
      uint[3] memory c = [uint(1) , 2, 3];
      assert(c.length == 3);
   }
}

Loops

While Loop

The purpose of a while loop is to execute a statement or code block repeatedly as long as an expression is true. Once the expression becomes false, the loop terminates.

pragma solidity ^0.5.0;

contract SolidityTest {
   uint storedData; 
   constructor() public{
      storedData = 10;   
   }
   function getResult() public view returns(string memory){
      uint a = 10; 
      uint b = 2;
      uint result = a + b;
      return integerToString(result); 
   }
   function integerToString(uint _i) internal pure 
      returns (string memory) {

      if (_i == 0) {
         return "0";
      }
      uint j = _i;
      uint len;

      while (j != 0) {
         len++;
         j /= 10;
      }
      bytes memory bstr = new bytes(len);
      uint k = len - 1;

      while (_i != 0) { // while loop
         bstr[k--] = byte(uint8(48 + _i % 10));
         _i /= 10;
      }
      return string(bstr);
   }
}

// Output => string: 12

For Loop

The for loop is the most compact form of looping. It includes the following three important parts.

pragma solidity ^0.5.0;

contract SolidityTest {
   uint storedData; 
   constructor() public{
      storedData = 10;   
   }

   function getResult() public view returns(string memory){
      uint a = 10; 
      uint b = 2;
      uint result = a + b;
      return integerToString(result); 
   }

   function integerToString(uint _i) internal pure 
      returns (string memory) {
      if (_i == 0) {
         return "0";
      }
      uint j=0;
      uint len;
      for (j = _i; j != 0; j /= 10) {  //for loop example
         len++;         
      }
      bytes memory bstr = new bytes(len);
      uint k = len - 1;
      while (_i != 0) {
         bstr[k--] = byte(uint8(48 + _i % 10));
         _i /= 10;
      }
      return string(bstr);//access local variable
   }
}

// Output => string: 12

Do-while Loop

The do...while loop is similar to the while loop except that the condition check happens at the end of the loop.

pragma solidity ^0.5.0;

contract SolidityTest {
   uint storedData; 
   constructor() public{
      storedData = 10;   
   }
   function getResult() public view returns(string memory){
      uint a = 10; 
      uint b = 2;
      uint result = a + b;
      return integerToString(result); 
   }
   function integerToString(uint _i) internal pure 
      returns (string memory) {

      if (_i == 0) {
         return "0";
      }
      uint j = _i;
      uint len;

      while (j != 0) {
         len++;
         j /= 10;
      }
      bytes memory bstr = new bytes(len);
      uint k = len - 1;

      do {                   // do while loop    
         bstr[k--] = byte(uint8(48 + _i % 10));
         _i /= 10;
      }
      while (_i != 0);
      return string(bstr);
   }
}

// Output => string: 12

If-Else

Here when the conditions of if statements are True then the code inside the if block is executed, else the code inside the else block is executed.

Below is the syntax of the if… else statement in Solidity.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
contract DemoContract 
{
    uint storedData;
    function set(uint x) public 
    {
        storedData = x;
         if (storedData < 50)
        {
            storedData = storedData*0;          
        }
        else
        {
            storedData = storedData*2;
        }
    }
    function get() public view returns (uint) 
    {
        return storedData;
    }
}

Enum

Enums are a way of creating user-defined data types, it is usually used to provide names for integral constants which makes the contract better for maintenance and reading. Enums restrict the variable with one of a few predefined values, these values of the enumerated list are called enums. Options are represented with integer values starting from zero, a default value can also be given for the enum. By using enums it is possible to reduce the bugs in the code.

Syntax:

enum <enumerator_name> { 
            element 1, element 2,....,element n
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.5.0;
contract Types { 
    // Creating an enumerator
    enum week_days
    {
      Monday,
      Tuesday,
      Wednesday,
      Thursday,
      Friday,
      Saturday,
      Sunday
     } 
    // Declaring variables of
    // type enumerator
    week_days week;   
    week_days choice;
    // Setting a default value
    week_days constant default_value
      = week_days.Sunday;
    // Defining a function to
    // set value of choice
    function set_value() public {
      choice = week_days.Thursday;
    }
    // Defining a function to
    // return value of choice
    function get_choice(
    ) public view returns (week_days) {
      return choice;
    }
    // Defining function to
    //  return default value
    function getdefaultvalue(
    ) public pure returns(week_days) { 
        return default_value; 
    } 
}

Struct

Structs in Solidity allow you to create more complicated data types that have multiple properties. You can define your type by creating a struct.

They are useful for grouping related data.

Structs can be declared outside of a contract and imported into another contract. Generally, it is used to represent a record. To define a structure struct keyword is used, which creates a new data type.

Syntax:

struct <structure_name> {  
   <data type> variable_1;  
   <data type> variable_2; 
}
// Solidity program to demonstrate
// how to use 'structures'
pragma solidity ^0.5.0;
// Creating a contract
contract test {
// Declaring a structure
struct Book {
    string name;
    string writter;
    uint id;
    bool available;
}
// Declaring a structure object
Book book1;
// Assigning values to the fields
// for the structure object book2
Book book2
    = Book("Building Ethereum DApps",
            "Roberto Infante ",
            2, false);
// Defining a function to set values
// for the fields for structure book1
function set_book_detail() public {
    book1 = Book("Introducing Ethereum and Solidity",
                "Chris Dannen",
                    1, true);
}
// Defining function to print
// book2 details
function book_info(
)public view returns (
    string memory, string memory, uint, bool) {    
        return(book2.name, book2.writter,
            book2.id, book2.available);
    }
// Defining function to print
// book1 details
function get_details(
) public view returns (string memory, uint) {
    return (book1.name, book1.id);
    }
}

Mapping

Mapping in Solidity acts like a hash table or dictionary in any other language. These are used to store the data in the form of key-value pairs, a key can be any of the built-in data types but reference types are not allowed while the value can be of any type. Mappings are mostly used to associate the unique Ethereum address with the associated value type.

Syntax:

mapping(key => value) <access specifier> <name>;
// SPDX-License-Identifier: MIT
pragma solidity ^0.4.18;

contract mapping_example {     
    // Defining structure
    struct student { 
        // Declaring different
        // structure elements
        string name;
        string subject;
        uint8 marks;
    }     
    // Creating mapping
    mapping (address => student) result;
    address[] student_result;     
    //Function adding values to the mapping
    function adding_values() public {
        var student
          = result[0xDEE7796E89C82C36BAdd1375076f39D69FafE252]; 
        student.name = "John";
        student.subject = "Chemistry";
        student.marks = 88;
        student_result.push(
          0xDEE7796E89C82C36BAdd1375076f39D69FafE252) -1; 
    }     
     // Function to retrieve
     // values from the mapping
     function get_student_result(
     ) view public returns (address[]) {
        return student_result;
    } 
    // Function to count number
    // of values in a mapping
    function count_students(
    ) view public returns (uint) {
        return student_result.length;
    }
}

Storage V/S Memory

Storage and Memory keywords in Solidity are analogous to Computer’s hard drive and Computer’s RAM. Much like RAM, Memory in Solidity is a temporary place to store data whereas Storage holds data between function calls. The Solidity Smart Contract can use any amount of memory during the execution but once the execution stops, the Memory is completely wiped off for the next execution. Whereas Storage on the other hand is persistent, each execution of the Smart contract has access to the data previously stored in the storage area.

Every transaction on Ethereum Virtual Machine costs us some amount of Gas. The lower the Gas consumption the better your Solidity code. The Gas consumption of Memory is not very significant as compared to the gas consumption of Storage. Therefore, it is always better to use Memory for intermediate calculations and store the final result in Storage.

  1. State variables and Local Variables of structs, and arrays are always stored in storage by default.

  2. Function arguments are in memory.

  3. Whenever a new instance of an array is created using the keyword ‘memory’, a new copy of that variable is created. Changing the array value of the new instance does not affect the original array.

// A contract is created to demonstrate the ‘storage’ keyword.
pragma solidity ^0.4.17;
contract helloGeeks
{
// Initialising array numbers
int[] public numbers;
// Function to insert values
// in the array numbers
function Numbers() public
{
    numbers.push(1);
    numbers.push(2);

    //Creating a new instance
    int[] storage myArray = numbers;
    // Adding value to the
    // first index of the new Instance
    myArray[0] = 0;
    }
}

Output: When we retrieve the value of the array numbers in the above code, Note that the output of the array is [0,2] and not [1,2].

// Contract is created to demonstrate the keyword ‘memory’.
pragma solidity ^0.4.17;
contract helloGeeks
{
// Initialising array numbers
int[] public numbers;

// Function to insert
// values in the array
// numbers
function Numbers() public
{
    numbers.push(1);
    numbers.push(2);

    //creating a new instance
    int[] memory myArray = numbers;

    // Adding value to the first
    // index of the array myArray
    myArray[0] = 0;
    }
}

Output: When we retrieve the value of the array numbers in the above code, Note that the output of the array is [1,2]. In this case, changing the value of myArray does not affect the value of the array numbers.

Contract Balance

Payable Function

The keyword payable allows someone to send ether to a contract and run a code to account for this deposit.

This code could potentially log an event, modify storage to record the deposit, or it could even revert the transaction if it chooses to do so.

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.8;
contract payable{
    address payable user = payable(0x{user-wallet-address})
    function payEther() public payable{
    }
    function getBalance() public view returns(uint){
    return address(this).balance;
    }
    function sendEtherAccount() public{
    user.transfer(1 ether);
    }
}

Access Modifier

In Solidity, access modifiers are the keywords to decide the level of access provided over variables and functions in a smart contract. Access modifiers can only restrict access to other contracts, but we should keep in mind that all the data on the blockchain can be viewed publicly.

There are four types of access modifiers available in Solidity.

  • Private: It is used to grant access only within a contract.

  • Internal: It is used to grant access within the contract and all the contracts that inherit it.

  • External: It is used to grant access only outside of the contract.

    • We can’t access the external function within our contract. However, they can be accessed using this.function().
  • Public: It is used to grant access within the contract as well as outside of the contract.

svg viewer

Conclusion

Below are the links to resources that I am following for learning Blockchain Development.

If you liked this article do share it with your friends and follow me on my socials.

GitHub LinkedIn Twitter Hashnode

Did you find this article valuable?

Support Mrinmoy Porel by becoming a sponsor. Any amount is appreciated!