Simohamed Marhraoui Vue and React developer | Linux enthusiast | Interested in FOSS

Writing smart contracts with Solidity

4 min read 1173

Solidity Logo Over a Tiled Background

What is a smart contract?

Popularized by Ethereum, smart contracts are programs that are stored and executed on a blockchain. The term was coined in the late ’90s in an attempt to “provide the blueprint for ideal security.”

This blueprint governs the relationship between parties when an event occurs using code, making it vastly secure and as predictable as the code itself.

Smart contracts vs. external accounts

Much like an external (Ethereum) account, smart contracts have addresses and can hold and transfer funds. External accounts, however, are not bound to a single network. You can use the same account to connect to any number of blockchain networks.

Smart contracts, on the other hand, can only be connected to one specific network. They can augment or replace real-life contracts because of their transparent nature and the immutability of the system (blockchain) they run on. The most popular way to write such a contract is through the Solidity programming language.

Introducing Solidity

Solidity is a compiled object-oriented programming language created by the Ethereum team that has JavaScript-like syntax. Unlike JavaScript, Solidity is strongly-typed and makes great use of inheritance.

Solidity compiles our source code into deployable byte code and an Application Binary Interface (ABI) to interact with the byte code using other smart contracts or programming languages.

Writing a smart contract with Solidity

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.4.17 <0.9.0;

contract Storage {
  uint data;

  function set(uint newData) public {
    data = newData;
  }

  function get() public view returns (uint) {
    return data;
  }
}

Because smart contracts’ source code is often readily available to read, it’s a good idea to specify the license of your code in the first line after SPDX-License-Identifier:.

Following that, the pragma directive tells the compiler which version of Solidity to use. The versions start with 0. to indicate that breaking changes are to be expected in minor, regular updates. Our smart contract can be compiled against version 0.4 or higher, but not version 0.9.

Contracts

Contracts in Solidity are pretty similar to JavaScript classes in that they hold variables and methods that interact with one another. But unlike classes, you do not need a this keyword to access a variable in Solidity. It’s also mandatory to have semicolons after declarations (function definitions do not count.)

Our Storage contract holds integer data (annotated by the uint type keyword) and exposes two functions that can change and display it. The data variable is a storage variable that will exist for the lifetime of our contract. If we deploy this contract, anyone can call set and get to modify and retrieve the value of data.

We made a custom demo for .
No really. Click here to check it out.

Initializing our variables in Solidity contracts

To initialize our data variable with a value, contracts can provide a constructor function that takes zero or more arguments:

contract Storage {
  uint data;

  constructor (uint defaultData) {
    data = defaultData;
  }

  function set(uint newData) public {
    data = newData;
  }

  function get() public view returns (uint) {
    return data;
  }
}

Inheritance

A contract can inherit from another contract through the is keyword:

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.4.17 <0.9.0;

contract C {
    string public greeting = 'hello';
}

contract D {
    string public farewell = 'goodbye';
}

contract E is C, D {}

Contract D will have access to both greeting and farewell variables.

Solidity functions

Solidity functions have the following pattern:

function <function name>(<parameters type>) \[function type\] [returns (<return type>)] {}

The commonly used function types are public, external, private, internal, view, pure, and payable.

Here’s how the types that govern the visibility of the function work:

  • public: anyone can call the function
  • external: anyone but the contract can call the function. Using the external type instead of public can have a performance boost and potentially save a lot of gas
  • private: only the contract holding the function can call it
  • internal the contract and its derivatives can call the function

These types govern access to the state:

  • view: the function only reads the state
  • pure: the function neither reads nor writes to the state

Note that payable is used when the function can accept payment when it’s called.

A more detailed pattern for the function type would look like this:

{public|external|private|internal} [pure|view|payable]

Thus, in our contract, the get function that has the types public view returns (uint) is universally accessible, reads data, and returns an integer.

Solidity, however, provides us with a shortcut to automatically create get functions that display our state. By simply adding the keyword public before our variable data, a data function will be created to replace our get function:

contract Storage {
  uint public data; // a data function will be created to access the `data` variable

  constructor (uint defaultData) {
    data = defaultData;
  }

  function set(uint newData) public {
    data = newData;
  }
}

Deploying using Remix

To test and deploy our contract to a blockchain network, we can either rely on an IDE like Remix to simplify our job or use a real coding environment. For this article, we’ll use Remix.

Remix is a Solidity IDE used to compile, deploy, and manually test Solidity code. It can interface with an array of Ethereum test networks, as well as the main network.

First, create a new contract under the contracts directory and copy over our contract code.

Contracts Directory

Contract Code

When our Solidity code is saved, Remix will automatically compile our code, creating a bytecode that gets sent to the network, as well as an ABI to interact with the deployed contract.

We can inspect both the bytecode and the ABI in the Solidity compiler tab:

ABI

If our code compiles successfully, we can start deploying and interfacing with it under the deploy and run transactions tab.

In this tab, we can pick our environment, the contract to deploy, and which account to deploy it with. JavaScript VM means that Remix will maintain a blockchain network inside our browser to make testing run as fast as possible.

The value input is associated with payable function calls and is unnecessary for our contract.

Deployed Contracts

At the bottom of the tab, we see Deployed Contracts, which indicates that we can deploy multiple instances of one or many contracts.

Under Contracts, Remix picks up on our defaultData inside the constructor function. Enter an integer and hit Deploy to deploy a new contract:

Deploy Dropdown

Storage Dropdown

The data button represents the automatically generated getter for our public data variable, while the set button represents our set method.

The color difference can be attributed to the fact that our getter data function does not modify the state in our app, and therefore, does not cost anything to run on the blockchain. However, our set function is a transaction type of function that consumes gas and resources to run, much like the initial Deploy button.

Running the data function would return our initial input 2021 and set modifies it accordingly.

Data 2021

Set 2022

Data 2022

Conclusion

In this article, we looked at the basic building blocks of a Solidity contract, as well as how to write, compile, deploy, and test our Solidity code using the Remix IDE. From this point on, we should take it a step further and use a real environment using Ganache and Truffle. Happy hacking.

: Full visibility into your web apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.
Simohamed Marhraoui Vue and React developer | Linux enthusiast | Interested in FOSS

Leave a Reply