DEV Community

Maarek
Maarek

Posted on • Edited on

Write your first smart contract in Solidity

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
Enter fullscreen mode Exit fullscreen mode

Directory and files will be created :

├── contracts
│   └── Migrations.sol
├── migrations
│   └── 1_initial_migration.js
├── test
└── truffle-config.js
Enter fullscreen mode Exit fullscreen mode

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 {

}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

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);
};
Enter fullscreen mode Exit fullscreen mode

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!

Top comments (0)