![]() |
VOOZH | about |
The Replay is a weekly newsletter for dev and engineering leaders.
Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.
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.β
π Solidity Logo Over a Tiled BackgroundThis blueprint governs the relationship between parties when an event occurs using code, making it vastly secure and as predictable as the code itself.
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.
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.
// 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 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.
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;
}
}
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 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 functionexternal: 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 gasprivate: only the contract holding the function can call itinternal the contract and its derivatives can call the functionThese types govern access to the state:
view: the function only reads the statepure: the function neither reads nor writes to the stateNote 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;
}
}
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.
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:
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.
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:
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.
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.
Client-side issues that impact usersβ ability to activate and transact in your apps can drastically affect your bottom line. If youβre interested in monitoring UX issues, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.
π LogRocket Dashboard Free Trial BannerLogRocket lets you replay user sessions, eliminating guesswork around why bugs happen by showing exactly what users experienced. It captures console logs, errors, network requests, and pixel-perfect DOM recordings β compatible with all frameworks.
LogRocket's Galileo AI watches sessions for you, instantly identifying and explaining user struggles with automated monitoring of your entire product experience.
Modernize how you debug web and mobile apps β start monitoring for free.
Learn how to use Gemini CLI subagents to delegate frontend, backend, testing, and docs tasks to specialized agents with guardrails and clear ownership.
Learn how next-browser gives AI agents runtime context for debugging Next.js apps, including React props, hydration, PPR, forms, and performance.
Build dynamic LLM routing in Next.js with OpenRouter, TanStack AI, task classification, model fallbacks, and cost-aware routing.
TSRX adds first-class control flow, conditional hooks, and scoped styles to React via a TypeScript compiler extension β no new framework required.
Hey there, want to help make our blog better?
Join LogRocketβs Content Advisory Board. Youβll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up now