Write your first smart contract in Solidity
Maarek
Posted on December 30, 2021
Few month ago, I started my journey on Ethereum development. I discovered an amazing and very promising ecosystem that is placing the foundation stones of the futur of the internet as we know it.
So today, I decided to write a series of article to get started in this environment that may sound very obscure to a lot of people right now.
Before we start...
In this article I will cover how to setup a development environment to start working with the Solidity programming language and write a smart contract, then deploy it on a local network. I will assume you know the basics of programming (eg: variables, functions, control flows and loops, class...).
Installing everything you need:
Firstly, you need to get a NodeJS environment set up. If you don’t already have that, you can download NodeJS from the official website or use your favorite package manager.
Now we can install Truffle, an open source tool suite that will allow you to develop, test and deploy your contract.
Use npm install -g truffle
and you’re all set.
Then, download Ganache from the Truffle website. This tool will allow you to setup a personal Ethereum blockchain that you can use to run and test your contract.
Finally, you can fire up any IDE, time to code. I would recommend VSCode with the Solidity plugin.
Time to code!
Alright, the first thing to do once you’ve downloaded everything is to init a project. To do so, create a new directory and let truffle do his thing:
mkdir fundraiser-contract
cd fundraiser-contract
truffle init
Directory and files will be created :
├── contracts
│ └── Migrations.sol
├── migrations
│ └── 1_initial_migration.js
├── test
└── truffle-config.js
We’ll quickly go over these files :
-
contracts/
will contains your solidity sources. It already have a contract in it, called Migration (.sol is the solidity extension). This contract keeps track of migrations and deployment in the network you’re working on. -
migrations/
contains your smart contracts deployments logic. -
test/
as you can guess is here for your testing environment.
Good, we’re all set. Now we’re going to create a new contract. Let’s work on a simple fundraiser contract.
So let’s start by creating a new solidity file, say Fundraiser.sol
in the contract
directory. Then we’ll add a license, a version directive and create a contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Fundraiser {
}
Specifying a license is mandatory in solidity. The pragma statement is used to tell the compiler which Solidity version it should use.
This contract will have few things :
- The owner’s address, which deployed the contract & the one who will get the money collected by the contract.
- An array of the backers, so the owner can personally thank them.
So we will add these as attributes like you would on a regular class:
contract Fundraiser {
address public owner;
address[] public backers;
}
In this example, I’ll set all the variables’ access to public.
To get the owner’s address we will just implement the contract’s constructor and get his address from here. In solidity there is a few global variable that you can access. Here we will use msg
, which contains the address of the one who calls the functions: msg.sender
.
Our constructor would look like :
constructor() {
owner = msg.sender;
}
Now we need a function accessible to anyone to send some Ether to this contract. We’ll call it sendMoney
cause that’s what it actually does.
function sendMoney() public payable {
require(msg.value > 0, "No Ether were sent.");
backers.push(msg.sender);
}
The first statement is a require
call. He's here to check if the condition given as its first argument is true, otherwise, the function will stop its execution and the transaction will be reverted with the error message passed as second argument. Here we want to make sure the caller actually sent some Ether: we check if the function caller attached a value: msg.value
.
Note that the function is marked public
and payable
so anyone can call it, and send Ether.
Then, we just add the sender’s address to the backers list.
Next we want to let the owner get it’s freshly raised money. So let’s make a function called endFundraising
that will collect the money.
function endFundraising() public {
require(msg.sender == owner, "Only the owner is allowed to end the fundraising.");
payable(owner).transfer(address(this).balance);
}
That function will be public but we are going to make sure that the caller (msg.sender
) is the owner with a require
statement.
Then, we can just transfer its funds to the owner with the Solidity transfer
method.
Just for fun, I’ll also add a get balance function:
function getBalance() public view returns (uint256) {
return address(this).balance;
}
Every contract has a balance and can hold funds.
And we’re done! You just wrote your first contract 😎.
Here is the full code :
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Fundraiser {
address public owner;
address[] public backers;
constructor() {
owner = msg.sender;
}
function sendMoney() public payable {
require(msg.value > 0, "No Ether were sent.");
backers.push(msg.sender);
}
function getBalance() public view returns (uint256) {
return address(this).balance;
}
function endFundraising() public {
require(msg.sender == owner, "Only the owner is allowed to end the fundraising.");
payable(owner).transfer(address(this).balance);
}
}
As you can see, this contract is quite simple, and I bet you can see a lot of evolutions, such as locking the fundraising once the funds has been transferred, also, wouldn’t it be nice to have a cool web app that would allow any user to send the funds?
Let’s deploy!
Ok, so the contract should work right? The next step would be to deploy it on your personal network.
And, hey, I can ear you: “Woow!! Are we about to deploy this? Shouldn’t we write tests before and make sure it passes all? What kind of developer is this guy!”...
And you are right. But I keep the testing part for another post. This one is getting quite long already - don’t be mad.
Earlier, you installed Ganache. Launch it, click on Quickstart, it will automatically start and setup an Ethereum blockchain on your local network and give you 10 accounts loaded with 100 fake Ether to play with it. Once started, we can prepare our deployment.
Remember that migration
directory? Create a new JavaScript file called 2_deploy_contracts.js
.
In this file we will write the deployment/migration code for our contract. It’s pretty standard, you can just copy past it:
var Fundraiser = artifacts.require("./Fundraiser.sol");
module.exports = function(deployer) {
deployer.deploy(Fundraiser);
};
Now you’re really done. You would just need to type the command truffle migrate
, in you terminal (make sure you’re in your project’s root).
Now what? Testing time! Deployment? And, wouldn’t it be nice to test it with a small web app? Yup, that’s what’s next!
Don’t hesitate to comment or contact me via Twitter if you have any question.
Happy coding!
Posted on December 30, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.