How to Write an Ethereum Smart Contract with Solidity

In this video, we'll write our first Solidity smart contract

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

Let's write and deploy our first Ethereum smart contract in Solidity.

The process looks like this:

  • we write our contract (in a high level language)
  • compile it
  • and deploy it to the network
  • and after it's been deployed we can interact with it

This lesson preview is part of the Intro to Programming Ethereum ĐApps course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to Intro to Programming Ethereum ĐApps, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course Intro to Programming Ethereum ĐApps
  • [00:00 - 00:04] Let's write and deploy our first Ethereum smart contract. The process looks like this.

    [00:05 - 00:09] We'll write our contract in a high-level language. Next we'll compile it.

    [00:10 - 00:14] Then we'll deploy it to the network. And after it's been deployed, we can interact with it.

    [00:15 - 00:24] In order to write contracts on Ethereum, it's really important to understand the context in which they are run. The first thing that we'll start with is the Ethereum Virtual Machine, or the EVM for short.

    [00:25 - 00:33] The EVM is a low-level assembly-like programming environment. It can perform arbitrary computations, put data in storage, read that data out, etc.

    [00:34 - 00:43] When we write code for Ethereum, we generally don't write the bytecode directly . Instead, we use a higher-level language that compiles down to these basic operations.

    [00:44 - 00:54] The second thing to know is that this code is run by every node on the network. That is, every minor node on the Ethereum network will run our smart contracts code.

    [00:55 - 01:04] But keep in mind, they're going to run the EVM bytecode and not our Solidity code directly. Because our code is run by every node on the network, this has a lot of implications around data privacy and cost.

    [01:05 - 01:11] We'll talk about those later. The third thing to keep in mind is that our contracts will only run in response to a transaction.

    [01:12 - 01:21] That is, they're not running constantly in the background. Instead, our contracts will only run and make changes if a transaction is sent to the network that wakes them up.

    [01:22 - 01:27] There's a lot to unpack here, so let's just start by looking at some code. I'm going to be working out of our new line Web3 directory.

    [01:28 - 01:35] I'm going to make a contracts directory, and I'm going to create the file contracts counter.soul. You can find this in the lesson notes.

    [01:36 - 01:41] This is a Solidity contract. It keeps track of account variable which we can increment.

    [01:42 - 01:50] Now, it's not the most exciting code, but we have a lot of new ideas to cover around Ethereum itself. We'll expand into more interesting contracts once we grasp how everything fits together.

    [01:51 - 01:59] We open by stating pragma solidity and then a version number. This pragma is an instruction to the compiler as to what version of Solidity we 're using.

    [02:00 - 02:09] The version number is semantic versioning, much like JavaScript's NPM modules. The version number is important because remember, we're not running Solidity code on the EVM.

    [02:10 - 02:16] We're running bytecode. The Solidity compiler compiles this contract down to EVM bytecode.

    [02:17 - 02:36] The Solidity compiler, like the rest of the system, is under development, and so two different versions of the compiler could reasonably emit two different versions of the bytecode. This might not be that important when we're compiling code for a regular computer, but when our code is controlling thousands or sometimes millions of dollars, little changes in the compiler can make a big difference.

    [02:37 - 02:50] So we fix our Solidity version in our smart contract so that way we know we can get a consistent output from our code down the line. Next we define our contract with the keyword "contract" as well as the name of the contract, which in this case is "counter".

    [02:51 - 02:58] A quick scan of this code might remind you of JavaScript. And that's deliberate in that Solidity was designed to be approachable for web developers.

    [02:59 - 03:05] That said, don't let the superficial similarities fool you. Solidity is just similar enough to JavaScript to be dangerous.

    [03:06 - 03:14] There are some unintuitive aspects of Solidity that you really have to be careful of. We'll cover them as we go along, but one similarity is that you can think of this contract as a class.

    [03:15 - 03:20] The counter contract is like an object class. On the next line we have "uint count".

    [03:21 - 03:35] Solidity is a statically typed language and this count variable is an unsigned integer. "uint" is an alias for "uint 256", which means it can hold a positive integer up to 2 to the 256th minus 1.

    [03:36 - 03:40] It's a very large number. The value of this counter will be stored on the Ethereum blockchain.

    [03:41 - 03:48] This means that the value of count will be stored on every full node on the Ethereum network. This service is not provided for free.

    [03:49 - 03:58] If you want a value to be stored permanently by thousands of nodes, you're going to have to pay for this. Understanding and calculating these costs is also something we'll talk about later.

    [03:59 - 04:06] For now, know that this "count" variable is like an instance variable. We can read from it and write to it as you see in the functions below.

    [04:07 - 04:13] The first function that we have is the constructor. The constructor is a function with the same name as the class.

    [04:14 - 04:24] As happens in other languages, the constructor function is called when we create an instance of the class. One question you might be asking is, how do we create an instance of this class anyway?

    [04:25 - 04:39] The answer is, after we compile the code, we'll submit a transaction to the network that creates an instance of this class. This instance will be given its own address and it can control both data and funds on the Ethereum network.

    [04:40 - 04:46] That is, this contract can receive payments of its own. It can verify conditions and it can send funds out.

    [04:47 - 04:53] Well, this counter contract can't do any of that because we haven't implemented any of that functionality. But in other contracts, we will.

    [04:54 - 05:10] Just know that when we upload this code to the network, an instance will be created and given its own permanent immutable address. Speaking of immutability, another thing that you should know is that once we've created an instance of a contract, its code is immutable and cannot be changed.

    [05:11 - 05:17] You can't upload a bug fix and you can't make any tweaks. Once it's been created, it's written in stone.

    [05:18 - 05:28] There are strategies for mitigating this limitation, but really, immutability is a feature, not a bug. But you'd better make sure that you do extensive testing before you start handling real funds.

    [05:29 - 05:36] Back to our code, in this constructor, we're going to set count equal to one when the contract is created. The next function is increment.

    [05:37 - 05:46] The increment function will read the existing count from storage, add one, and then store the new value in the count instance variable. The get function returns the value of count.

    [05:47 - 06:03] In the get function declaration, we're stating that it is a constant function, which means it doesn't modify any of the state, and it returns a Uint, an unsigned integer. Remember, every node on the network stores a copy of the storage for every contract.

    [06:04 - 06:17] And given that we have our own node, this means that we can read any of the data for free instantly. That is, the get function can be executed completely on our local machine without going to the network.

    [06:18 - 06:23] We already have the value of count on our disk. The increment function, however, is different.

    [06:24 - 06:36] Because it changes state, the validity of that change must be confirmed by the whole network. So to make a call to increment, we must submit a transaction that calls increment.

    [06:37 - 06:47] That transaction will hopefully be picked up by a miner to be included in a block. When that happens, the transaction will be run, which will increment the count value.

    [06:48 - 06:53] We've looked close enough of this code, let's compile it, deploy it, and then interact with it on the blockchain.