Solidity is used for crafting complex Smart Contracts designed to operate on the Ethereum blockchain. This language presents unique strate­gies that dis­tin­guish it from other pro­gram­ming languages.

What is Solidity?

Solidity is a high-level pro­gram­ming language for creating smart contracts on the Ethereum blockchain. Smart contracts are self-executing contracts that automate the exchange of assets between parties. What is special about them is that no in­ter­me­di­aries are needed to ensure com­pli­ance with the smart contract.

Solidity source code is compiled into bytecode and deployed on the Ethereum blockchain as a smart contract. Once done, the smart contract can be executed by any node on the network, and the state is stored on the blockchain. We show an example of a simple contract modeling an NFT vending machine:

pragma Solidity 0.8.7;
contract NFTVendingMachine {
    // Declare state variables
    address public owner;
    mapping (address => uint) public nftBalance;
    // Run on deployment
    constructor() {
        owner = msg.sender;
        nftBalance[address(this)] = 100;
    }
    // Allow the owner to restock the NFT balance
    function restock(uint amount) public {
        require(msg.sender == owner, "Only the owner can restock.");
        nftBalance[address(this)] += amount;
    }
    // Allow anyone to purchase NFTs
    function purchase(uint amount) public payable {
        require(msg.value >= amount * 1 ether, "You must pay at least 1 ETH per NFT");
        require(nftBalance[address(this)] >= amount, "Not enough NFTs in stock to complete this purchase");
        nftBalance[address(this)] -= amount;
        nftBalance[msg.sender] += amount;
    }
}
solidity

Which ap­pli­ca­tions is Solidity suitable for?

Solidity is specif­i­cal­ly designed for creating dis­trib­uted ap­pli­ca­tions or DApps running on the Ethereum Virtual Machine (EVM). Smart contracts are suitable for managing digital assets, creating de­cen­tral­ized exchanges, and im­ple­ment­ing voting systems, among other things.

Web Hosting
Hosting that scales with your ambitions
  • Stay online with 99.99% uptime and robust security
  • Add per­for­mance with a click as traffic grows
  • Includes free domain, SSL, email, and 24/7 support

De­cen­tral­ized finances (DeFi)

Solidity is being used to develop DeFi ap­pli­ca­tions such as de­cen­tral­ized exchanges, credit and lending platforms, pre­dic­tion markets, and cryp­tocur­ren­cies. DeFi has become one of the most popular use cases for blockchain tech­nol­o­gy. In the process, Solidity has become an in­dis­pens­able tool for building DeFi ap­pli­ca­tions on the Ethereum network.

Non-fungible tokens

The non-fungible token (NFT), has enjoyed great pop­u­lar­i­ty since the 2020s. NFTs are unique digital assets stored on the blockchain. They can be digital artworks, sports mem­o­ra­bil­ia or artifacts from the gaming industry. Solidity is used to create the smart contracts that power NFTs.

Delivery chain man­age­ment

Solidity can be used to create smart contracts for mon­i­tor­ing and managing supply chains. The contracts are used to automate various supply chain processes. These include tracking the movement of goods, verifying the au­then­tic­i­ty of products, and pro­cess­ing payments between parties.

Rec­on­cil­i­a­tion systems

Solidity can be used to create smart contracts that implement secure and trans­par­ent voting systems on the blockchain. The contracts can be used to ensure that votes are counted correctly and that the voting process is fair and trans­par­ent.

What are the pros and cons of Solidity?

While Solidity is a powerful language for con­struct­ing smart contracts on the Ethereum blockchain, it has its specific ad­van­tages and dis­ad­van­tages that de­vel­op­ers should consider when de­vel­op­ing smart contracts. Nev­er­the­less, crafting secure smart contracts demands a specific level of pro­fi­cien­cy and caution.

As an il­lus­tra­tion, below is a smart contract that functions as a black hole. Any Ether sent to the contract is per­ma­nent­ly consumed, with no pos­si­bil­i­ty of re­triev­ing the Ether or making a payout:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.9.0;
// This contract swallows all Ether sent to it
contract Blackhole {
    event Received(address, uint);
    receive() external payable {
            emit Received(msg.sender, msg.value);
    }
}
solidity

Ad­van­tages of Solidity

  • Flex­i­bil­i­ty: Solidity is a versatile language. It can be used to develop different smart contracts with a variety of use cases.
  • Security: Solidity was created with a focus on security, in­cor­po­rat­ing char­ac­ter­is­tics such as access controls, exception handling, and failure mech­a­nisms to aid de­vel­op­ers in crafting secure contracts.
  • Ethereum com­pat­i­bil­i­ty: Currently, Solidity is the preferred language for producing smart contracts on the Ethereum blockchain.
  • Distinct community: A large community of blockchain de­vel­op­ers works with Solidity, resulting in a plethora of resources for learning and problem-solving.

Dis­ad­van­tages of Solidity

  • Learning curve: For de­vel­op­ers who are new to blockchain and smart contract de­vel­op­ment, Solidity has a rel­a­tive­ly steep learning curve.
  • Un­change­abil­i­ty: Once a smart contract is deployed on the blockchain, it cannot be modified further. It follows that de­vel­op­ers need to be extremely careful when writing and testing.
  • Lack of formal ver­i­fi­ca­tion: Solidity lacks built-in tools for formal code review. This ne­ces­si­tates that de­vel­op­ers utilize external tools to guarantee the accuracy of their contracts.
  • Limited tooling: Solidity’s tooling ecosystem is still in its nascent stages, which could result in issues with In­te­grat­ed De­vel­op­ment En­vi­ron­ments (IDEs), testing frame­works, and other de­vel­op­ment tools.

What is the basic syntax of Solidity?

Solidity is an object-oriented pro­gram­ming language designed for smart contracts. It takes in­spi­ra­tion from JavaScript, Python, and C++. The language’s syntax is similar to JavaScript, albeit with some in­trigu­ing idio­syn­crasies.

Variables in Solidity

At first glance, Solidity’s variable handling may appear similar to other pro­gram­ming languages. However, a critical dis­tinc­tion arises from the fact that the Ethereum Virtual Machine (EVM) serves as the execution en­vi­ron­ment. All op­er­a­tions on the EVM, including data storage, incur a certain amount of “gas” cost. Con­se­quent­ly, during pro­gram­ming, one must weigh the ef­fi­cien­cy of an operation and determine how it can be im­ple­ment­ed as ef­fi­cient­ly as feasible.

In addition to regular variables, Solidity has constants, which must be defined during compiling. Constants ne­ces­si­tate less gas for storage:

// Regular variable can be declared without defining
int a;
// Constant needs to be defined at declaration
int constant b = 51;
solidity

The same applies to immutable variables in that they require less gas and cannot be changed after as­sign­ment. Unlike constant variables, the as­sign­ment of immutable variables can be done at runtime.

Control state­ments in Solidity

As an im­per­a­tive pro­gram­ming language, Solidity supports familiar control state­ments, such as branches and loops. We show the code for selecting the larger of two numbers, a and b:

int largerNumber = 0;
// If-else statement
if (a > b) {
    largerNumber = a;
} else {
        largerNumber = b;
}
solidity

The for loop in Solidity cor­re­sponds to the syntax known from JavaScript or C++:

// Loop 10 times
for (int i = 0; i < 10; i++) {
    // …
}
solidity

The while loop also works as usual. We combine a ter­mi­na­tion condition with a numeric counter variable:

bool continueLoop = true;
int counter = 0;
// Loop at most 10 times
while (continueLoop && counter < 10) {
    // …
    counter++;
}
solidity

Simple types in Solidity

Solidity is a sta­t­i­cal­ly-typed language and supports the types commonly found in pro­gram­ming languages. Simple types that represent single values include Booleans, numbers, and strings.

Booleans in Solidity map the values true and false. They can be linked using the known Boolean operators and used in if state­ments:

bool paymentReceived = true;
bool itemsStocked = true;
bool continueTransaction = paymentReceived && itemsStocked;
if (continueTransaction) {
    // ...
}
solidity

Solidity supports a wide range of numeric types. Integer numbers can be dis­tin­guished between signed (int) and unsigned (uint) numbers, where the latter may only be positive. Fur­ther­more, the range of a number can be specified in steps of 8 bits, from int8 via int16 up to int265:

uint8 smallNumber = 120;
int8 negativeNumber = -125;
int8 result = smallNumber + negativeNumber;
assert(result == -5)
solidity

Strings are used in Solidity mainly for gen­er­at­ing status messages. The language supports single and double quotes as well as Unicode char­ac­ters:

string message = 'Hello World';
string success = unicode"Transfer sent";
Solidity

Functions in Solidity

Functions are a fun­da­men­tal aspect of Solidity, as in most pro­gram­ming languages. The de­f­i­n­i­tion of a function is similar to JavaScript, where the argument types must be ex­plic­it­ly specified. Ad­di­tion­al­ly, a returns keyword is utilized to indicate the return value types.

// Define a function
function addNumbers(int a, int b) returns (int) {
    return a + b;
}
solidity

The call of a function is done as usual:

// Call the function
int result = addNumbers(2, 3);
solidity

In­ter­est­ing­ly, analogous to named arguments, return values in Solidity can also be named. In this situation, assigning the cor­re­spond­ing variables in the function body suffices, and an explicit return via return is un­nec­es­sary:

function divideNumbers(int dividend, int divisor) returns (int quotient) {
    quotient = dividend / divisor;
    // No `return` necessary
}
solidity

Similar to constant or immutable variables, in Solidity functions can be marked as not state-modifying. The keywords view and pure are used for this purpose. A view function doesn’t change the state, while a pure function ad­di­tion­al­ly guar­an­tees not to read state variables.

Smart Contracts in Solidity

In addition to standard types, Solidity knows a handful of smart contract spe­cial­ized types. The basic type is address and maps Ethereum addresses. Addresses that are payable can receive transfers in Ether. For this purpose, payable addresses provide balance() and transfer() methods.

// Get address of this contract
address mine = address(this);
// Get payable external address
address payable other = payable(0x123);
// Transfer if balances fulfill conditions
if (other.balance < 10 && mine.balance >= 100) {
    other.transfer(10);
}
solidity

Building on the address type, the contract type exists as a central language construct. Contracts cor­re­spond roughly to classes in object-oriented pro­gram­ming languages. Thus, contracts bundle state data and functions and shield them from the outside world. Contracts support multiple in­her­i­tance, as known from Python or C++.

Contracts usually begin with a pragma line spec­i­fy­ing the allowed Solidity version, followed by the actual de­f­i­n­i­tion:

// Make sure Solidity version matches
pragma Solidity >=0.7.1 <0.9.0;
// Contract definition
contract Purchase {
    // Public state variables
    address seller;
    address buyer;
    
    // View-function
    function getSeller() external view returns (address) {
        return seller;
    }
}
solidity

Smart contracts can define state data and functions. As known from C++ and Java, one of three access levels can be defined in each case:

  • public: The variable can be accessed by reading and writing from within the contract. Ad­di­tion­al­ly, a view function is au­to­mat­i­cal­ly generated as a getter for external read access.
  • internal: The variable is shielded from external access. Read and write access is possible from within the contract as well as from in­her­it­ing contracts.
  • private: like internal, but there’s no access from in­her­it­ing contracts

Functions can further be char­ac­ter­ized as external. An external function acts as part of the contract interface and is used for external access. The receive function for receiving ether is a well-known example:

// Define without `function` keyword
receive() external payable {
    // Handle Ether
}
solidity

Modifiers in Solidity

Solidity has an in­trigu­ing language construct in the form of modifiers, which bear re­sem­blance to Python’s dec­o­ra­tors. Similar to Python, modifiers in Solidity are utilized to alter the in­vo­ca­tion of a function. They are fre­quent­ly employed to ensure that a specific condition is satisfied before executing a function:

contract Sale {
    uint price;
    address payable owner;
    modifier onlyOwner {
        // Will throw error if called by anyone other than the owner
        require(
            msg.sender == owner,
            "Only owner can call this function."
        );
        // The wrapped function's body is inserted here
        _;
    }
    
    // `onlyOwner` wraps `changePrice`
    function changePrice(uint newPrice) public onlyOwner {
        // We'll only get here if the owner called this function
        price = newPrice;
    }
}
solidity

Trans­ac­tion man­age­ment with Solidity

Solidity has a built-in trans­ac­tion man­age­ment. This can be used to ensure that an ether transfer is either com­plete­ly settled or not settled at all. The language un­der­stands the revert keyword, which triggers a “roll-back” of a trans­ac­tion. With the error keyword you can define your own error codes:

// Custom error definition
error InsufficientPayment(uint256 paid, uint256 required);
// Contract representing a sale
contract Sale {
    uint price;
    // Purchase if enough ether transferred
    function purchase() public payable {
        if (msg.value < price) {
            revert InsufficientPayment(msg.value, price);
        }
        // Complete purchase
    }
}
solidity

Another fre­quent­ly en­coun­tered pattern is the use of the require() function. This can be used anal­o­gous­ly to revert:

// Using `require()` function
if (!condition) revert("Error message");
// Equivalent to
require(condition, "Error message");
solidity
Go to Main Menu