Write Your First User Profile Smart Contract


Introduction
I have found learning smart contract development very intimidating. That’s exactly why I decided to take things a step further by documenting my assignment for the Lisk Bootcamp. If you’ve ever felt overwhelmed or stuck, starting just like I was, I’m here to simplify the process and make it much easier for you.
This guide shows you how to write a simple smart contract to manage user profiles on the blockchain. With this contract, users can register their name, age, and email, update their information, and view their profile. The contract ensures one registration per user and records the registration time.
Prerequisites
Before starting, ensure you have the following tools and knowledge:
Tools You Need
- Use Remix online IDE for writing, compiling, and deploying Solidity smart contracts. No installation needed.
What You Should Already Know
What a blockchain is and the role of smart contracts.
Understanding Ethereum networks and accounts/addresses.
Familiarity with Solidity basics like functions, variables, and data types.
Step-by-Step Guide
Step 1: Set Up Your Contract and Define the User Structure
Start by declaring the Solidity version and the contract name.
Inside the contract, create a struct named User to hold profile data like name, age, email, and registration timestamp.
pragma solidity ^0.8.30;
contract UserProfile {
struct User {
string name;
uint256 age;
string email;
uint256 registeredAt;
}
}
What this does:
The struct User organizes your user data in one container. Each user will have their own User struct stored.
Step 2: Create Storage for User Data
Add two mappings to store user profiles and check if an address has been registered.
mapping(address => User) public users;
mapping(address => bool) public registered;
Explanation:
users
is a mapping that links each Ethereum address to its corresponding User profile. So, every user’s data is stored by their wallet address.registered
is a mapping to track whether a particular address has already been registered, preventing users from registering multiple times.
Step 3: Write the Register Function
This function lets users create their profile by entering their name, age, and email. It checks if the user is already registered and saves their data with the current timestamp.
// Register a new user
function register(string memory _name, uint256 _age, string memory _email) public {
require(!registered[msg.sender], "Already registered.");
users[msg.sender] = User({
name: _name,
age: _age,
email: _email,
registeredAt: block.timestamp
});
registered[msg.sender] = true;
}
Explanation:
require(!registered[msg.sender], "Already registered.");
checks if the caller’s address has already been registered; if yes, it stops execution with an error message.If not previously registered, the user data is saved in the users mapping with the current timestamp (
block.timestamp
) recorded as their registration time.Finally, the registered mapping marks the address as registered (true) to block future duplicate registrations.
Step 4: Write the Update Profile Function
This function allows users to update their profile data only if they have already registered.
// Update existing user profile
function updateProfile(string memory _name, uint256 _age, string memory _email) public {
require(registered[msg.sender], "Not registered.");
users[msg.sender].name = _name;
users[msg.sender].age = _age;
users[msg.sender].email = _email;
}
Explanation:
The require statement ensures that only registered addresses can update their profiles.
The user’s stored name, age, and email fields get overwritten with the new values provided.
Step 5: Write the Get Profile Function
This function allows users to fetch their profile information.
// Get your own profile details
function getProfile() public view returns (string memory name, uint256 age, string memory email, uint256 registeredAt) {
require(registered[msg.sender], "Not registered.");
User storage user = users[msg.sender];
return (user.name, user.age, user.email, user.registeredAt);
}
Explanation:
require(registered[msg.sender], "Not registered.");
first checks that the caller is registered.Then it retrieves the
User
struct corresponding to the caller’s address and returns their name, age, email, and registration timestamp.
Wrap Up
The contract now lets users register once, update their details, and view their profile securely on the blockchain, with registration time tracked.
Next, you will learn how to deploy and verify your smart contract on the Lisk Sepolia test network.
Stay tuned for the deployment guide, and don't hesitate to reach out anytime for assistance with deployment or expanding the contract’s features.
Further Resources
Subscribe to my newsletter
Read articles from Etugbo Judith directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Etugbo Judith
Etugbo Judith
I'm a Technical writer passionate about breaking down complex concepts into clear, concise and engaging content.