This content originally appeared on Level Up Coding - Medium and was authored by Dmitry Glazunov
I occasionally like to explore areas outside of mobile development when something sparks my interest.
This time, it’s about writing my first smart contract using Solidity. In this article, I’ll walk through the basics: what a smart contract is, how it lives on the blockchain, and how to write and deploy a simple contract step by step. It’s not a deep dive into advanced Solidity but rather a practical first step into the world of smart contract development.
What is a smart contract?
A smart contract is a program deployed on the blockchain that automatically executes logic when triggered by transactions. Think of it as a public backend function that nobody can change once deployed, ensuring transparent, trustless execution without intermediaries.
Here’s what makes smart contracts different from typical APIs:
- Immutable сode (mostly)
Once deployed, the code can’t be changed, ensuring that all users interact with the same logic. (There are upgradeable patterns, but they add complexity and trust assumptions.) - On-chain state
The contract can store variables (balances, mappings, configuration) directly on the blockchain, making them globally accessible and verifiable by anyone. - Users pay to execute
Every interaction requires users to pay a gas fee, which covers the cost of computation and storage on the network. - Deterministic execution
Given the same inputs and state, the contract will always produce the same result, ensuring consistency across all nodes. - No traditional authentication
Instead of API keys or OAuth, contracts rely on wallet signatures and the Ethereum address of the sender, shifting trust from centralized auth systems to cryptographic proof of ownership. - Public by default
Anyone can call your contract’s functions, and all transactions and state changes are visible on the blockchain explorer. Privacy requires specialized patterns like zero-knowledge proofs or off-chain computation.
In simpler terms, smart contracts let you write rules that execute automatically in a decentralized system, but with trade-offs in cost, complexity, and immutability compared to traditional backend systems.
How does it live on the blockchain?
Once deployed, a smart contract becomes part of the blockchain itself. It’s not just a file on a server — it’s stored across thousands of nodes, ensuring its code and state are replicated, verifiable, and tamper-proof.
Here’s what that means in practice:
- Deployment = Transaction
When you deploy a contract, you send a transaction containing the compiled bytecode to the blockchain. This transaction requires gas, which can be expensive if your contract is large. - Stored at an address
Once mined, the contract is assigned a unique Ethereum address, just like a wallet. Users and other contracts can call it by sending transactions to this address. - Code and state separation
The code of the contract is immutable and stored permanently.
The state (variables, balances, mappings) is stored in the Ethereum state trie, which can change with each transaction interacting with the contract.
- Execution on every node
Whenever someone calls a function on the contract, every node in the network executes the function to reach consensus on the new state. This is what makes the blockchain trustless: no single server decides the result. - Gas and costs
Each operation (storage, computation, logging events) costs gas. Writing to storage (e.g., updating a variable) is much more expensive than reading, which shapes how you design your contract logic. - Interacting with other contracts
Smart contracts can call other contracts, creating complex interactions on-chain. However, all of these calls happen synchronously within a single transaction context.
In essence, once your contract is on-chain, it becomes a public, decentralized backend microservice that anyone can call, and whose state is updated transparently across the network with every transaction.
This permanence is a superpower, but also a source of risk. Mistakes in your contract can’t be patched with a simple redeploy. You’ll need to plan carefully, test thoroughly, and often adopt patterns (like upgradeable proxies) if you expect your contract logic to evolve.
Setting up your environment
Before writing your first Solidity smart contract, you need a development environment that allows you to write, compile, deploy, and test your Solidity code safely and efficiently.
What is Solidity?
Solidity is a contract-oriented, statically typed programming language designed for writing smart contracts on Ethereum and compatible blockchains (EVM chains). It looks similar to JavaScript or TypeScript but compiles down to EVM bytecode.
Key characteristics:
- Strongly typed: You must define variable types (uint256, address, etc.).
- Supports inheritance, modifiers, and interfaces.
- Compiled with solc (Solidity compiler) to bytecode for deployment.
Current stable versions: 0.8.x and 0.8.24+ are commonly used, adding overflow checks and improved error handling compared to older versions.
Install Node.js and npm
Ethereum tooling for Solidity projects uses Node.js for dependency management:
- Download Node.js (LTS recommended) from nodejs.org.
- Verify:
node -v
npm -v
Install Hardhat for Solidity development
Before we jump into installing Hardhat, it’s worth mentioning that there are different ways to start experimenting with Solidity.
You can use Remix (a browser-based Solidity IDE) for quick experiments and to get instant feedback without installing anything. It’s a great way to write your very first “Hello World” contract.
However, for this article, I chose to use Hardhat because it reflects how Solidity development is done in real projects:
- It lets you compile and test contracts locally, with full control over compiler versions
- It provides a local blockchain for testing deployments without spending real ETH.
- It enables automated, test-driven development, preparing you for production workflows.
- It allows you to write deployment scripts and simulate complex contract interactions.
Install Hardhat:
npm install --save-dev hardhat
Then, initialize your project:
npx hardhat
Choose:
- “Create a JavaScript project”
- Or “Create a TypeScript project” if you prefer type safety.
Install Solidity сompiler and VS сode plugins
Hardhat comes with built-in Solidity compiler support, but it is helpful to:
- Install the Solidity VS Code extension for syntax highlighting and error checks.
- Configure your hardhat.config.js to specify the Solidity version:
module.exports = {
solidity: "0.8.24",
};
You can also specify multiple compiler versions if interacting with older contracts:
module.exports = {
solidity: {
compilers: [
{ version: "0.8.24" },
{ version: "0.7.6" }
]
}
};
Install MetaMask and get test ETH
To deploy your Solidity contracts to testnets:
- Install MetaMask in your browser.
- Create a wallet and securely save your seed phrase.
- Switch to a testnet like Sepolia or Goerli.
- Request test ETH from a faucet, e.g., Sepolia Faucet.
Writing your first smart contract
Now that your environment is ready, let’s write a practical Solidity contract that:
- Receives ETH deposits.
- Allows the owner to send ETH to other addresses.
- Logs transactions for transparency.
- Demonstrates modifiers, events, and payable functions.
- Write MyFirstSimpleWallet.sol
Create contracts/MyFirstSimpleWallet.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract MyFirstSimpleWallet {
address public owner;
event Deposit(address indexed sender, uint256 amount);
event Withdrawal(address indexed to, uint256 amount);
modifier onlyOwner() {
require(msg.sender == owner, "Not the owner");
_;
}
constructor() {
owner = msg.sender;
}
// Receive ETH
receive() external payable {
emit Deposit(msg.sender, msg.value);
}
// Fallback to receive data with ETH
fallback() external payable {
emit Deposit(msg.sender, msg.value);
}
// Send ETH to another address
function withdraw(address payable _to, uint256 _amount) external onlyOwner {
require(address(this).balance >= _amount, "Insufficient balance");
(bool sent, ) = _to.call{value: _amount}("");
require(sent, "Failed to send Ether");
emit Withdrawal(_to, _amount);
}
// Get contract balance
function getBalance() external view returns (uint256) {
return address(this).balance;
}
}
- Owner pattern: owner is set to the deployer’s address and restricts who can withdraw funds.
- Modifiers: onlyOwner restricts withdrawal functions to the owner.
- Events: Deposit and Withdrawal help track transactions on-chain.
- receive() and fallback(): enable the contract to receive ETH directly.
- withdraw(): allows the owner to send ETH from the contract to another address.
- getBalance(): view the ETH balance of the contract at any time.
2. Compile with Hardhat
Run:
npx hardhat compile
Verify that compilation completes without errors.
3. Write Tests
Create test/myFirstSimpleWallet.js:
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("MyFirstSimpleWallet", function () {
let wallet, owner, addr1;
beforeEach(async function () {
[owner, addr1] = await ethers.getSigners();
const Wallet = await ethers.getContractFactory("MyFirstSimpleWallet");
wallet = await Wallet.deploy();
await wallet.deployed();
});
it("should accept deposits", async function () {
const depositAmount = ethers.utils.parseEther("1");
await addr1.sendTransaction({ to: wallet.address, value: depositAmount });
expect(await wallet.getBalance()).to.equal(depositAmount);
});
it("should allow owner to withdraw", async function () {
const depositAmount = ethers.utils.parseEther("1");
await addr1.sendTransaction({ to: wallet.address, value: depositAmount });
const initialBalance = await ethers.provider.getBalance(addr1.address);
await expect(() =>
wallet.withdraw(addr1.address, depositAmount)
).to.changeEtherBalances(
[wallet, addr1],
[depositAmount.mul(-1), depositAmount]
);
});
it("should prevent non-owner from withdrawing", async function () {
await expect(
wallet.connect(addr1).withdraw(addr1.address, 1)
).to.be.revertedWith("Not the owner");
});
});
Run:
npx hardhat test
You will see:
- Deposits work.
- The owner can withdraw funds.
- Non-owners cannot withdraw.
4. Deploy locally or on a Testnet
Create scripts/deploy.js:
async function main() {
const Wallet = await ethers.getContractFactory("MyFirstSimpleWallet");
const wallet = await Wallet.deploy();
await wallet.deployed();
console.log(`MyFirstSimpleWallet deployed to: ${wallet.address}`);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Run locally:
npx hardhat node
In a new terminal:
npx hardhat run scripts/deploy.js --network localhost
Or to a testnet:
npx hardhat run scripts/deploy.js --network sepolia
While exploring Solidity syntax, I tried building various test contracts to get a feel for how smart contracts actually work on Ethereum. I decided to focus on the MyFirstSimpleWallet example above, and here’s why:
- It shows real patterns in Solidity like modifiers, events, and access control — all essential for writing secure and maintainable contracts.
- It teaches ETH handling and safety checks, which are critical when your contract deals with real assets on-chain.
- It provides hands-on, test-driven Solidity development experience, allowing you to validate your contracts before deploying to a live network.
- It prepares you for building dApps on Ethereum, giving you a solid foundation before moving on to advanced topics like upgradeable proxies, gas optimization, and DeFi protocols.
Conclusion
Learning Solidity is best done through practice. I’ve shared the exact steps I took to set up a real development environment, write, test, and deploy a smart contract, and understand how it lives on the blockchain.
Smart contract development is a skill you sharpen by building and experimenting. Add new features, test out different patterns, and explore how contracts can interact with each other. Each project you try will deepen your understanding of the unique mindset Solidity development requires.
If you found this guide helpful, let me know in the comments or share what you’ve built — I’d love to see your first steps in Solidity.

Hands-on insights into mobile development, engineering, and team leadership.
📬 Follow me on Medium
Writing your first smart contract in Solidity was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Level Up Coding - Medium and was authored by Dmitry Glazunov

Dmitry Glazunov | Sciencx (2025-07-09T16:18:36+00:00) Writing your first smart contract in Solidity. Retrieved from https://www.scien.cx/2025/07/09/writing-your-first-smart-contract-in-solidity/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.