Solidity 101

Learn about Solidity in this article by Brenn Hill, a senior software engineer with a master’s degree in Information Science from UNC-CH. He strives to work with business to ensure that tech projects achieve good ROI and solve key business problems.

Solidity 101

Solidity is a statically typed programming language introduced by the Ethereum foundation that makes it possible to create decentralized applications on top of Ethereum blockchain, either to be used for creating another cryptocurrency token or for any other use case in which blockchain can have an essential role.

Ethereum runs smart contracts on its platform; these are applications that use blockchain technology to perform the required action, enabling users to create their own blockchain and also issue their own alternative cryptocurrency. This is made possible by coding in Solidity, which is used for writing smart contracts that are to be executed on the Ethereum blockchain and perform the programmed tasks.

Solidity, influenced by C++, Python, and JavaScript, was proposed in August 2014 and developed by the Ethereum project’s solidity team. The complete application is deployed on the blockchain, including smart contract, frontend interface, and other modules; this is known as a DApp or a Decentralized Application.

Solidity is also known as a contract-oriented language, since contracts are similar to classes in object-oriented languages. The Solidity language is loosely based on ECMAScript (JavaScript); hence, a prior knowledge of the same would be helpful in understanding Solidity. Here are some tools required to develop, test, and deploy smart contracts programmed in Solidity:

· TestNet: The choice of TestNet to work on, the specified network ID to be used.

· Compiler: Choosing the required compiler, for example solc , is a solidity compiler; it is included in most of the nodes and also available as a standalone package.

· Web3.js: The library that helps in the connection between the Ethereum network and our DApp via HTTP or the IPC network connection.

· Framework: It is important to choose a framework from those available for contract compilation and the deployment and other tasks. Some of the frameworks used are Truffle, Embark, Dapple, and others.

The basics of working on Solidity

If you program regularly, you are already aware of code editors or Integrated Development Environments (IDEs). There is a list of integrations available for various IDEs already present; apart from this, Ethereum foundation has also released a browser-based IDE with integrated compiler and a Solidity runtime environment, without the server components for writing and testing smart contracts. It can be found at remix.ethereum.org.

Using the compiler

For small and learning-based DApps projects, it is suggested to work on the browser-based compiler by the Ethereum foundation: Remix. Another way is to install the Solidity compiler on to your machine. solc can be installed from npm using the following command:

npm install -g solc

Solidity can also be built from the source by cloning the Git repository present on the GitHub link at https://github.com/ethereum/solidity.git.

Programming in Solidity

In this section, we will be discussing the structure and elements of a Solidity source file; we will discuss the layout, structure, data types, its types, units, controls, expressions, and other aspects of Solidity. The format extension of a solidity file is .sol .

Laying out a Solidity file

Solidity is going through active development and has lot of regular changes and suggestions from a huge community; hence, it is important to specify the version of a solidity file at the start of the source file, to avoid any conflict. This is achieved by the Pragma version. This is defined at the start of the solidity file so that any person looking to run the file knows about the previous version. Take a look at this code:

pragma solidity ^0.4.24;

By specifying a version number that specific source file will compile with a version earlier or later than the specified version number.

Importing files

Similar to ECMAScript, a Solidity file is declared using the import statement as follows:

import “filename.sol”;

The preceding statement will import all the symbols from the filename.sol file into the current file as global statements. Paths are also supported while importing a file, so you can use / , . , or .. similar to JavaScript.

Commenting

Single line ( // ) comments and multi-line( /* … */ ) comments are used, although apart from this there is another type of comment style called Natspec Comment, which is also possible; in this type of comment, we either use /// or /** … */ , and they are to be used only earlier function declaration or statements.

Natspec is short for natural specification; these comments as per the latest solidity version (0.4.24) do not apply to variables, even if the variables are public. Here is a small code snippet with an example of such these types of comments:

pragma solidity ^0.4.19; /// @title A simulator for Batman, Gotham’s Hero /// @author DC-man /// @notice You can use this contract for only the most basic simulation /// @dev All function calls are currently implement without side effects contract Batman { /// @author Samanyu Chopra /// @notice Determine if Bugs will accept `(_weapons)` to kill /// @dev String comparison may be inefficient /// @param _weapons The name weapons to save in the repo (English) /// @return true if Batman will keep it, false otherwise function doesKeep(string _weapons) external pure returns (bool) { return keccak256(_weapons) == keccak256(“Shotgun”); } }

Tags

They are used in the Natspec comments; each of the tags has its own context based on its usage, as shown in the following table:

Structure of a contract

Every contract in Solidity is similar to the concept of classes. Contracts can inherit from other contracts, in a fashion similar to classes. A contract can contain a declaration of the following:

· State variables

· Functions

· Function modifiers

· Events

· Struct types

· Enum types

State variables

These are the values that are permanently stored in the contract storage, for example:

pragma solidity ^0.4.24; contract Gotham { uint storedData; // State variable // … }

Functions

Functions can be called internally or externally, for example:

pragma solidity ^0.4.24; contract Gotham { function joker() public Bat { // Function // … } }

Function modifiers

Function modifiers can be used to amend the semantics of functions in a declaration. That is, they are used to change the behavior of a function. For example, they are used to automatically check a condition before executing the function, or they can unlock a function at a given timeframe as required. They can be overwritten by derived contracts, as shown here:

pragma solidity ^0.4.24; contract Gotham { address public weapons; modifier Bank() { // Modifier require( msg.sender == coins, “Only coins can call this.” ); _; } function abort() public coinsbuyer { // Modifier usage // … } }

Events

Events allow convenient usage of the EVM, via the frontend of the DApp. Events can be heard and maintained. Take a look at this code:

pragma solidity ^0.4.24; contract Attendance { event Mark_attendance(string name, uint ID); // Event function roll_call() public marking { // … emit Mark_attendance(Name, ID); //Triggering event } }

Types

In Solidity, the type of each variable needs to be specified at compile time. Complex types can also be created in Solidity by combining the complex types. There are two categories of data types in Solidity: value types and reference types.

Value types

Value types are called value types because the variables of these types hold data within its own allocated memory.

Boolean

This type of data has two values, either true or false, for example:

bool b = false;

The preceding statement assigns false to boolean data type b .

Integers

This value type allocates integers. There are two sub-types of integers, that is int and uint , which are signed integer and unsigned integer types respectively. Memory size is allocated at compile time; it is to be specified using int8 or int256 , where the number represents the size allocated in the memory. Allocating memory by just using int or uint , by default assigns the largest memory size.

Address

This value type holds a 20-byte value, which is the size of an Ethereum address (40 hex characters or 160 bits). Take a look at this:

address a = 0xe2793a1b9a149253341cA268057a9EFA42965F83

This type has several members that can be used to interact with the contract. These members are as follows:

· balance

· transfer

· send

· call

· callcode

· delegatecall

balance returns the balance of the address in units of wei, for example:

address a = 0xe2793a1b9a149253341cA268057a9EFA42965F83; uint bal = a.balance;

transfer is used to transfer from one address to another address, for example:

address a = 0xe2793a1b9a149253341cA268057a9EFA42965F83; address b = 0x126B3adF2556C7e8B4C3197035D0E4cbec1dBa83; if (a.balance > b.balance) b.transfer(6);

Almost the same amount of gas is spent when we use transfer , or send members. transfer was introduced from Solidity 0.4.13, as send does not send any gas and also does not propagate exceptions. Transfer is considered a safe way to send ether from one address to another address, as it throws an error and allows someone to propagate the error.

The call , callcode , and delegatecall are used to interact with functions that do not have Application Binary Interface (ABI). call returns a Boolean to indicate whether the function ran successfully or got terminated in the EVM.

When a does call on b , the code runs in the context of b , and the storage of b is used. On the other hand, when a does callcode on b , the code runs in the context of a , and the storage of a is used, but the code of and storage of a is used.

The delegatecall function is used to delegate one contract to use another contract’s storage as required.

Array value type

Solidity has a fixed and dynamic array value type. Keywords range from bytes1 to bytes32 in a fixed-sized byte array. On the other hand, in a dynamic-sized byte array, keywords can contain bytes or strings. bytes are used for raw byte data and strings is used for strings that are encoded in UTF-8 .

length is a member that returns the length of the byte array for a fixed-size byte array or for a dynamic-size byte array.

A fixed-size array is initialized as test[10] , and a dynamic-size array is initialized as test2[ .

Literal

Literals are used to represent a fixed value; there are multiple types of literals that are used; they are as follows:

· Integer literals

· String literals

· Hexadecimal literals

· Address literals

Integer literals are formed with a sequence of numbers from 0 to 9. Octal literals and ones starting with 0 are invalid, since the addresses in Ethereum start with 0. Take a look at this:

int a = 11;

String literals are declared with a pair of double( “…” ) or single( ‘…’ ) quotes, for example:

Test = ‘Batman’; Test2 = “Batman”;

Hexadecimal literals are prefixed with the keyword hex and are enclosed with double ( hex”69ed75" ) or single ( hex’69ed75' ) quotes.

Hexadecimal literals that pass the address checksum test are of address type literal, for example:

0xe2793a1b9a149253341cA268057a9EFA42965F83; 0x126B3adF2556C7e8B4C3197035D0E4cbec1dBa83;

Enums

Enums allow the creation of user-defined type in Solidity. Enums are convertible to and from all integer types. Here is an example of an enum in Solidity:

enum Action {jump, fly, ride, fight};

Function

There are two types of functions: internal and external. Internal functions can be called from inside the current contract only. External functions can be called via external function calls.

Function Modifiers

There are various modifiers available, which you are not required to use, for a Solidity-based function. Take a look at these:

· pure

· constant

· view

· payable

The pure functions can’t read or write from the storage; they just return a value based on its content. The constant modifier function cannot write in the storage in any way. Although, the post-Solidity Version 0.4.17 constant is deprecated to make way for pure and view functions, view acts just like constant in that its function cannot change storage in any way. payable allows a function to receive ether while being called.

Multiple modifiers can be used in a function by specifying each by white-space separation; they are evaluated in the order they are written.

Reference types

These are passed on by reference; these are very memory heavy, due to the allocation of memory they constitute.

Structs

A struct is a composite data type that is declared under a logical group. Structs are used to define new types. It is not possible for a struct to contain a member of its own type, although a struct can be the value type of a mapping member. Here is an example of a struct:

struct Gotham { address Batcave; uint cars; uint batcomputer; uint enemies; string gordon; address twoface; }

Data location

This specifies where a particular data type will be stored. It works with arrays and structs. The data location is specified using the storage or memory keyword. There is also a third data location, calldata , which is non-modifiable and non-persistent. Parameters of external functions use calldata memory. By default, parameters of functions are stored in memory ; other local variables make use of storage .

Mapping

Mapping is used for key-to-value mapping. Mappings can be seen as hash tables that are virtually initialized such that every possible key exists and is mapped to a default value. The default value is all zeros. The key is never stored in a mapping, only the keccak256 hash is used for value lookup. Mapping is defined just like any other variable type. Take a look at this code:

contract Gotham { struct Batman { string friends; string foes; int funds; string fox; } mapping (address => Batman) Catwoman; address[] public Batman_address; }

The preceding code example shows that Catwoman is being initialized as a mapping.

Units and global variables

Global variables can be called by any Solidity smart contract. They are mainly used to return information about the Ethereum blockchain. Some of these variables can also perform various functions. Units of time and ether are also globally available. Ether currency numbers without a suffix are assumed to be wei. Time-related units can also be used and, just like currency, conversion among them is allowed.

If you found this article interesting, you can explore Blockchain Developer’s Guide to build real-world projects like a smart contract deployment platform, betting apps, wallet services, and much more using blockchain. Blockchain Developer’s Guide takes you through the electrifying world of blockchain technology and helps you build efficient decentralized applications.