0% found this document useful (0 votes)
26 views99 pages

Developing Applications On Ethereum Blockchain - Pluralsight (9409)

Uploaded by

ALWAYS MIND IT
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
26 views99 pages

Developing Applications On Ethereum Blockchain - Pluralsight (9409)

Uploaded by

ALWAYS MIND IT
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 99

Developing

by Ivan Mushketyk
Applications on Ethereum Blockchain
Start Course
Bookmark Add to Channel Download Course Schedule Reminder

Table of contents Description Transcript Exercise files Discussion Related Courses 

Course Overview

 

Transcript links

Course Overview
Hi everyone. My name is Ivan Mushketyk, and welcome to my course, Developing Applications on Ethereum
Blockchain. I am a senior software engineer with years of experience developing traditional and
Blockchain‑based applications. In the last several years, we've witnessed a rapid development of the new
ecosystem of decentralized applications. Ethereum is at the very center of this revolution and is the most
popular platform to develop decentralized applications. In this course, we're going to learn how to develop
applications for Ethereum blockchain. Ethereum, as other Blockchain projects, has a steep learning curve, but
this course starts from the very foundations of this technology and progresses to more and more complex
features and covers other related topics as well. Some of the major topics that we will cover include foundations
of the Blockchain and the Ethereum technologies, Solidity programming language, developing smart contracts
with Solidity, Truffle framework, and how to build web applications with Ethereum. By the end of this course, you
will know how to develop nontrivial applications for Ethereum and will be able to implement full stack
applications for this platform. Before beginning this course, you should be familiar with at least one
object‑oriented programming language and have at least basic knowledge of web development. I hope you'll
join me on this journey to learn how to write decentralized applications for Ethereum with the Developing
Applications on the Ethereum Blockchain course at Pluralsight.
Ethereum Protocol
Introduction
Hi. My name is Ivan Mushketyk, and I'm excited to welcome you in my course, Developing Applications on
Ethereum Blockchain. And let's start right off the bat, why learn Ethereum? Ethereum allows us to build a new
breed of applications called decentralized applications. Just as regular applications, they run on multiple
machines. But what differs them is that these machines are not owned by a single group or organization. They
are owned by different people in different organizations, and anybody across the world can provide
computational resources for the network. No single actor controls the whole application or the whole network.
And having this network allows us to build applications on top of it. But why would we be interested in building
decentralized applications? Well, there are multiple reasons, but here are the most important. First of all,
decentralized applications are more reliable. There is no single point of failure, and they will continue to run even
if some machines will go down. They are more secure. Code and data are cryptographically secured, and
nobody can amend them. And the last, they are transparent. Any participant can verify that everyone is playing
by the rules and not, for example, try change data that should not be changed. All of these properties create a
sort of a trust layer. They create more trust in applications and more trust in users that are using them. But why
learn Ethereum specifically? Well, first of all, it allows us to create decentralized applications. It is a
multi‑billion‑dollar industry, and new players enter the field literally every day. Ethereum has a huge community
that is improving platform constantly. And the last, but not the least, Ethereum is one of the most in‑demand
skills in software engineering. Now let's look at some examples of applications that we can build using Ethereum.
First one could be an online voting, which would allow us to ensure that nobody has amended the results of the
voting. The second one is self‑executing legal agreements that do not require lawyers, and anybody can verify
that a legal agreement was executed exactly as it was specified. A very popular set of applications is called DeFi,
or decentralized finance, which is a set of financial applications on top of Ethereum. And the last example we will
talk about is digital ownership. We can create a provable record of who owns what, and nobody can maliciously
amend those records. Now let's take a very high‑level overview of Ethereum. At the bottom of Ethereum is an
Ethereum network. It has applications code and data used by these applications. The next layer is called Web3
API, or application programming interface. It allows to programmatically interact with Ethereum. And then using
Web3, we can build client applications and server‑side applications that interact with Ethereum. I hope that this
has piqued your interest in Ethereum just a little bit so you must be eager to know what we are going to learn in
this course. So we will start this course by looking into Ethereum protocol. And Ethereum protocol is the basis of
Ethereum network. Then, we will look into smart contract development, and smart contracts are executable bits
of code that run on Ethereum. We will learn a programming language called Solidity that is used to develop
smart contracts. We will then see how we can create a development environment for Ethereum to become more
efficient in developing smart contracts. And then we will look into how we can develop even more advanced
smart contracts. Now all of these topics, they will constitute the server‑side of our decentralized application. At
the end of the course, we will see how we can build a web application built on Ethereum. Now what do you need
to know to get the most out of this course? This course is for software developers, first of all. So you should be
familiar with at least one programming language. And you also need to know the basics of web development,
which will be important for the last part of this course. Now here is what you don't need to know. You don't need
to know anything about blockchain or Ethereum. We will cover everything in this course from scratch. You don't
need to be an expert in JavaScript. We will use it to write some simple scripts and tests, but I will cover all
nontrivial JavaScript features that we will use in this course. And in the last module, we will build a web
application using React, but you don't need to know React to follow along. Even more, we will cover the bare
minimum fundamentals of React so you can follow along with the demo and understand how a React‑based
web application works.

Blockchain Technology
Before we start talking about the Ethereum, let's briefly talk about what is blockchain. And this is important
because blockchain is a foundational technology for Ethereum. We will learn about how it was developed, and
we will talk about Bitcoin, the first application built on blockchain. We will then talk about how Blockchain works
in a nutshell. The history of blockchain starts in 2008 when an anonymous person named Satoshi Nakamoto
published a Bitcoin whitepaper. Up until this day, nobody knows who Satoshi Nakamoto was. But this paper that
he wrote described how to build a decentralized currency. This was a major breakthrough in cryptography. It
was the first working approach for how to build a digital currency that has no master of central nodes. This paper
also described blockchain technology. Following the whitepaper, in 2009, Bitcoin was launched, and it became
the first decentralized currency in the world. The development of Bitcoin ignited the cryptocurrency space. And
in 2011, there were already more cryptocurrency projects. Some of them were just clones of Bitcoin, but some of
them were more specialized projects. And by the way, when I'm saying a cryptocurrency, that is the same as
decentralized currency. Slowly, but steadily, Bitcoin was gaining more and more adoption. And in 2014, more
businesses and users started adapting Bitcoin. Now before discussing Bitcoin in more detail, let's discuss an
alternative to Bitcoin like a bank. Now if you want to send money, you can't do it directly. You need to rely on a
centralized financial institution, like a bank. The bank, in turn, is responsible for tracking financial transactions and
balances for its users and provides services like payments. But why would Satoshi Nakamoto would want to
design an alternative? Well, there can be a few reasons. First of all, the banking system requires a total trust,
which may not be an issue in developed countries, but can be quite an issue in developing countries.
Transactions in a banking system are quite slow and may take sometimes days to process, especially if this is an
international transfer. And a banking system has quite high fees. And how does Bitcoin compare to a banking
system? Bitcoin is just a network of machines, and this network stores a registry of assets. It stores who owns
what amount of Bitcoin. But there is no need to trust any individual, actor, or entity in this network. None of these
actors control the whole network. We can instead trust the algorithm that is underpinning the network. Using
this Bitcoin network, users can send payments to each other using Bitcoin as the currency. Now let's briefly
mentioned the main characteristics of Bitcoin. Bitcoin is a public registry of assets and transactions. Everybody
can see what transactions took place and what is the balance of each account. The Bitcoin network is
autonomous, and it is controlled by software and not by people. So even if there is somebody with malicious
intent, they cannot compromise the network. Bitcoin is permissionless, and anybody can join the network either
to use it for payments or to provide more computational resources for the network. And now the last, but not the
least, Bitcoin is cryptographically secure. Nobody can change the history of transactions, take their Bitcoins,
amend the transactions, etc. Now let's briefly talk about blockchain, the technology that underpins Bitcoin. As
the name suggests, a blockchain is just a chain of blocks. Every block has a list of transactions that took place,
and they're grouped into a block. A block also has a pointer to a previous block that happened before it. If we
follow this chain of blocks, we'll eventually get to the very first block that is called the genesis block. If we
traverse this chain in the opposite direction, we would be able to see what were the balances for each account
at any point in time. But who generates those blocks? Well, there is no central node in the system that generates
those blocks. Instead, Bitcoin is a peer‑to‑peer network. Everybody is equal in Bitcoin. Every node is connected
to a subset of nodes. And if somebody wants to send a transaction, they would just broadcast it to the network
through its peers. Those peers would validate incoming transactions, check that a sender has Bitcoins they want
to send, and then they broadcast it further to their peers. Later at some point, a block is generated in the
network. It is not generated by a single machine. Instead, there is a process that temporarily elects the leader.
Well, this leader generates a new block, and it stores it in its own storage and then broadcasts it to its peers until
the block is broadcasted to all other peers. And every peer will validate that the block is correct. And only if they
confirm that the block is correct, they store it locally to their storage, and it becomes the part of their state. Now
it is interesting to discuss what operations we can do with the blockchain. First of all, we can read historical
transactions, and we can create new transactions, and then these transactions are grouped into new blocks.
What we can't do, we cannot go back into the past and update all transactions. And we also cannot delete all
transactions and, say, pretend that this transaction never happened.

Hash Functions
Before we start talking about Ethereum, let's briefly talk about how a blockchain achieves its properties such as
immutability. At the core of it is a concept of a hash function. A hash function is just an algorithm that can take an
input of any length, and as a result, it generates a very long number. There are more multiple types of hash
functions, but all of them have the same properties. One property is that for the same input, a hash function will
always generate the same output. If we change the output just slightly, a hash function will generate a
completely different output. It will have the same length, but different value. It is important to understand that
the output value of a hash function or a hash value is not an encrypted data. We can compute the hash value
using a hash function, but it is impossible to go the other way around and get the input if we have just the
output. Now let's talk about the properties of hash functions. First of all, hash functions are very fast. An output
of a hash function is very small in size. Depending on the hash function, it is usually between 20 and 64 bytes.
The other important property is that it is impossible to find two inputs that would result in the same hash value.
And all these property together, they allow to use hash functions to compute digital fingerprints. For example, if
you have a file and you want to know if it has been changed, you can just compute its hash value. And if it's the
one that you expected, it means that the file has not been changed, and if it is different, it means that somebody
has changed it and you have a different hash value. And here's how blockchain uses hash functions. Each block
contains a hash value of the previous block, and this is how a blockchain maintains links between the blocks. If
someone tries to amend a block and, say, change the transaction, then this block will now get a different hash,
and this is why it is completely impossible to secretly change passed transaction or change blockchain data.

Ethereum Overview
Now once we've covered all the basics, like blockchain and hash functions, let's talk about Ethereum. And here,
we'll, first of all, talk about the rationale for Ethereum. Why would someone come up with an idea for this? We will
talk about how it was developed, and then we will have a 10,000 feet overview of how it works. To understand
how Ethereum was developed, let's look at the history of blockchain applications. At some point, blockchain
technology became very popular, but the problem is that every project was built on its own slightly‑different
blockchain implementation. For example, Bitcoin was useful for payments, and it had its own blockchain
implementation. Other projects like Namecoin, for example, that was based on blockchain to implement the
decentralized domain name system, again, had its own blockchain implementation. Another project called Nxt
for implementing financial services, again had its own blockchain as well. And the main problem here is that the
entry barrier for new applications was just too high. It was very difficult to develop your own blockchain for a new
application, so this is where Ethereum came up. It aimed to create a single blockchain that will allow to develop
applications on top of it. So instead of specializing for a particular application, it would be a platform for
developing any applications on blockchain. So, a way to think about it is those initial blockchain applications,
they were like old‑school pagers. It has one predefined function, and this function is built into it. Ethereum now is
like a smartphone. Instead of having one application or set of applications, it is a platform that allows developers
to build applications on top of it. Now Ethereum was designed in 2013. It was designed by the Vitalik Buterin.
And this is his real name. He is not an anonymous person. Ethereum development started in 2014. And in 2015,
there was the first release of the Ethereum network. Every major release of Ethereum has a code name, and this
release was named Olympic. Ethereum was slowly gaining adoption for the next five years until in 2020, there
was a so‑called DeFi Summer, a boom in activity in decentralized financial obligations. And in 2022, the
community has finished The Merge project, an upgrade of the execution layer of Ethereum that made it faster
and more efficient. Just like Bitcoin, Ethereum has its own currency. In case of Ethereum, it's called Ether, or ETH.
Just as Bitcoin, it supports financial transactions. But unlike Bitcoin, we can use Ethereum currency to pay for
computations on the Ethereum network. Ethereum is what is known as Turing‑complete, which is a sophisticated
term to say that you can just develop general‑purpose applications on top of Ethereum. And the way to think
about it is that Ethereum is like a cloud provider, you can upload your application to an Ethereum network, but
you have to pay with Ether and not with dollars or euros to run your applications on top of Ethereum. Now let's
look at how Ethereum works in a nutshell. In Ethereum, there are two types of participants. The first one is called
an externally‑owned account. An externally‑owned account is controlled by a person. It has a unique address
and an Ethereum balance, and this account can send Ether to other accounts, so similar to what we can do with
Bitcoin. Another type of participant is called a smart contract. And smart contracts, they are not controlled by
people, but they are controlled by code deployed on a Ethereum. Just like externally‑owned accounts,
contracts have unique addresses and Ethereum balance that they control. But they also have data associated
with them, which is called state, and they have methods that other participants can call. When a method is
called, it can change a state of a smart contract, send Ether, or interact with other contracts. Now Ethereum has
been around for quite some time, and it has some interesting projects, so let's briefly mention some of them. One
project is Auger. And Auger is a prediction market where people can bet on outcomes of real‑life events.
Another one is OpenSea. This is a marketplace for digital collectibles, which is an interesting concept when
something can be digital, and, at the same time, it can be a unique collectible item. The other interesting project
is called Uniswap, and this is a decentralized exchange for trading cryptocurrencies. And the other project is
called Compound, which is a fully‑decentralized platform for lending and borrowing. Before going to other
topics, I want to briefly mention the concept of Web 3. You may find this term when you read about Ethereum.
And the idea of Web 3 is that Ethereum and similar platforms are an evolution of the internet like we had Web 1,
where we just had static web pages, and now we are using Web 2 that consists of dynamic web applications.
Now, Web 3 doesn't have a specific definition, but what people usually mean when they refer to Web 3 is that
they refer to an internet based on smart contracts, native payments built within these applications, and digital
ownership of items on the network.

Ethereum Wallet
Now let's talk about how we can interact with an Ethereum network. To interact with an Ethereum network, we
need to use a special piece of software called a wallet. Despite its name, the wallet doesn't store any money or
ether, so the name is quite misleading. Instead, a wallet stores cryptographic keys that are used to sign
payments or transactions that you are sending to the network. So a better name could be a key store, but the
wallet is what everybody uses. There is no single wallet implementation for Ethereum; instead, there are dozens
of different wallets, each one with its own focus. And they're also developed for different platforms. There are
command‑line wallets, desktop applications, there are wallets that are run in a browser, and there are mobile
applications. But before we talk about how Ethereum wallets work, let's discuss how Ethereum accounts are
different from bank accounts. Well, bank accounts are issued by a bank, so there is an institution that creates an
account for you, while an Ethereum account is created by a user themselves, and it can be created by any user
at any time and any user can have as many accounts as they want. The bank count is mostly used for payments,
while an Ethereum account can be used for payments, but it can also be used to access Ethereum applications.
An important word of warning is that a bank account can be restored by a bank. So, for example, if you forgot a
password to your bank account, a bank can still help you to restore your password. An Ethereum account, on
the other hand, cannot be restored if the access is lost, so with Ethereum you are responsible for keeping it safe.
On the other hand, a bank account is controlled by a bank and a bank can block it or suspend it, etc. An
Ethereum account, on the other hand, cannot be blocked or deleted. And now let's talk about how an Ethereum
wallet works. A wallet is connected to several Ethereum nodes, and a node is pretty much just a computer
running Ethereum software. At some point, once a block is generated somewhere in the network, it is being
propagated to other nodes, and very soon it will reach your wallet. A wallet checks if there are any transactions
related to the accounts that it tracks, and if there are any such transactions, it updates the state of the account
in its local storage. Notice that the wallet doesn't store any funds, it just reflects the state of the network, and the
state of the network is stored on individual nodes. Now we've covered how wallets are processing payments, but
what is more interesting is to learn how a wallet creates those payments, and to do it, we need to talk about the
keys that a wallet is storing. When you create an account in a wallet, a wallet creates a so‑called private key, and
this is just a long number. A private key is used to digitally sign transactions that you send from a wallet, and it
should be private. Whoever has access to the private key will be able to sign transactions and control your
account. Now from a private key, a wallet creates a public key and an address. A public key is, as the name
suggests, it's public, and it can be used by anybody to verify that the sender of a payment controls a particular
account. Now if a wallet needs to send a transaction, it first of all creates this transaction, then it
cryptographically signs it using the private key, and then it sends a payment and a signature to the network, and
then any participant on the network can look at the signature and verify that the payment was sent by the
account owner. So anybody else on the network can verify that the payment is valid, but they cannot send
payments using your account. Now the system only works if you keep your private key a secret, so I urge you if
you use Ethereum, please keep your private key secret, otherwise, somebody might steal your account.
How to Get Ether
At this point, you might be wondering, how do you get ether? One way to get ether was to participate in the
Ethereum presale that happened just before the Ethereum network was launched, but it happened in 2014. If
you don't have a time machine and cannot travel back to 2014, another option is to purchase some E's for other
currency such as dollar, euro, or a cryptocurrency like bitcoin. You can do it on one of the various crypto
exchanges, and there is even a guide on an official Ethereum website that walks through how to do this. Another
option is to provide Ethereum infrastructure. Previously you could do this through the process called mining, but
after the merge, which was a major upgrade of Ethereum in 2022, it is now a different process called staking, and
we will discuss both mining and staking in way more details in one of the next modules. But for this course, you
don't need to spend any money. Instead, you can use test Ethereum network, which works just like a regular
Ethereum network, but Ethereum on it is free. There are multiple Ethereum test networks, but the most popular
test network at the moment is Goerli. It is very similar to the main network, and it will have a long‑term support,
meaning that it will receive all upcoming Ethereum updates, and this is a network that we will use in this course.
There are other test networks, and if you read other sources about Ethereum, you might encounter test
networks like Ropsten, Rinkeby, etc. However, all of these networks are already deprecated. Now you can also
create your own test network, and to do this, all you need to do is to run Ethereum software on multiple
machines and connect them together. To get test ether, we need to use a special service called a faucet, and all
we need to do is to send the request to a faucet, and we will get some test ether for free. We will see how to do
this in one of the next demos. Now, this however, works only for test networks, and if you see somebody
advertising a free ether giveaway on the main network, this is likely a scam. Notice that test networks are
completely isolated from the main Ethereum network. They have different history, different transactions,
different blocks, everything is different. You can have the same account on both networks, but they will have
different account balances. So if you get some test ether, it won't be reflected on the main network.

Installing Metamask
In this demo, we will see how to install an Ethereum wallet. We will see how we can install and use MetaMask,
and there are two reasons why we pick MetaMask specifically out of all other options. First of all, it has a browser
wallet, and we will use it later in the course to interact with the Ethereum network from a browser and to use it to
interact with web applications. And second of all, it is one of the most popular wallets, so it is useful to be at least
familiar with it. And then using this wallet, we will create an Ethereum account, and then we will use this account
in later demos. To install MetaMask, we first of all need to go to the official website and then click on the
Download button. This Download button will lead us to the extension web page for the browser that you are
using, and since I'm using Chrome on these demos, it directed me to the chrome web store page. Now if I click
Add to Chrome, it will ask me if I want to install MetaMask extension and I want to do this. Now, to start the
process, I need to click Get Started; agree or disagree if you want to share information about how MetaMask is
used, and I'll say I'll agree. And now it asks me if I want to create a new wallet or if I want to import an existing
wallet, and for the purposes of this demo, I'll show you how to create a new wallet. Now while creating a wallet,
MetaMask will generate a private key, and it will encrypt this private key in the browser. To encrypt a private key,
it asks me to provide a password. So here I've provided a password and I can click Create. I can skip this video.
What it did in the background, it created a private key, and now it gives me an opportunity to back up this
private key. The way it works is these Ethereum wallets encode a private key in a set of 12 words that are easy to
record or remember, and this is just another way to represent a private key. Here I show it to you because this is
a test account, but you should never share a private key for your own account in any format. What it asks me to
do now is to record this sequence of words that is also called a recovery phrase, somewhere in a secret and
secure location. Now once you've done this, you can click Next. And then it asks to repeat this secret recovery
phrase just to ensure that you have recorded it. Now once I've done this and MetaMask is satisfied that I have
recorded this recovery phrase, I can click Confirm, and we're done. We have created an account in MetaMask.
And this is the interface of MetaMask, so at the top it shows our account name, which is account ID, but it also
shows an account address, and we can use this address to send funds to this account. We can share it with
other users so they can transfer Ether to us. There are other controls that allow us to buy and send Ether, and
there's a list of different digital assets at the bottom, and the only entry here is Ethereum, which we have none
for now. And this is it, we can close this tab, and if at any point you want to interact with MetaMask, it should be
available here. And to make it accessible, all I need to do is to pin the plugin, and now we can always open the
MetaMask page by just clicking on this icon and it will show the same interface we saw before.

Using Ethereum
Now once we have MetaMask wallet installed, we will see how we can interact within an Ethereum network. To
do this, we will first see how we can get test Ether from a faucet, and then we will see how we can send the
payment from one Ethereum account to another one. And at the end of the demo, we will see how we can use
MetaMask to use a decentralized application. To get this Ether for the Goerli network, we will use this website. So
this website is goerlifaucet.com, and it is developed by Alchemy, which provides development solutions for
Ethereum and other blockchain platforms. To get this Ether, we first of all need to sign up for an account with
Alchemy, which I have already done, and then we need to provide an address where we want to send test Ether.
To get an address of our account, we need to go to MetaMask, then click on this button to copy and address to
clipboard. Now we have our account address, and we can just paste it here. Now I'll click Send Me ETH, and
we've got this nice animation from Alchemy, but now we can go and look at our account. It seems that there is
nothing here at the moment, but this is because we're looking at a different network. We are looking at Ethereum
Mainnet, but we actually need to change our network to Goerli. To do this, we need to click here, and as you can
see, we only have Ethereum Mainnet, and we don't have any test networks, so we first need to show these test
networks in MetaMask. To do this, we need to click here, and then switch this toggle for Show test networks.
Okay, now if we go back, we can select Test Network from this list, and let's select Goerli, and as you can see, we
already have 0.25 GoerliETH, and if you are going through these steps yourself and you got to this point and you
still see 0 ETH in your account, maybe just give it a bit more time, because there is a slight delay between
sending the funds and receiving the funds. All right, so we have Test Ether, so let's try to send some of it to
another Ethereum account. To send Ether, I've created another Ethereum account in a different browser, and
here it is. And to send ETH to it, we need to copy the address of this account, go back here, click Send to send
Ether, then provide an address of this different account, and select the amount of ETH we want to send. And
let's just send 0.01 of an Ether. Now let's click Next, and now we see a confirmation page where we need to
confirm that we indeed want to send Ether to this other account. And a few things to notice here are that we
see this Estimated gas field that specifies how much we will pay for this transaction if we decide to send Ether,
and then we see the total amount of Ether that will be collected from our account to send this transaction. We
won't dive deeply into how gas and fees work, but we will cover this in depth in the next module. So now let's
click Confirm, and as you can see, here we have a pending transaction that is being processed by the network,
so let's just give it a few seconds to complete. Just a few seconds later, this transaction was successfully
executed. Now let's go to our second account and see if it received our payment. And as you can see, the
amount of ETH has increased, and we have a new record in the Activity tab that shows that this account has
received 0.01 of an Ether. Now we saw how we can send transactions using a Ethereum, let's see how we can
interact with a decentralized application. And as an example, we will see how we can use ENS or Ethereum
Name Service. ENS is similar to DNS, which is a Domain Name Service, and its goal is to record human‑readable
names for Ethereum addresses. Now to use it, we need to go to this website, ens.domains, and then we need to
go to the application by clicking this button. Now this is the ENS, the centralized application, and as you can see,
it looks just as a regular web application. Now, the only big difference is that to use this application, we need to
connect our MetaMask wallet with this application. ENS has already requested permission to connect MetaMask
wizard, and this process of connecting MetaMask simply means that we need to specify which accounts can be
used with this application. And I have only one account, and I'll select it and click Next, and it shows a warning
that this application will see addresses and account balances. If we connect it, it won't be able to send
transactions, but it will be able to ask for permission to send the transaction. And if I approve it, MetaMask will
sign it using the private key it stores, and it will send the transaction to the network. And its application is
connected, and now we can use it just as a regular web application. So, let's try to see if there is a name on the
ENS available, and I'll just select a very long name that is unlikely to have any matches. I don't think anybody is
interested in this particular name. And let's click Search, and as you can see, this name is available, so we can
click on it, and if we want to purchase this name, we need to first specify that we want to use a MetaMask wallet,
and we can now try to register our name. And as you can see, it asks if we want to send another transaction, and
now this transaction is actually to purchase this name. So we could, for example, register our account address
with this human‑readable name, but we won't do this. As you can see, the centralized applications, they look
very similar to regular web applications, with some differences around using a wallet. But now, once we've
covered how to use MetaMask as a user, how to interact within a serial network, let's see how we can develop
our own smart contracts.

Summary
In this module, we've covered introduction to Ethereum and blockchain. We've learned that Ethereum is a
platform for building decentralized applications and that Ethereum is based on blockchain technology. We can
build various applications on top of Ethereum, like payments, domain name system, financial applications, and
many, many more. We've learned that in the nutshell a blockchain is just a chain of blocks. Every block contains a
group of transactions and a pointer to a previous block. The current block points to the previous block and so on
until it reaches the first block that is called the genesis block. If we traverse the blockchain from the very first
block till the end, we will be able to explore the full history of transactions on the network. We also covered that
in Ethereum there are two types of accounts, externally owned accounts that are controlled by people and
smart contracts that are controlled by code. People can interact with contracts and other people, and smart
contracts can interact with contracts and other people as well. Now, after we've covered the basic theory of
Ethereum, we are ready to start learning about how to develop decentralized applications. And in the next
module, we will learn Solidity, a programming language that is used to build applications on Ethereum.

Getti n g
Contracts Started wi th Smart
Inroduction
Hi, this is Ivan Mushketyk with Pluralsight, and welcome to the next module of this course, Getting Started with
Smart Contracts. In this module, we'll move from theory to practice, and we will start implementing our first smart
contract. And if you recall, a smart contract is an executable code running on Ethereum network. And to do this,
we will use the Solidity programming language, the most popular programming language to implement smart
contracts. To become a proficient developer of smart contracts, it is important to learn how they are executed.
And that's why we'll also spend some time on learning about EVM, or Ethereum Virtual Machine, the software
that executes smart contracts. This module has two main goals. First of all, we will write a very simple smart
contract. This smart contract will only be able to store a single value, using Ethereum blockchain. Sort of a Hello,
World! application in the world of smart contracts. But we will also learn the basics of smart contract
development, a foundational skill that we will build upon in the next modules.

Smart Contracts
Now we will start learning about how to develop smart contracts in Ethereum. Just to remind you, smart
contracts are executable bits of code that live on the Ethereuem network. Each smart contract has code and
data associated with it, and in this way they are similar to objects in object‑oriented programming. Each contract
also has a unique address and a balance of ether that this contract controls. To develop smart contracts for
Ethereum, we can use one of the few programming languages. The most popular of them is Solidity, that is a
JavaScript‑like programming language, and Vyper, a security‑oriented Python‑like programming language. In this
course we will learn Solidity, and this is because this is the most popular programming language to write smart
contracts for Ethereuem, and it is even used for writing smart contracts for other blockchain platforms. Now,
here is how to create a smart contract. First of all, we need to provide a smart contract in Solidity and define
methods and state fields of a smart contract. Then, once we have a definition of a smart contract, we can deploy
one or multiple instances of it to the Ethereum network. And notice that once a smart contract is deployed, we
cannot add or remove methods from it, or we cannot add or remove its state variables. And in this way, smart
contracts are similar to statically‑typed languages like Java and not dynamic programming languages like
JavaScript.

Solidity Programming Language


Now let's look at how we can define a simple smart contract in Solidity. A structure of a smart contract is similar
to a structure of a class. To define it, we need to use the contract keyword, then specify a name or a smart
contract, and then the body of a smart contract that will contain state variables and methods. To define a state
variable, we first need to specify a type of a variable, which is uint, or unassigned integer in this case. Then we
need to provide an access modifier that specifies who can access this variable, which we will talk about in more
details later, and then a name of the variable, which is val in this case. And we can also define methods in a smart
contract that our users can call to interact with a smart contract. And to define a function, we need to use the
function keyword, provide a name, a list of parameters, which is empty in this case, and specify a return value
from this function. And as with the variables, we need to specify who can call this function, and public means
that anybody on the network can call this function. Now, once we have this definition, we can specify the body
of a function, and in this case, it just returns the private variable from this contract. Now, so far, it might be pretty
familiar to other programming languages. What might be unusual is that in Solidity, we need to specify a version
of a compiler that should be used to compile this smart contract, and to do this, we use this pragma solidity
statement and specify a version of a compiler. The 0.8.0 means a version, and the ^ here means that we allow any
version until 0.9. In Solidity, we can write comments, and they look like in Java or JavaScript where we can have
single‑line comments, which is everything that starts with a //, or we can define multi‑line comments and
everything between /* and */ as a multi‑line comment. Types in Solidity shouldn't be a surprise to you. There is a
Boolean type that defines a variable that can either be true or false. There is then int type, which is a signed
integer, and integers in Solidity by default are 256 bits, and there's also uint for unsigned integer. If you need an
integer of a different size, there are types like int8, int16, etc, for 8 to 256‑bit signed integers, and similar types for
unsigned integers. There is also a string type that allows us to specify a string of characters, and there is a
special type for Ethereum address, and this can be an address either of a smart contract or an address of an
externally owned account. We can define variables as we define them in other programming languages. So, we
can define fields, and these fields form the data of a smart contract that is persisted in the blockchain. We can
also define function parameters that a function accepts when we call this function, and we can also define local
variables. Local variables are only accessible within a function, and they're not persisted to the network. We can
also update state variables, and when we update them, it will write new data to the network. Now we can also
define constants, and unlike variables, they cannot be changed anywhere in the code. And to define a constant,
we need to specify a type, then use the keyword constant, provide a name of a constant, and assign a value to it.
And then we can use this constant anywhere in the smart contract. Solidity also has a set of operators that are
similar to other programming languages, and it supports arithmetic operations, it supports reminder operation, it
supports power operation, for example, in this case, we use it to compute a cube of a variable. Solidity also
supports binary shift operations that allow to shift a binary representation of a number left or right, and it also
has the usual shortcuts, such as added value to a number or increment a variable. And, of course, as many other
programming languages, Solidity has comparison operators such as greater than or less than, and we can also
combine these conditions using logical operators such as logical && and logical ||.

Functions in Solidity
Now let's talk in more details about functions in Solidity. As in many programming languages, we can return
values from a function. To define a function that returns a value, we need to first use the returns keyword and
specify the return type in parentheses, and then in the body of the function, we can use the return keyword to
return a value from the function. We can also have a function that does not return anything, and in this case we
can just omit that returns keyword. In Solidity, we can also return more than one variable from a function, and
there are two ways to do this. One way is to provide two or more return types in parentheses, and if we want to
return multiple values from a function, we can list them in parentheses using the returns keyword. Solidity also
supports another syntax where we can specify names of return values, and if we do this, instead of using the
return keyword, we can assign return values using the names of return variables. Functions in smart contracts
can also call other functions. If we have a function like this that accepts two arguments, we can call it either
using a classic syntax where we specify a name of a function and then a list of arguments that we want to pass,
or we can use an alternative syntax where we can specify names of parameters, their values, and to do this, we
need to specify names and value pairs in curly brackets. Solidity also supports functions overloading, and
overloading is a case where we have several functions with the same name, but different parameter types, like in
this case where we have two functions named validate, but one of them expects a string and another one
expects an integer. If we want to call a validate function, Solidity will decide which one to execute based on the
parameters that are passed to a function.

Access Restrictions
The last topic that we will discover before we are going to implement our first smart contract are access
modifiers that specify who can access what methods on our smart contracts. And the reason why this is
important to discuss is because when we are deploying smart contracts on a public network, any participant can
have access to them and they can call any methods on our smart contracts. Since these method calls can
change a state of a smart contract, this might be dangerous. If you open access to all methods, anybody can
change the state of a smart contract in a way we don't want them to. A solution to this in Solidity is to specify
what methods can be called from the outside of the smart contract and what methods can be called only from
within the smart contract. And this solution works very similar to encapsulation in object‑oriented programming
languages such as Java, C#, etc. We've already covered the public function modifier, and just to remind you, it
means that anybody on the network, any participant can call this method. Now, if we don't provide a modifier,
this is the same as providing a public modifier, so these two definitions are equivalent. Now, external access
modifier is more restrictive than public modifier. It means that anybody from outside the smart contract can call
this method, but a smart contract cannot call this method itself. The last two modifiers, internal and private,
means that a method can only be called from inside the smart contract, but cannot be called from the outside of
it, and we will discuss the difference between private and internal later in the course when we will talk about
contracts inheritance in later modules. And yes, smart contracts can inherit each other like classes in
object‑oriented programming. We can also apply modifiers for individual fields, and public means that a value
can be read from the outside. It cannot be written from the outside if it is public. To change a variable, we need
to provide a method that actually changes it. Internal and private means that this variable can only be accessed
from inside the smart contract, and if we don't provide a modifier, it is different for fields than for methods. Fields
without modifiers are private by default.

First Smart Contract


And now it's time to implement our first smart contract, and for the first smart contract, we will do something
very simple; we will implement a smart contract that can store a single integer value. And while it seems very
simple, it will allow us to go through the basics that we will build upon in the next demos and followup modules.
Now to write our smart contract, we will use an online IDE called Remix that allows us to write and test smart
contracts. Now, to go to Remix IDE, we need to go to the remix‑project.org, and then click on the REMIX IDE
button. Now this is an interface of Remix IDE, and let's explore what we can do with it. First of all, we have a File
Explorer on the left, and it shows file hierarchy of files in our project. Now, we can add new files and folders using
this File Explorer, and we also can create multiple different workspaces, each one with its own independent set
of files. We can also go to the next step, which is Search if we want to search through the files in our project. The
next step allows us to compile our smart contract, and we will see how to do this in just a bit. And once we have
a smart contract, we can go to the next app, and we can deploy our smart contract, and we won't be deploying a
smart contract to an actual network in this demo, but instead, we will use a Remix VM that is selected here,
which is an embedded test environment, which will allow us to test our smart contracts. There are also a few
more tabs at the bottom, like here is a Plugin Manager, which allows us to enable additional plugins, and here we
have some additional settings that we can configure. Now, to get started with our smart contract, first of all, let's
create a new workspace, and I will call it HelloWorld, and we can also choose a template, which is a
preconfigured set of files that implement a particular smart contract, and I'll just select blank so we will start with
an empty workspace. Now let's add our first smart contract, and I'll call it HelloWorld.sol, and sol is in a file
extension for smart contracts in Solidity. And here I have a blank file. Now the first thing that I need to do is to
specify a version of a Solidity compiler that I want to use in this project. And for this project, we will use Solidity
version 0.8, and now we need to define our smart contract, and I'll call it HelloWorld, and the first thing that we
need to do here is to specify state variables for our smart contract that will define what kind of data our smart
contract can store. And I'll define a single variable of type uint, which is called value, and I'll make it public so
anybody can read this value. Now we'll add a single method to our smart contract that will allow to change the
value of our only variable, and I'll call it setValue. It will receive just one parameter called newValue, and I'll make
this method public. Now, as you can see on the right, Remix also writes an estimation of a fee that we will have to
pay to execute the smart contract, and it is estimated in gas and we will see how this works in details in one of
the later clips in this module. Now, let's implement our method, and to do this, we just need to assign a new value
to our variable. Okay, and that's it. Our smart contract is ready. Now we can go to the Compile tab, and we can
compile our smart contract. Now a compiler gave us a single compilation warning, and what it tells us is that in
Solidity, we need to provide a code license for our smart contract. Essentially, we need to add a comment like
this, which starts with a mouthful, SPDX‑License‑Identifier, and then we need to specify the name of our software
license, which can be an open source license or unlicensed, if this code is not open sourced. Now, we can
recompile our smart contract, and by the way, if you don't want to constantly click on the Compile button once
you change your smart contract, you can also toggle the Auto compile checkbox here, which will recompile your
smart contract after every change. Now since our smart contract is now compiled, we can deploy it, and to do
this, we need to select our smart contract here, and it is already selected, and click Deploy. And if we scroll
down, we see a list of all deployed smart contracts, and they are deployed in this Remix testing environment,
and we only have our one deployed contract here. If we click on this button, we'll see a list of methods that we
can call to interact with our smart contract, and we have two methods here. One is setValue, the ones that we've
defined, but we also have a method called value, which is the same name as the name of our variable, and this is
because our variable is public, so Solidity has defined a public method to read this variable. Now let's see how it
works. Let's try to write a new value, for example, 12, and set this value, and in this console below, we see what
happened with our transaction, and this green checkbox means that our transaction was successful, so our
method was executed without any errors. To read the current value of our variable, we need to call the value
method, and to do this, we just need to click on this button. There were again no errors, but notice that Remix
has displayed the result value that was returned by this auto‑generated method. So that's it. It seems like our
smart contract works as we expected. Now, let's see what happens if we change this public to private. And as
you see, we have this green checkbox here, which means that our smart contract was recompiled. We'll now
deploy it, and to deploy it to avoid any confusion, I'll remove the old smart contract, I'll click the Deploy again,
and we have a new smart contract deployed. And if we toggle here, we only have one method that we can
interact with, which is our setValue method.

Smart Contracts Execution


Now, once we've created our first smart contract and ran it in a test environment, let's talk about how smart
contracts are executed. Ethereum nodes do not run Solidity code. Instead, they run what is called a byte code.
So a human‑readable Solidity code is first transformed into bytecode, and bytecode is basically just a set of very
low‑level commands such as add, subtract, compare to numbers, etc. Now, this bytecode allows Ethereum to
have common representation of smart contracts that can be used by different programming languages. So if we
have a smart contract in Solidity, then using a Solidity compiler, we can transform it into Ethereum bytecode, and
then this bytecode can be deployed and executed on the network. The same process works for other
programming languages like Vyper. While it has a different compiler, it all compiles down to a
language‑independent bytecode. Now let's talk about how this bytecode is executed. On every Ethereum node,
there is a component called Ethereum Virtual Machine, or EVM. Now, EVM can run this Ethereum bytecode.
Every node on the network stores a number of contracts that can be executed, and every contract has
bytecode that EVM can run. Now, just to give you an idea of how Ethereum bytecode looks like, let me give you
a few examples. There are a few hundreds of bytecode instructions in Ethereum, but we will look at just a few.
The first one is ADD, and it just adds two numbers. When it is compiled to a bytecode, it is represented as a
single byte with a value 1. There is another bytecode instruction called MUL, and it has code 2, and it multiplies
two numbers. Ethereum also has comparison operators like less or equal, and it also has some very specific
operations like computing SHA3 hash, deploying a smart contract or storing data to an Ethereum network. EVM
is implemented as a so‑called stack‑based VM, which means it is based around a stack data structure. This data
structure has two operations, push, to add an element on top of a stack, and pop to remove a top element in the
stack. All Ethereum instructions operate on top elements in the EVM stack. Now let's look at a very simple
example like a stack‑based machine like EVM can execute a simple expression. Let's say we have an expression
that multiplies two numbers and then add another number and we want to execute this expression. Now,
roughly, it will be compiled to a bytecode like this, which has a sequence of these bytecode instructions that
EVM will execute one by one. First it will execute the PUSH command that stores number 2 on the stack. Then it
will execute the second PUSH command that will push the number 3 on the stack, and then it will execute the
multiply command that will take the top two elements of the stack, multiply them together, and put the result of
this multiplication to the stack. To implement the addition operation, it will first push the 1 to the stack, and then
call the ADD instruction to take the first two elements, add them together, and write the result of this expression
to the stack.

Transaction on Ehtereum
Now let's talk about how we can interact with an Ethereum network. So far, this aspect was conveniently hidden
from us by Remix, but now we will learn about how it works, and we will see it in action later. No matter in what
way we want to change the state of the network, either to deploy a contract, or send Ether, or change a contract
state, we need to send a transaction. And here is a way to visualize it. A Ethereum network has a particular state.
If we want to change it, we need to send a transaction. Once a transaction is executed, it changes an existing
state of the network, and now we have a new Ethereum state. For performance reasons, Ethereum groups
transactions in blocks, and all transactions in a block are executed together. These are the same blocks, by the
way, that we've discussed previously where we were talking about the blockchain structure. Now I want to note
a few things about transactions execution. First of all, transaction execution is atomic; it either completes
successfully, or if it fails, it results in no changes to a contract state. Also, transactions on a smart contract
execute one after the other; they do not run in parallel so they cannot interfere with each other. To send a
transaction, a wallet forms a message and sends it to the network, and this message has a particular structure
that we will discuss now. First of all, a transaction has a nonce, and a nonce is just a transaction number from a
particular account. So for example, when a wallet sends a first transaction for the account, the nonce number is
0, then for the second transaction it will be 1, and so on. The second, the other parameter, is a gas limit, which
specifies a maximum amount of gas a user is willing to spend for a transaction execution, and we will talk about
how it works in one of the next videos. The other field is destination. This is an address of a receiver of a
transaction. It can be an address of a smart contract if we want to execute a method, or it can be an address of
another user if we want to send Ethereum. A transaction also has an amount field, and this is used for Ether
transfers. A transfer can be either to another user, or to a smart contract. The next three fields are v, r, and s, and
these fields together form a signature of a transaction. As we talked before, a signature is used to verify that the
center of a transaction is the owner of the account that sends funds or sends a transaction. And the last field
that we will discuss is called init or data, and it has a dual purpose. If a user wants to deploy a smart contract,
then this field will contain the byte code of a smart contract to deploy, or if a user wants to call a method on an
existing smart contract, this field will contain arguments for a method. Now let's see how smart contracts are
executed on Ethereum. The process starts with one of the users creating a transaction. This transaction contains
the byte code for a new contract, and it is sent to all of the peers of this user. The peers validate this transaction
and can either reject it or send it to other peers, so sooner or later, all nodes on the network will see this
transaction. At some point, one of the nodes will generate a new block, and this block will contain the byte code
of this new smart contract. This node will send this block to other nodes. Once this block is stored, we can now
execute methods on this smart contract. And the process for this looks very similar. If the user wants to call the
method, then a user creates a transaction. Its transaction is then sent to its peers that validate this transaction,
and then later, a block will be created that contains an executed transaction. Now, so far, we were talking about
how transactions look like and what fields they contain, but now let's talk about the structure of a block. A block
contains many fields, but we will talk about the most important fields. First of all, a block contains a block number,
and a block number is just an integer that is incremented for every new block. A block also has a hash of the
previous block, and this is the mechanism that we've discussed that links blocks together in a blockchain. As
we've discussed before, a block contains list of executed transactions that were executed in this block. And also,
a new block contains a new state of the network. And in case of Ethereum, the new state of the network is stored
in a tricky data structure called Patricia tree, and the way it works exactly is beyond the scope of this course.
Now the other field is a timestamp, and a timestamp specifies the time when this particular block was generated.
To wrap up the discussion of transactions, let's talk about smart contract limitations. Now, one limitation arises
from the fact that any participant can validate any transactions, and because of this, smart contract execution
should be deterministic, which means that a state change should depend only on the inputs in a transaction and
the current state of the network. This means that contracts cannot do things like access outside resources, like
sending an HTTP request, or they cannot generate truly random numbers by themselves. However, there are
solutions for this, and while we won't discuss them in this course, you can look into things like blockchain oracles
that try to solve this problem, and specifically, you can look into the work of the Chainlink company that provides
oracles for Ethereum.

Paying for Computation


Every time we want to execute a transaction in Ethereum, we need to pay for its execution, and the more
computation a transaction performs, the more we'll have to pay. We need to pay for every bytecode instruction
that is executed during a transaction execution, and the more computation we need to perform, the more we'll
have to pay. The payment we pay is then collected by nodes on the network that provide infrastructure for
Ethereum. Now, you might be wondering why it cannot be just free, and the main reason for this is the payment
mechanism is a way to defend the network against attackers. Otherwise, someone could just send a smart
contract that executes an infinite loop and it would just clog the network. So you might think that since
Ethereum has its own currency, we'll pay for execution in Ether, but it is slightly more complicated than this. The
prices for transaction execution are calculated in gas, which is a virtual currency in Ethereum. You cannot buy or
sell or store gas, and what happens is every transaction specifies an exchange rate from Ether to gas. But the
price of every command, the price of every bytecode instruction, has a fixed price in gas. So here I picked
examples for different bytecode instructions and how much they cost in gas. Arithmetic commands like addition
and multiplication, they cost around 3 or 5 gas. A complex command like SHA3 hash calculation will cost at least
30 gas, but the exact price will depend on the size of data to hash. To create a new smart contract, we'll have to
pay 32,000 gas, and to store a single word on the Ethereum blockchain, we'll have to pay 20,000 gas. As you can
see, each command has a fixed gas price, but the exchange rate between gas and Ether will change from
transaction to transaction. And here is how paying for transactions work. Every transaction includes the
maximum gas to spend and the gas price. The payment is done from the sender's account, and they should
have enough Ether to pay for a transaction. After this, when a transaction is executed, the gas is spent on every
bytecode instruction. If there was enough gas to execute a transaction, then the transaction is executed and
the remaining Ether is refunded. If there was not enough gas, then the state of a smart contract will not be
changed, but the gas is not refunded. It will be spent even if the execution of a smart contract has failed. For
convenience, Ether has multiple denominations that can be used to measure fractions of Ether. The smallest
possible denomination is called a wei, and a wei is one tenth in the 18 power. This is the small amount of Ether
that we can represent, and when we write software for Ethereum, all Ether amounts are represented in weis, and
that's why when we work with Ether in the code, we always represent Ether amount as an integer.

Transactions and Calls


So far, we were talking about one way to interact with the Ethereum network, which is sending a transaction. And
transactions can change the state of Ethereum, but they also cost Ether to execute and they take time to
process. The other way to interact with the Ethereum network is called a call. A call cannot change a state of the
network, but it is free to execute and calls are much faster than transactions. However, they can only be
executed on a function with a view or a pure modifier. And these modifiers, they are different from the modifiers
that we've discussed before. Now if we define a function like this, it means it can read and write contract data.
However, if we add a view modifier, it now restricts this function and it will be able to read data in the smart
contract like it can read this state variable, but it cannot change the state of this contract or the state of the
network. And if we use the pure modifier, a function with that cannot even read the state of the smart contract
and it can only calculate its outputs from its inputs.

Removing Smart Contracts


Until now, all our smart contracts were running in a browser in a Remix test environment, but in the next demo,
we will take our smart contract and we will deploy it to Goerli using the Remix IDE. And then once our smart
contract is deployed, we will interact with it using Remix. After we are done with our smart contract, we will then
remove it from the network, and this is what we are going to discuss next. To remove a smart contract, we need
to use the selfdestruct function in Solidity. Once this function is executed, a smart contract will no longer be
able to process calls or transactions. And an interesting point about the selfdestruct function is it actually costs
negative gas, which is an exception to a general rule, and it costs negative gas because we are freeing resources
from the network. But one thing to keep in mind is even if we remove a smart contract from the network, the
history of the smart contract will still be in the Blockchain. We won't be able to make any new calls, but
everybody could see when the smart contract was deployed and what methods were executed. Now let's see
how we can use the selfdestruct function. To call the selfdestruct function, we need to provide a beneficiary
address. If you recall, smart contract has an Ether balance associated with it, so we can specify where to transfer
the remaining Ether from the smart contract when it is being removed. Notice that to transfer Ether in Solidity,
we need to use special address payable type, which is just the same as a regular address, but we specify that we
can send Ether to this address. We can even make the remaining balance inaccessible, and to do this, we can
send all remaining funds to the account with address 0, which nobody has access to. And this process of making
Ether or other cryptocurrency inaccessible is also called burning the funds.

Using "selfdestruct" Function


In this short demo, we will implement a remove method, which will allow us to remove a smart contract from an
Ethereum network, and to do this, we will use the selfdestruct() function. To implement a remove method, we
need to define a new function called remove, and I'll make it public so anybody can call it. And now we need to
call the selfdestruct() function. As we've discussed, we need to provide an address where to send any Ether
balance that our smart contract instance has, and since we won't be sending any Ether to our smart contract, it
won't have any, so it is pretty safe to provide here a 0 address. Now notice that a compiler has shown us an error.
It says that we are providing an invalid type for argument in this function call, which is because we are passing 0,
which is a number, but we need to pass an address. And to do this, I can convert 0 to address for which we have
to call the address function and pass the value of an address to it. The compiler is complaining again, and in this
case, it says that it cannot converge from address to address payable, and this is what we've discussed before
that there is a special type in Solidity for addresses that can receive payments. And again, it is not hard to fix. All
we need to do is to use the payable function to convert an address to a payable address, and that's it. As you
can see, there are no more compiler issues. I have the green checkbox on the left, which means that there is no
issue with compiling our smart contract, so let's try to deploy it. And it was deployed successfully. Let's try this as
a value, say 12. We can now read this value so it works fine, and now let's call the remove method. As we can see,
there were no errors, so this method was executed successfully, but now, if we try to read the value from our
smart contract, it returns 0 because the smart contract has been removed from the network.

Deploying Smart Contracts


In the last demo of this module, we will see how we can deploy our smart contract to the Goerli network. And
once we have our smart contract deployed, we will send some transactions and calls to the test network. And
once we've done with this demo, we will then remove our smart contract from the test network. All right, so we
still have our smart contract from the previous demo and we won't change any code, but instead we will just
deploy it to the Goerli network instead of deploying it to a test Remix environment. And now to deploy our smart
contract to a Goerli test network, I need to scroll up and select the environment where we want to deploy. And
here I will select Injected Provider ‑ MetaMask. What it means is that to interact with an Ethereum network,
Remix will go through the MetaMask plugin that is installed in our browser. And if you remember, in MetaMask we
can select which network to connect to and which account to use. And to do this, MetaMask injects a special
object called provider that Remix will use to interact with Ethereum. And now I want to specify that I want to
connect Remix with MetaMask and use the account that we have created before. So Remix is now connected to
Goerli through MetaMask, and now we can deploy our smart contract. And to do this, I need to scroll down here.
I need to recompile our smart contract. Click Deploy, and as you can see now, instead of deploying our smart
contract, we need to confirm that we want to send a transaction to an Ethereum network, and if we confirm this,
MetaMask will sign a transaction and send it to Goerli. Now to do this we need to scroll down here and click
Confirm, and instead of immediately executing this transaction, it is now being processed by the network and we
can look at the state of a transaction using the link that was provided by Remix. And if we scroll up, we can click
here, and it will lead us to the website called Etherscan, where we can get information about pending and
executed transactions. So this is a page for the transaction that we've just sent, and we can see a few interesting
bits of information here. First of all, as you can see, we have a Status field which is Success, which means that our
transaction was successfully executed. We then see a Block number, which is the block to which our transaction
was included. We see a Timestamp of a transaction, we see an address that sent this transaction, and we also
see that this transaction has created a new contract with this address. We also see information about the
amount of Ether that was sent, which is 0, Transaction Fee, and the Gas Price for this transaction. Now we also
can click on the block number, which is a link, and it will give us information about the block; the Block Height,
which is a number of our block in the Blockchain since the beginning. We see a number of transactions included
in this block, and we can explore them if we want to. And we also see other additional information about the
block. Now we can go back and we can try to interact with the smart contract. Just as before, we need to click
on this button and we have three methods that we can call. Let's first try to setValue. And, again, to interact with
a smart contract in an Ethereum network, we need to sign a transaction, and I will do it just as before. And now
our transaction is being processed, so let's just give it a few seconds. As we can see, our transaction was
successfully executed and now we can try to read value from our smart contract. To do this, we will call the value
method, and this call has already been executed, and as you could see, it was performed almost instantaneously
and we didn't have to sign a transaction to send to the network. And this is because to call the value method we
had to use a call operation which is free and much faster than sending a transaction. Now, to clean up after
ourselves, let's remove our smart contract, and to do this, we need to call the remove method, sign a transaction,
and wait until this transaction will be executed. Okay, so our transaction was successfully executed, and if we try
to call the value method now, it returns 0, so our smart contract has been removed.

Summary
In this module, we've covered the basics of smart contract development and implemented a simple smart
contract. As we've learned, every Ethereum node runs an Ethereum virtual machine, or an EVM for short. Every
Ethereum node also stores smart contracts, and these smart contracts are represented as byte code
instructions, which are just low‑level operations such as add, multiply, divide, and so on. In order to execute
these smart contracts, they should first be compiled into byte code, and to get byte code, we first need to use
one of the existing compilers to compile code into byte code. We've also learned that to change the state of an
Ethereum network, for example, to send the payment or to deploy a smart contract, we need to send a
transaction. These transactions are then grouped into blocks, and when transactions are executed, an Ethereum
network changes its state according to executed transactions. We've also covered that there are two ways to
interact with an Ethereum network, calls and transactions. A transaction can change a state of a network, but it
takes time to execute, and it takes Ether to process. Another option is to use a call operation. It is free and much
faster, but a catch here is that a call operation cannot change a state of a network. So in this module, we have
covered just the basics, but in the next module, we will dive much deeper into the Solidity programming
language. We will learn things like data structures, control structures, input validation, and so on. And we will use
this knowledge to build some more interesting and more complex smart contracts.
Solidity Programming Language
Introduction
Hi, and welcome to the next module of this course called Solidity Programming Language. In the previous
module, we've just scratched the surface of what we can do with Solidity programming language, and in this
module, we will dive deeper into Solidity. We will first look into data structures, such as arrays and mappings. We
will learn about control structures, such as ifs and loops. We will learn about structs, and structs is a way to group
several fields together in a single type. We will also learn how to perform input validation in Solidity, and we will
also use many other useful methods and language features. And to put our skills into practice, we will build a
simple voting smart contract on Ethereum. Now, without any further ado, let's get started.

Arrays
In this module, we will develop a smart contract for a simple voting app. In our application, anybody will be able
to cast a vote, and we will have a predefined set of options a user can choose from. And we also will only allow
one vote per Ethereum account. Now, to store voting data in our smart contract, we'll use arrays, a data
structure that we have not used before. Arrays in Solidity are very similar to arrays in other programming
languages. It is a way to store a sequence of elements in a smart contract. Now, all of these elements in an array
should have the same type, and this is where Solidity is different from other programming languages, such as
JavaScript, that allow us to store, say, integers and strings in the same array. Arrays allows us to get and set
elements by a numeric position, and they are a built‑in Solidity feature, so we don't need to use any third‑party
library. In Solidity, an array can be of one of two types. It can be a dynamic array that has a variable length, so it
can change as we remove or add elements to this array, or it can be statically‑sized array when the length of an
array is predetermined at compile time. First, we will discuss dynamic arrays, and to define a variable of a
dynamic array type, we need to specify a type of an element in the array, then use the square brackets and the
name of our variable, and this will create an empty array in Solidity. We can also create an array with a specific
size. So, for example, if we use this syntax and in parentheses we provide an initial size of an array, this will create
an array of size 2. Now, what we can do with an array, first we can get an element in an array by its position. And
keep in mind that in Solidity elements in array, they are numbered from 0. Then we can set an element in the
array, and to do this, we need to use this syntax. We need to provide the name of our array, then in square
brackets provide the position of an element we want to change, and the new value to write into this position. We
can also get a length of an array using the .length property. And we can add an element to the end of the array
using the .push method and provide a new element to add to an array. If we need an array with a specific fixed
size, then we need to use statically‑sized arrays. And to do this, we need to use a very similar syntax, but now,
instead of using empty square brackets, we need to provide a size of an array, and in this case, we'll create an
array that can only be of a length 5. It cannot shrink, it cannot extend its length. So with a statically‑sized array,
we cannot use the push method to add a new element to the end of the array, but we can still use all other
operators. We can get an element by its position, we can write an element to a specific position, and we can get
the length of our array. In Solidity, we can also define multi‑dimensional arrays. So, for example, in this case, I
would create two‑dimensional arrays because there are two pairs of square brackets. Solidity also defines types
for static byte arrays of various sizes that range from bytes1, which is a byte array of size 1, till bytes32, which is a
byte array of length 32. And it also has a type called bytes for a dynamicBytes array.

Reference Types
Now let's cover an important topic of value versus reference types. All types that we were using so far were
value types. Integers and Boolean, they're all value types. Most of the new types that we will learn in this module
will be reference types. So, arrays and structs, those of reference types. But what are the differences between
value and reference types? The main difference between them is what happens when we copy a value of each
type. If we copy a value type, it creates a copy of a variable, and if we change a copy, it doesn't change the
original variable. So, in this case, the value of the a variable remains unchanged. It is different with reference
types. If we assign an array, for example, to a different variable, it doesn't create a copy. In this case, both a and b
refer to the same array. This is why they're called reference types. If we change array b in this case, this will affect
both variables. And since we're going to use reference types a lot in this module, this is something to keep in
mind.

Memory
Now we'll have to talk about an important, but what can be a slightly confusing topic in Solidity, which is memory
and smart contracts. In Solidity, a variable can be stored in one of three places: memory, storage, and calldata.
So, let's see what is the difference between those three places. Well, memory is for temporary variables. They're
only stored for the duration of a call or a transaction, and as soon as it finishes, they disappear. However, memory
is very cheap to use. Storage, on the other hand, is for contract state. If we write something to storage, it is
persisted between transactions. However, the downside of storage, it is orders of magnitude more expensive
than using memory. And calldata is a special location for function parameters. Now it is immutable, we cannot
change it, and it is the cheapest to use among all three. Storage and memory have important implications for
reference types. Now, for example, this array in the smart contract field it is stored in storage. We don't need to
specify it explicitly. All contract fields are stored in storage. But if we define a local variable for an array, we need
to specify if we want it to be stored in memory or in storage. If we store a local variable in memory and assign a
contract field to it, then Solidity will copy data from storage to memory, and any changes to this array will modify
a copy. However, if we specify that we store our array in storage, and in this case, this assignment will not create
a copy, instead, if we make any changes to it, it will modify an original array. If we use reference types for input
parameters or outputs, we need to specify their memory types. For input parameters, it can be either calldata or
memory. Calldata is cheaper to use, but it is immutable. And we also need to specify storage type for return
values, which can be either memory or calldata as well.

Constructors
Before we implement the first version of the voting smart contract in Solidity, there are two more Solidity
features we need to learn. One of them is constructors. Constructors allows us to initialize fields of a contract
when it is deployed to a network. This should be a familiar construct to you. If you're familiar with other
object‑oriented programming languages, the main difference between Solidity and other programming
languages is that in Solidity, a smart contract can have only one constructor. Now, let's look at an example of a
constructor in a smart contract. To define a constructor, we need to use the constructor keyword, then provide a
list of parameters to constructor, and this works just as with a regular function, and in the body of a constructor,
we can specify how to initialize fields of our smart contract. Now, Solidity has a special type of field that can only
be changed in a constructor. These are called immutable variables. Immutable variables are similar to constants
that we have already discussed before. The main difference between them is that constants cannot be changed
anywhere in the smart contract while immutable variables can be changed in a constructor, but they cannot be
changed in any other function.

Input Validation
The last thing that we need to cover before starting working on our smart contract is how to reject invalid
transactions. Some users might try to execute invalid transactions. They might pass invalid arguments. For
example, they might try to vote for a non‑existing option in our voting contract, or some users might try to
change the state of a smart contract in an invalid way. Now, we need to reject those bad transactions. And to do
just that, Solidity provides multiple functions, such as revert and require and assert that we will learn in this
video. The main common thing between those functions is that if any one of them is executed, a transaction will
be stopped, and it will revert all state changes so far. Require is a function that you will probably use most often,
and it works like this. If you call require, you need to provide a Boolean expression. If this Boolean expression is
false, execution of the transaction will be stopped and reverted. Now we can optionally provide an error
message so if a transaction is reverted, a user might get more information about what happened with a
transaction. Now, the thing to keep in mind that when a transaction is reverted, the remaining gas is refunded to
a user, require is usually used to verify arguments passed to a function in the smart contract. But there is
another method that is used to verify an internal state of a smart contract to make sure that the state is
consistent. Assert and require, they work very similarly, and the biggest difference between them is that if assert
is executed, it will use up all the remaining gas. And the reason behind this is maybe if an internal state of a smart
contract is violated, then the user might have tried to do something malicious. So a developer of a smart
contract might decide to punish an attacker. Solidity has another function that is called revert. And unlike
require, revert does not accept the condition. If this function is executed, a transaction will be reverted without
any conditions. Now we can also provide a condition for revert by using an if statement. With Solidity, we can
also define a custom error. Now, these error types are defined like this. We use the error keyword, then the name
of an error, and then the list of parameters that an error has, and these parameters allow to store information
about why an error occurred so a user that sent a transaction might get more information about what happened.
We can also define a custom error without any parameters. Now, to use a custom error, we need to use the
revert keyword, provide the name of an error we want to use, and pass the values for the parameters of this
error, and we can use this key value syntax to specify the value of each parameter. If you read some old Solidity
code, you might encounter that throw keyword. Now, this keyword is deprecated. It was used in older versions of
Solidity, but nowadays you should use revert, require, and assert methods instead.

Voting
Now let's implement a simple voting smart contract using Solidity. In this smart contract, we will implement a
constructor that will allow us to initialize it, and we will also implement methods to vote and get voting results.
Now to start, I have already created a template for our voting smart contract. I have defined a constructor that
accepts a single parameter with a list of options that our users can vote for. And I've defined a method called
vote that our users can use to vote for one of the options. To start working on the smart contract, I need to
define the fields of the state of the smart contract. And here we will have two fields. First, we'll have an array of
votes, and each element in this array will contain a number of votes that users have casted for an option with a
specific position. And we'll also store a list of options that were used to initialize this smart contract. Now, once
we have our fields, we can initialize them in our constructor. First of all, we can initialize the options array, and to
do this, we just assign a parameter in our constructor to the state field. And then we need to initialize the votes
array. And to do this, I create a dynamic array of integers, and I create it with the same size as the list of options
that was passed to this constructor. Now to implement the vote function, what we need to do, first of all, we
need to record the vote, and to do this, we need to increment a number of votes for a particular option. To do
this, we'll read the number of votes that we have so far. We add 1 to this and restore it back to our array. But our
users can provide an invalid option number, so we need to protect ourselves from this. And to do this, we can
use the require function, and we can provide a condition that the option that was provided should be strictly
less than the length of the options array. We don't need to check if the option is negative because we use the
uint, which is an unsigned integer, which cannot be negative. And I'll also provide an error message here as well.
Okay, so now we can go to the Compile tab, and we can compile our smart contract. It seems like there were no
errors, so we can now deploy it. And notice that to deploy it, we need to provide an options list, which is the
parameter that we have in our smart contract. So to do this, I need to provide a list of strings, and I need to
encode it as a valid JSON, which I'll do like this. I'll define a JSON array, and I'll provide two values, coffee and tea.
So our users can vote for their favorite drink. And I'll click Deploy. And it seems that our contract has been
deployed, and if we go to the list of deployed contracts, we can see our smart contract. And notice that we have
three methods for our smart contract. Vote is the method that we have defined, and we have two methods for
the public fields that we have defined in our smart contract, but they won't return the arrays themselves. This
auto‑generated method allows us to provide a position of an element that we want to read. So, for example, if we
provide 0 here and click options, it will return the first option in the list of options. If we want to get the full array,
we will have to implement these methods ourselves. Now let's see how the vote method works. So let's vote for
option number 1, which is coffee. And it seems like transaction was executed successfully. And if we try to get
the number of votes for the first option, it now returns a 1. If we try to get it for the second option, it will return 0.
Now let's see how require works. So if we try to vote for an option that doesn't exist, then we will get an error
because we explicitly check that an option position is valid. Now we can also add two more methods that return
an option array and the votes array. Seems like no errors there. And now we can remove this smart contract and
deploy a new smart contract with these new methods. And it seems like it has been deployed. And now we have
two more methods, and if we call getOptions, we'll get the full array instead of getting individual elements.

Overflow Protection
Just to wrap up our discussion of reverting by transactions and error handling, we need to talk about overflow
protection. Overflow protection is an important safety check that is embedded into Solidity programming
language, and it ensures that numeric values we are trying to store can fit the ranges of the variables that we
use. And it is important because whatever numeric type we use, it only has a limited range of values it can store.
But why is it so important to embed it into the language itself? Well, because it can break some smart contracts.
For example, let's say in a smart contract, we're storing an amount of a contribution to an auction. Now if we
somehow try to write a value that is bigger than a particular type can store, that can lead to incorrect results.
Solidity has built‑in protection just for this specific case, and it is a relatively recent feature. It was only added to
version 0.8 of Solidity. So let's look into this using a simple example. Let's say we have an 8‑bit variable. An 8‑bit
variable in any programming language can serve values from 0 to 255. What happens if we store the maximum
variable already and we try to increment it by one? In Solidity, as in many other programming languages, what
will happen is that the value will overflow and v will now be equal to 0 instead of 256. But in the current Solidity
version, what will happen is it will raise an error and it will revert all state changes that have happened so far. Now
we can optionally disable this behavior, and to do this, we need to use a special unchecked block. And if we
perform any numeric operation within the unchecked block, then all numeric operation will be performed as they
were performed before. So for example, in this case, if we add two values, they will be equal to 0 and an error will
not be raised. If you read older Solidity code, you may encounter SafeMath library. And this library was
implementing overflow protection for earlier versions of Solidity, but now similar functionality is already
embedded in the language itself, so there is no more need to use this library in newer projects.

Mapping in Solidity
At the moment, our smart contract has one glaring issue. It doesn't track who has already voted. So it allows a
single account to vote as many times as they want. Now to fix this, we need to store who has already voted, and
to do this, we will use a data structure called mapping. Now in other languages, this data structure is called a
dictionary or hash map or hash table, depending on the language that you are familiar with. But regardless of
how it was named, it was the same concept. This data structure allows to store key value pairs and allows to
quickly find a value in this data structure by a key. In our smart contract, it can be a mapping of an address of a
voter to a Boolean where if the value is true it means that an address has already voted. To define the mapping
in Solidity, we need to use the mapping keyword and then in parentheses provide the type of a key, then this
arrow and then the value of a type and then the name of our mapping. So for example, the way we could define
mapping in our smart contract would look like this where we define mapping of address to Boolean, and the
name of our mapping will be hasVoted. Now what operations can we do with the mapping? Well, first of all, we
can store a value by a key. So in this case, the key is Adam, which is a string, and the value is 1, which is integer.
We can also get the value by a key. We can provide a key Adam, and it will return value 1 that we have stored.
What happens if we try to get a value for a non‑existing key? It will return a default value for the value type. So
for example, in this case, the value type is integer and the default value for integer in Solidity is 0. So if we try to
get a value for a non‑existing key, it will return 0. If a value type in the mapping is false, it will return false since
this is a default value for a Boolean type. Solidity defines default values for all types. For example, for an array, it
will be an empty array, and for a string, it will be an empty string. Solidity will also use default values to initialize
variables if we don't initialize them ourselves. Now one question that we need to figure out before we can go and
update our smart contract is how to get an address of a user that has sent a transaction to our smart contract.
Well, to do this, we can use the msg variable, and the msg variable provides information about a transaction that
was sent to our smart contract. So it contains fields like value, which is an amount of ether in wei that was sent to
our smart contract. The sender field, which is an address of a sender of a transaction, and this is the field that we
will use later. And data that contains complete transaction data in the byte format and an identifier of a smart
contract method that was called. The msg variable and its fields are available both in a constructor and in
regular methods.

Using Mappings
So now let's update our smart contract and allow only a single vote per Ethereum account, and we will use a
mapping data structure to track who has already voted. Now the smart contract is in the same state we have left
it in the previous demo. To make the changes, we will first of all need to add another field, and this will be
mapping (address => bool), and we will call it hasVoted. Now instead of recording votes in this function, what I'll
do, I'll first of all add a new function which is called recordVote. And it will receive the same option position as
our vote method, but it will update both the array of votes and the mapping hasVoted. It will write true for the
address of the sender who has sent a transaction to our smart contract. And now all I need to do is to call the
recordVote and provide the option position to it. We also need to add a check that the same account has not
voted already, and to do this, we'll use another require statement. And the condition here will be that the sender
of the transaction has not yet voted. To do this, I get the value from the hasVoted for the address of the sender,
and if it is true, then the require will fail. This will work for the users that have not voted because for an address
that has not voted, it will return a default value which is false, and this is why this require will not fail a
transaction. And I'll also provide an error message here. Okay. So now we can try to compile our smart contract
again, and we can deploy it with the same array of options as before. Let's click Deploy. Our smart contract has
been deployed, and now let's try to vote. If we vote once, everything seems to work fine. But if we vote another
time, this transaction fails because we enforce that the same account cannot vote multiple times. To test how
our smart contract works when multiple users with different addresses use it, we can scroll up here, and we can
specify which one of the test accounts to use. So to use another account, I need to click here, then scroll back
down, and click Vote. And in this case, this other test account will send a transaction. And because this account
has not voted before, this transaction will succeed. If I vote again though, it will fail, so just as we have expected.

Control Structure
In order to implement any nontrivial obligation, sooner or later, you will have to use control structures. And
Solidity provides two major control structures you can find in the majority of other programming languages.
These are if‑else and loops. So let's briefly look at if‑else statements. If you're familiar with other programming
languages, there won't be a lot of surprises for you. To use an if statement, we need to use the if keyword, then
provide the condition of the if block and the body of the if block. And the body will be conditionally executed if
this condition is executed to true. We can also chain multiple conditions using the else if statement. So the block
for the else if statement will be executed if this condition is executed to true and the previous condition was
executed to false. We can optionally also provide the else block that will be executed if all previous if statements
were not executed. One thing to keep in mind is that in Solidity, we can only use Boolean expressions in if
statements. So these expressions are valid in Solidity, but unlike other programming languages like JavaScript, in
Solidity, we cannot use the variables of other types in these expressions. So for example, we cannot use
numbers or strings or arrays in if statements. When working on smart contracts, sooner or later, you will have to
compare strings, and you would imagine that you can just use the = separator to do this. However, this is not
supported in Solidity. So a common pattern to work around this problem is to use hash functions. We can
compute the hash value of our strings we want to compare and then compare the hashes. And if you remember
our discussion about the hash functions, the reason why it works is because the hash function always produces
the same output for the same input. So if strings are the same, their hashes should be the same. Now let's talk
about loops. As in many languages, Solidity provides while loops. To use the while loop, we need to use the while
keyword, provide the condition, and the body of a loop. And this body will be executed as long as this condition
is evaluated to true. Solidity also has the do while loop where the first execution of the block is unconditional,
and then Solidity will execute the body of the loop for as long as this condition evaluates to true. Just as many
other C‑like languages, Solidity has a for loop, and it works exactly the same. It has three sections, all of which are
optional. The first one is to initialize our variables. The second one is to implement a condition for when the loop
should be executed, and the third block is to update variables in our loop. Solidity also supports break and
continue keywords to skip some or all iterations of loop. In this case, for example, if i = equal to true, Solidity will
execute the break statement and exit the loop completely. The continue statement, on the other hand, allows us
to skip a single loop iteration. So in this case, if i = true, Solidity will skip a single iteration and will, in this case, skip
the execution of the push function and will start the execution of the loop from the very beginning.

New Vote Method


In this demo, we'll implement a new vote method. But now, instead of receiving a position of an option to vote
for, it will receive a name of an option to vote for. And to implement it, we'll practice using control structures,
such as ifs and loops. So first, let's define our new method. First of all, I've defined a new vote method. Notice
that our old method and our new method, they have the same names. This is allowed in Solidity for as long as
they have different input parameter types. Now this method receives a name of an option instead of a position of
an option, so we'll have to search through the options that we've stored in our so smart contract state and find
the position of an option a user has voted for. Now, first of all, what we need to do is check if a user has already
voted or not. And to do this, we'll again use the hasVoted mapping, and we'll do it in the same way as we did
before. And now we need to find a position of an option a user has provided. So to do this, we'll write a for loop,
and we'll iterate through the option names. We will then get the name of each option. And then for every option
name, we need to check if this is the option that a user wants to vote for. And to do this, we'll implement a
separate function that compares the values of two strings, and we will implement it just a bit later. Now, if there is
a match, what we will do, we will record the vote. And to do this, we'll use the save function that we've defined
before, and then we'll return from the function, and it will exit the loop and the vote method without executing
any other statements. Now we also need to take care of the case when there is no option with the provided
name. And in this case, I just want to revert a transaction, and I'll use the revert function for this. Now the last
thing that is left to do is to implement the stringEqual method to compare two strings. And I'll do it as we've
discussed before, where instead of comparing strings, we'll calculate hashes of these strings and then compare
hashes instead. Notice that to call the hash functions, we first need to convert a string into a byte array using the
bytes function. Now let's try to compile our smart contract, and it seems like it was compiled successfully. Now
let's try to deploy it, and I'll provide the same list of options. Click Deploy. Our contract has been deployed
successfully, and now let's try to interact with it. As we can see, we now have two methods to vote for one of the
options, the old method that receives a position of an option and the new method that receives a string. So let's
try to vote for one of the options, and it seems like the vote has been recorded successfully. Let's get the list of
votes. And as we can see, the vote has been recorded, so our method works just as we have expected.

Structs
In the new implementation of the vote method, we use a loop to find a position of an option by its name. While it
works, it can be quite slow if we have a lot of options, and it can cost us quite a lot of gas because we might
need to check every single option in an array to find the position of an option a user is voting for. What we can
do instead is to use mappings because a mapping is a combination of key‑value pairs, and a key can be the
name of an option, and a value can be its position, and that would be much more efficient. So the way it could
work, we could add another field mapping from string to int. And in our vote method, we can first get a position
of an option by its name using mapping and then implement the rest of the method as before. However, there is
a gotcha with this. So, say if we define this mapping, and a user provides a name of the first option, then our
mapping will return 0. But what will happen if a user will provide a name of a non‑existing option? Our mapping
will also return 0 because 0 is a default value, and a mapping will return default values for non‑existent keys. To
work around this problem, we will use a common pattern that involves using structs, and this is what we're going
to learn next. So struct is a way to define a type where every instance has a collection of fields, and each
instance has the same fields. Structs work like classes, but without methods, so they only contain data. They can
also be nested, so a field and a struct can be another struct. And the other difference between structs and
classes is that structs have no inheritance in Solidity. To define a struct in Solidity, we need to use the following
syntax. First of all, we need to use the keyword struct, then the name of a new type, and in this case, it is User,
and then we can provide a list of fields in the struct. So, in this case, we have two fields, a string name, and an
integer age. To create an instance of a struct, we need to use the name of a struct in parentheses, either provide
just the values of the fields of struct, or we can use this key‑value syntax where we explicitly specify a name of
each field and the value of each field. With structs in Solidity, we can either get values of individual fields. Like in
this case, we get the value of the age field. Or we can set values of fields in a struct, like in this case where we set
a value to the age field. Now when it comes to memory in storage, structs work similarly to arrays. If we have an
array of users in a contract storage like this and if we assign one of these users to a struct in memory and make
any changes to it, this will modify a copy of struct. If we have ever assigned it to User in storage and make any
changes to this variable, this will modify original in the storage of the smart contract. Now, let's go back to our
predicament with default values and see how we can fix it using structs. To solve our problem, we can define a
mapping that looks like this, where the type of a key is still string, but the value is our own struct. And this struct
will contain two fields, a position of an option and the Boolean flag that signals if this option exists, and we'll
always assign it to true for all existing options. Now, how will this help us? If we get an existing option, it will return
a struct where position is assigned to 0, but exists is assigned to true, and this true flag will mean that this option
exists. However, if we try to get a position for a non‑existing option, it will return a struct where all its fields are set
to their default values. So we'll get false for the exists flag, and this is how we can figure out that this option does
not exist.

Using Structs
In the last demo of this course we will reimplement the new vote method, and we will use mappings and structs
to practice our new skills. To update our smart contract, first of all, I'll remove this old vote implementation
because we will not need this, and I'll temporarily add a TODO comment here because later we'll come back
here and reimplement this method. Now to use mappings to reimplement our smart contract we'll first need to
define a new struct, which I'll call OptionPos, and it will have two fields, a position of an option and a Boolean flag
that will signal if this option exists. Now we need to define a mapping just as we've discussed, and it will be a
mapping from string, or a name of an option, to our new struct, and I'll call this mapping posOfOption. But now
we need to initialize our mapping, and to do this, I will add the following for loop. Now in this for loop we first
iterate through the options that the user has provided to us when they deployed the smart contract. And then
for every option we will create an OptionPos struct, and we will initialize it with the current position of an option,
which is i, and exists equal to true. We will then store every OptionPos instance to our mapping, and the key will
be the name of an option, which is options[i], and the value will be our struct instance. Now, having this mapping,
we can go back to the new Vote method and reimplement it using it. And this implementation will heavily rely on
the functions that we have already implemented. First of all, we will check if a voter has already voted, and we
will use the hasVoted mapping to do that. Then we will get a position of an option using the posOfOption
mapping. But before recording the vote, we will check if this option exists, and to do this we will use the exists
flag on the optionPos instance. If this option exists, we will record the vote using the recordVote method that
tracks who has already voted and records a tally of total votes. Now, having this, let's go and compile our smart
contract. And it was compiled successfully, and that was Deploy our smart contract. And I again need to provide
a list of options to initialize it. Now it is deployed, so let's try to interact with it. And I'll provide a string option and
click vote. And as you can see, our transaction was successful. If we get a list of votes, it looks that our vote has
already been recorded. Now let's try to vote for a non‑existing option. And as you can see, this transaction has
been reverted because our smart contract has successfully determined that this option name is invalid.

Summary
I think we've covered quite a lot in this module. We've learned a lot of new Solidity features, and we've used
them to develop smart contracts. We've learned what data structures we can use in Solidity, we've learned
about arrays and mappings, we've learned about control structures, like if and loops, we've learned about
constructors and how we can use them to initialize our smart contracts, and we've also learned about how to
verify input parameters and the state of our smart contracts using assert, require, and revert functions. We've
also learned about the memory in smart contracts, and we've learned about the difference between the
memory, calldata, and storage. Now, up until now, we've only been using Remix IDE, but to become proficient
Solidity developers we need to learn how to use proper development tools. We need to learn how to build smart
contracts, how to test smart contracts, and how to deploy our smart contracts. And to do all of this, in the next
module, we will learn how to use web3 API, an API that allows us to interact with an Ethereum network.

Ethereum API
Introduction
Hi. This is Ivan Mushketyk with Pluralsight, and welcome to the next module of the course Ethereum API. In
previous modules, we were using Remix to develop and deploy smart contracts in Solidity. And while it was easy
to do, it mostly works for learning Solidity. And in this lesson, we will take a step forward, and we will learn about a
more advanced way of interacting with Ethereum. And specifically, we will learn Ethereum API. And this API, or
application programming interface, allows us to write applications that interact with Ethereum programmatically,
and this opens a ton of possibilities for what we can do with the network. In this module, we will have two goals.
First, we will see how we can programmatically deploy a contract using Ethereum API, and then we will learn how
to interact with the deployed smart contract programmatically, and we will practice doing this as well. And now,
without any further ado, let's get started.
Solidity Compiler
Before we can deploy our smart contract or interact with it, we first need to compile it, and this is exactly what
we are going to look into first. We'll first see how we can install a Solidity compiler, then we will learn about what
outputs it produces, and then we'll see how we can compile our smart contract in an upcoming demo. When we
run a Solidity compiler, it generates two outputs. First, it's the bytecode, and this is a set of executable
instructions in the Ethereum bytecode format, and we've covered it briefly in one of the previous modules. And
we will have to use bytecode to deploy our smart contracts, so we'll first have to compile it into bytecode and
then deploy it to the network. The second output is ABI, or application binary interface. In ABI is a file in JSON
format that provides information about what methods our contract has. It specifies the name of the available
methods, their signatures, output types, modifiers, etc. And ABI is used when we want to programmatically
interact with the deployed smart contracts so that various libraries know what methods are available on a
particular contract. To use a compiler on our machine, we first need to install it, and we can do this using the
npm command. We need to install the solc package that contains the compiler, and we also need to use the ‑g
flag to make sure that this compiler is available from any folder on our system. To run a compiler, we need to use
the solcjs command and notice that it is different from the name of the package that contains this compiler. We
then need to specify that we wanted to generate bytecode using the ‑‑bin flag. We then can specify that it
should generate ABI using the ‑‑abi flag. Then provide the paths where our smart contracts are located, and
then provide the name of a file that contains the smart contract that we want to compile. And we can either use
a CLI command to use this solcjs compiler or we can use it as a JavaScript library and interact with it
programmatically.

Using Solidity Compiler


Now, once we've learned more about Solidity compiler, it's time to see how we can use it in practice. So in this
demo, we will first install a Solidity compiler, and then we'll compile our voting smart contract that we've
implemented in the previous module. And after this, we'll inspect the compiler output, we'll look at the bytecode,
and API of our smart contract. First of all, I've created a folder that only contains a single file, which is the Voter
smart contract. Now, to compile it, we first need to install the Solidity compiler, and we will use the npm
command for this and then specify that I want to install it globally using the ‑g flag. And now, once it is installed,
we can run the Solidity compiler to compile our smart contract. And to do this, I will use the solcjs command,
specify that I want to get the bytecode of a smart contract, and that I want to get an abi, or application binary
interface. I'll also specify that all smart contracts that we will compile are in the current directory, and I'll specify
the name of the file that we want to compile. Now, if I execute this command, the Solidity will compile our smart
contract, and let's look at the output. So as you can see it has created two files and they have the same name,
they're called the Voter_sol_Voter. And what it means is that the first part represents the name of the file that
contained the smart contract it compiled, and the second part is the name of a smart contract in this file for
which it generated the API and the bytecode. And this naming convention is useful because a single file can
contain more than one smart contract. So, let's first look at the bytecode of our smart contract. And to do this,
we will you the less command. And this is the bytecode. It's just a hexadecimal string encoding the bytecode of
the smart contract, and it is not readable because it is not for humans, and it is specifically for execution by the
Ethereum virtual machine. And now let's look at the second output of the compiler, which is the API. And to look
at this file, I'll first of all output this content, and then I'll send it to the jq command. And jq is a utility command to
work with JSON files, and it can do a lot of things, but we'll use it here specifically just to format the JSON file
that is produced by the compiler. And this is a JSON array where every object in this array contains the
information about a single function in our smart contract. If I scroll up, we will see that the first object in this array
describes the constructor function of our smart contract, and it describes input parameters of our constructor,
which is a single array of strings. If we look at the second object, it describes the other function in our smart
contract, which is getOptions. It doesn't have any inputs, but it has a single output, which is an array of strings.
And it also specifies that this is a view function. So, now once we have the bytecode of our smart contract in the
API, we can now look into how we can deploy and interact with our smart contract programmatically.

Ethereum Client
Now, once we've compiled our smart contract, let's see how we can interact with an Ethereum network
programmatically. And to do this, we first need to use an Ethereum client. An Ethereum client is just a running
Ethereum software. Another term that we will use a lot in this course is Ethereum node, and it is simply a
computer running an Ethereum client. And in this lesson, we will learn how we can work with an Ethereum client,
we will also learn about the APIs that Ethereum clients provide, and later we'll see how we can interact with an
Ethereum network programmatically using any Ethereum client. Now let's look at the role of a client in any
Ethereum network. As we mentioned, an Ethereum client is just a running Ethereum software, and each client
stores the Ethereum transaction's history, the blocks that were generated, and it also might store private keys
that the owner of this client can use to sign transactions. A client also provides a web3 API that users can use to
interact with the network. Ethereum network is just a set of interconnected Ethereum clients that are
communicating with each other. And network users can use Ethereum clients to interact with an Ethereum
network using the web3 API. And the name client might be a bit confusing. You might think that if there is a
client, there should be a server that this client interacts with, and there's no specific server in this case. An
Ethereum network is just a network of interconnected equal clients. Depending on the configuration in which
Ethereum software runs on a node, we can identify three different types of Ethereum nodes. The first one is
called a full node, and a full node stores the full blockchain data, and they also verify all blocks that are
generated on the network. So, they propagate correct blocks, and they reject invalid blocks that violate
Ethereum rules. And users can use full nodes to get the current state of the network. For example, they can call
a method on a smart contract using a full node. A second type of a node is called a light node, and they don't
download full blocks; instead, they only download block headers, which contain just a fraction of information of a
full block. They also don't verify blocks, and instead they completely rely on the full node to do this. There is also
another type of node called an archive node. And the way it is different from a full node is that it stores the full
historical data of the network, including very old blocks, and an archive node can be used to process requests
about the historical state of the network. Now, to run your only Ethereum node, you need to run two separate
types of clients. The first one is called an execution client. An execution client listens to new transactions, it
executes transactions, and it stores the network state. And before the major Ethereum update, called The
Merge, it used to be that you only had to run an execution client, but now you also need to run a consensus
client that interacts with the execution client. The consensus client implements what is known as a
Proof‑of‑Stake algorithm, and we will learn about what it does in the next module, but in a nutshell it allows an
Ethereum network to agree on the global network state. These two clients also interact with other
corresponding clients on other nodes via the peer‑to‑peer protocol. When a user wants to access these clients
and use their API, the user usually uses a web3 library in a corresponding programming language, and this library
will connect to both of these clients and use their APIs. Now with Ethereum, there is no single client
implementation. For execution client, the most popular option is Geth, implemented in Go, but there are also
other implementations like Besu, implemented in Java, and so on. The same story with consensus clients. The
most popular client, as of today, is called Prysm, and it is implemented in Go, but there are also other
implementations like Lighthouse, implemented in Rust, and so on. While these clients have different
implementation, they all implement the Ethereum specification that defines how execution and consensus
clients should operate. And having multiple clients is called clients diversity, and it is important because if there
was only one client and this one client had a particular error, this error could be exploited by attackers, and they
could potentially bring down the whole network. Having more clients will make the network more robust against
attacks and errors. So if you want to run your serial node, try to pick up not the most popular clients to promote
the clients diversity.

Web3 API
Now once we've covered what are Ethereum clients and how they work, let's look into what we can do with
them, and namely, what functionality Ethereum API provides. So this API allows us to do quite a lot of things. For
example, we could get a state of a node, check if it is connected to other nodes, etc. Using Ethereum API, we
can also get the state of a network. For example, we can look at the balance of a particular account, we can call a
method on a smart contract, etc. And note that the data will be returned as a particular client sees it. So if it is
still downloading blocks from other peers or if it has been disconnected, it will return stale data. We can also
send transactions using an Ethereum client. So, for example, we can deploy a smart contract, we can send
payments, etc. And Ethereum clients can also store private keys, and when we want to send a transaction, we
have two options. Either we can sign a transaction and send a signed transaction to a client, or we can send an
unsigned transaction to a client and ask it to sign it using a private key that it stores. To interact with the client
and use its functionality, we need to use its API, which is called JSON remote procedure call, or RPC API. And
this API is structured as a number of functions that we can call remotely by sending an input in a JSON format.
So let's go through several of many methods that any Ethereum client provides. The first one is clientVersion,
that simply allows us to get a version of a client that we interact with. The second method is called peerCount,
and it allows us to get a number of peer nodes that our node is connected to. Other methods are
getBlockByHash and getBlockedByNumber, and these methods allow us to get data about a particular block,
either by number or by its hash. And the last method that we will cover is called sendTransaction, and this
method allows us to send a transaction to the Ethereum network to deploy a smart contract, send a payment,
etc. And there are many other methods, and you can read Ethereum documentation to get a full list of methods
in its API. Now let's look at how we can send a JSON‑RPC request to a client if we want to do it manually. As an
input to an RPC request, we need to provide a JSON object that has several fields. The first one is a version of
the API. The second is a method that we want to call, and, in this case, we'll call getBlockByNumber method.
Then we need to provide parameters for the method call, and the list of parameters depends on what method
we want to call. For the BlockByNumber, we need to provide a number of a block we want to get and the flag
that specifies if we want a full transaction object or just its hash. And the last parameter is an id, and this is used
by a caller to match a request with a reply. A reply will also contain an id, and a client will be able to find out
which request this reply is for. And a reply will also contain an id, and the caller will be able to figure out which
request this reply is for. Now let's look at the response data. The first field is an id that we've just talked about,
the second one is a jsonrpc version, and the third one is result, and the result will depend on what methods we
have called. So, in this case, because we try to get information about the block, the result will contain data of a
block that we have requested.

Geth Client
Now let's briefly talk about how we can use one of the most popular Ethereum clients called Geth. The exact
instructions for how to install Geth depends on what operation system you're using. If you're using macOS, you
would need to first unload a repository that contains Geth using brew, and then you would need to use the brew
install to install Geth. If you use Ubuntu, you would need to use apt‑get to install Geth. And for Windows, you
would need to download binaries or build Geth from the source code. Regardless of how you install it, you then
need to run Geth client. And to do this, you need to use the geth command and provide a few parameters. If you
want to use Geth with Goerli network, you would need to use the ‑‑goerli flag. And if we use it, our client will
connect to go Goerli. If you want to use the JSON RPC API, we would also need to provide the ‑‑http flag that
will enable the HTTP‑RPC server on Geth. We can also specify in what mode we want to run our Geth client. If
we set ‑‑syncmode flag to a light, Geth will run as a light node. And if you recall, we've discussed earlier that it
means that our node will rely on other nodes to validate blocks. But we can also run it as a full node. But, in this
case, it will take longer for Geth to download all the blocks, and it will require more resources, more network
bandwidth, more disk space, more CPU, etc. And the final important flag in Geth is the ‑‑http.api. Geth
functionality is separated into different APIs, and here we can specify what APIs will be available over HTTP. So
this is necessary to restrict what outside users can do with our client and would allow to get some extra security.
And if we run this command, it will start Geth on port 8545, and we can also configure this port. And once we
have Geth up and running, we can use a library to connect to Geth and interact with the Ethereum network
programmatically. And we will see how to do this in just a few minutes, but there are also a few more ways to
interact with Geth. One way is to use the Geth CLI command, and we can use one of its subcommands to
interact with it. For example, if we use geth accounts, it will allow us to manage Ethereum accounts on the Geth
client. If we run geth init, it will create a new genesis block and it is needed if you want to start your own
Ethereum network, for example, your own test network. We can use geth help to display help. And we can also
use geth attach to connect to interactive JavaScript session running on Geth client. And these are not all of the
commands supported by Geth. If you want to get a full list, you can go to the Geth documentation. Now, if
you've used geth attach command, you can use its JavaScript console, and we can use one of the following
objects in this console to interact with Geth. For example, the admin object allows us to control the client node.
Personal object allows us to manage Ethereum accounts on this node. Txpool object provides information about
transactions that can be executed on the node. And the last one is debug, that you are unlikely to use often, and
this object allows us to debug Geth itself. And here's an example of how we can use this JavaScript console. We
can use the attach command, and once we execute it, we can use some of these JavaScript objects to interact
with Geth, like admin peers to get information about peer nodes Geth is connected to, or we can look at this
transaction pool that contains transactions that are not yet executed that are also called pending transactions.
And using the status field of this object, we can look at the status of the Geth transaction pool. In this module,
we are not going to run in Ethereum node. Instead, to focus on learning Web3API, we will use one of the
Ethereum node providers. And a node provider is a service that runs an Ethereum node for us, so we don't need
to install it or manage the node ourselves. And we can even use some of them for free if we don't send a lot of
transactions, like in the demos of this course. There are a few providers to choose from. One is Infura, which we
will use in this course. And this is one of the most well‑known providers, and it is also used by MetaMask. So
when we use Metamask, it is using Infura to interact with an Ethereum network. But there are also other
providers like Alchemy. And if you recall, we use their website to get the Ether. And there are also many other
providers. If we use one of these services, they will give us a URL that we can use to send requests to. And once
we have a URL from one of these services, we can just use it as a URL of our own Ethereum node. And there is
no difference from a developer perspective if this URL is pointing to a locally running client or to a client that is
operated by a node provider.

Promises in JavaScript
In the upcoming demos, we will write a lot of asynchronous code, and asynchronous means that when we
perform an operation we start a long running task, and our code will be notified when it is finished or receives an
error. And this will include things like sending transactions to an Ethereum network, calling methods, etc. And to
write this asynchronous code, we will use modern JavaScript idioms that on the one hand are easier to read and
write, but also requires you to know them. And in this clip, we will briefly learn these idioms. And if you're already
proficient with JavaScript, then feel free to skip this particular clip. We won't be covering anything related to a
Ethereum here. We will cover two main concepts, promises and async/await. So if you are familiar with these, feel
free to skip this next clip, and if you're not familiar or unsure, I would encourage you to keep watching. So, let's
start with a simple example of an asynchronous operation, and we will talk about the hypothetical method that
would look like methods that you can find in older JavaScript libraries. So let's say that we have a hypothetical
method that can send an HTTP GET request, and this method has three parameters, a URL to which we want to
send the request, the onSuccessFunc, which is a function that will be called by the get method if a request
succeeds, and the onFailureFunc that will be called if this request fails. And these functions that are called when
an operation is finished, they are are also called callback functions. And here is an example of how we'd use this
function. To call this function we would first specify a URL where we want to send this request, then define a
function that will be called if a request succeeds, and this function receives the only parameter, which is a result
of an HTTP request, and then also define a function that will be called if a request fails, and this function receives
a single parameter, which is an error that has occurred. And then we can pass these functions to the get call.
Now, this would work, but if we want to send another request if we receive a response from the first request,
we'll then need to define another onSuccess function and another onFailure function. And this can quickly get
out of hand. We would get these nasty nested callbacks, and the situation sometimes is referred to as a callback
hell. Now, fortunately in modern JavaScript, we have a better way to work with asynchronous code, that is called
promises. And if our hypothetical library would be implemented with promises, we'd have the following interface.
It would now accept a single parameter, which is a URL, where to send the request, and when we call it, it would
return a promise object. And to get the result data from this promise object, we would need to call the then
function on it and provide a callback function that will be called if this request succeeds. We would also need to
provide another callback using the catch function that will be called if this request fails. Now, once we've seen
an example of a promise, let's talk about the characteristics. A promise represents an asynchronous operation. If
you have a promise, it may not have a result yet, but it will notify when it has it. There is no way to get a result
from a promise directly. To get the result from a promise we need to use the then method that receives a
callback that will be called if the operation succeeds, and the catch method receives a callback that will be
called if an asynchronous operation fails. And the benefit of using promises is that with promises we can perform
multiple requests in the row and link them together. So for example, if after the first request I want to send
another one, then in the then callback we can just return another promise for the operation that sends the
second request. And then we can again call the then method that will receive the result of the second request
and so on. And in addition to this chain of operations, we can also provide a catch callback that will be called if
any of these operations in this chain fail. But in modern JavaScript there is even a better way to work with
asynchronous code, called async/await. If a function returns a promise, instead of using the then method to
handle a result we can use the await keyword, which will allow us to sort of extract the result from promise, and
then we can use the result value to send another request and so on. So using these await keywords, we can
write code that works with asynchronous operations as if we are writing a normal known asynchronous code.
And behind the scenes JavaScript will transform this code into using promises. So, all of this is just a very nice
syntax sugar. And the best part of this is that it even works with regular try catch blocks. So if any of these
asynchronous operations throws an exception, then the catch block will be executed to process it. One thing to
note is that this only works in functions that have a special async keyword in their definition. And if we call this
function anywhere else, this function will return a promise, and to handle this promise we can either use another
async await or we can use then catch methods.

web3.js
To use web3 API we need to use one of the existing web3 API libraries that are available for various
programming languages. In this course, since we are going to use JavaScript, we will use the web3.js library, but
there are also libraries like web3j for Java, web3.py for Python, or Nethereum for the .NET platform. To use the
web3 library, we first need to import it in our JavaScript code and then create an instance of web3 type. After
this, we need to specify how to connect to an Ethereum client. And to do this, we first need to create an
instance of a web3 provider, which specifies how to connect to a particular client, and then set it to web3 using
the setProvider method. And in this case we use the HttpProvider that will connect to an Ethereum client using
the HTTP protocol, and we will use the following URL. Once we have a web3 instance configured, we then can
use it to access an existing smart contract. And to do this, we first of all need to get an abi of a contract we want
to interact with. Once we have it, we need to provide a contractAddress. And then having those, we can create
an instance of a contract type from the web3 library and provide an abi and the contractAddress. When we want
to send a transaction using the contract instance, it will return a promise that we can then use to receive a result
of our transaction. Behind the scenes, the web3 library will send the request to an Ethereum client, and then this
Ethereum client will send a transaction to an Ethereum network. Once this transaction is executed, our promise
will be updated, and it will either call the then or the catch callbacks. So here's how we can send a transaction
using web3.js. So once we have our contract instance we then need to specify what method to use. And to do
this we need to use the methods field and then specify the name of the method we want to call and provide
arguments that we want to pass in a transaction to this method. And this by itself won't send a transaction to
Ethereum, we need also to call the send method on it that will then interact with an Ethereum client to send a
transaction to the network. And send will return an instance of a promise, so we need to use the send method to
get the result of our transaction. And if the transaction succeeds, web3.js will provide an instance of a received
object that contains information about an executed transaction. Now, as with any other JavaScript code, we can
also use async await when a method returns a promise. So, instead of using then, we can use the await keyword
to extract and receive from a send method result. Now let's go through a few more scenarios of how we can
interact with a smart contract using web3.js. If we have an overloaded method, which is when we have two or
more methods with the same name but different parameters, then we'd need to use a slightly different way of
calling it. We need to first of all get a method by providing its signature, like this, and then provide arguments
that we need to pass to this method call. And then again we need to use send to send a transaction and then to
be notified when it is executed. We can also deploy a smart contract using web3.js. To do this we first of all need
to create an instance of a Contract type, provide an abi of our smart contract, and then we need to call the
deploy method, and we need to provide the bytecode of the smart contract that we want to deploy. And then
this, again, won't send a transaction to deploy a smart contract. We, again, need to use the send method to send
a transaction to an Ethereum network. And as a result of this call, we will get an instance of a smart contract from
the web3.js library that we can then you to interact with it or, for example, to get its address. And we can also use
web3.js not just to send transactions, but we can also use the call mechanism to call a method. And using call
will look almost exactly the same, but instead of using the send method to send a transaction, we will call the call
method instead. And in this course, we won't cover all of the features of web3.js, but if you want to learn more
about this library, I'll suggest to go to the official documentation on this website.

Creating an Infura Project


In this and the following demos, we will see how we can deploy our smart contract and interact with it
programmatically. But before we can do this, we'll first need to create an Infura project that will allow us to use
Infura as Ethereum client. And the second thing that we would need to do is to export our MetaMask account so
we could use it in our application programmatically, and I will explain to you how to do this just a bit later. And as
a result of these two steps, we will create a configuration file that we will use in the following demo where we will
deploy our smart contract. First, to create a new Infura project, we need to go to the infura.io website where all
you need to do is to create an account, and I have already done so. And it is free to use if we send a small
amount of requests every day. So to create a new project, or a key as it is now called an Infura, we need to click
on the CREATE NEW KEY button. And then we need to select a network , which is Web3 API. And we need to
give it a name, which I'll call Pluralsight Ethereum, and I'll click CREATE. And with just this single step, we now
have a URL that we can use to interact with Ethereum using Infura. And as you recall in this course, we're not
using Mainnet, and we're using Gorli network, so before we can use this URL, we need to click here and select
Gorli. This is a URL that we can use to send RPC requests, and Infura will use these RPC requests to interact with
the Gorli test network. So let's copy this URL, and we now need to save it for the upcoming demo. So what I'll do,
I'll go to the ID, and I'll create a new file. And I'll call it .evn, and .env is a common configuration file in JavaScript
projects where we can store environment variables and that we can easily read then from JavaScript code. And
I'll create a new environment variable with our URL that I'll call INFURA_URL. Okay, so with this, we are almost
ready to start using Infura, but we're not done yet. And the problem is that Infura doesn't have a private key of
our MetaMask account. So in our application, we'd have to sign a transaction locally on our machines and then
send a signed transaction to Infura, and Infura will then send it to the network. The only problem is that we first
of all need to get this private key from MetaMask. And to do this, we'll need to go to MetaMask first, then click on
these three dots, then Account details, and then click on the Export private key. We need to enter the password,
and this is a private key for this account. And as this warning says, we should not disclose this key because
whoever has the access to this private key will have access to our account. Now let's copy this private key so we
can use it later in our application to sign transactions. And if we use this private key from anywhere else, we will
have access to the same account and the same ether balance that we can control from this MetaMask wallet.
And to use it, what I'll do, I'll go back to this .env file, and I'll create another variable that I'll call
ACCOUNT_PRIVATE_KEY. And I'll prepend it to 0x because this is what we'll have to do later, and then I'll paste
this private key. And as you can imagine, storing your private key in a text file might not be a good idea from the
security standpoint. So if you're working with a real private key, you need to use a more robust solution like using
a key management system, but it is okay for this demo. So, all right, now we have this configuration. We have to
INFURA_URL. We have the private key for our account, and now we can see how we can deploy our smart
contract programmatically.

Deploying a Smart Contract


In this demo, we will write a JavaScript application that deploys our smart contract, and we will do this using the
web3.js library that we were talking about in this module. And at the end of this demo, we will see how we can
deploy our smart contract using the script through Infura. I have already created a starter project for our
JavaScript application and have added a package.json file that describes this project and lists dependencies of
this project. The first dependency is the dotenv library, which will read the .env file that we've created in the
previous demo. And the second dependency is the web3 library that will allow us to interact with the Ethereum
network. So to get started, I will create a new file called deploy.js, and this is the file that will contain the logic for
deploying our smart contract. And the first thing that I need to do is to import all the dependencies. The first one
is the fs package that will allow us to read files from the file system. We'll use it to read the ABI and the bytecode
of our smart contract. The second one is the Web3 library. And in the next line we also add the dotenv
dependency and use the config method to read all the variables defined in the .env file. And it knows that it
should read the .env file since this is the convention in JavaScript projects. Now having this, we first have to read
the bytecode of our smart contract, and we do this using the readFileSync function, and we also need to read
the ABI of our smart contract. And notice that in both cases this will return a utf8 string, but to use ABI later we
need to convert it into JSON. And to create a JSON object from a string, we introduce the JSON.parse method.
Now we need to create an instance of web3 and set a provider. And we will use the HttpProvider, as we've
discussed before, but as a URL for this provider we will use the INFURA_URL, which we've already defined in the
env file in the previous demo. Now we're almost ready to deploy our smart contract, but one thing that we still
need to do, we need to add the private key of our account to web3. And to do this we'll use the following
construct. We'll use the privateKeyToAccount method and provide the private key of our account. This will
create an account instance that we'll then need to add to wallet of the web3 library. And then we'll use this
account later to sign the outgoing transactions from our script. And now we can start writing code to deploy our
smart contract. So here we first specify parameters for the transaction that will deploy our smart contract. We
specify the bytecode of our smart contract using the data key, and we specify the arguments for the constructor
of our smart contract. In here we just list a list of options for which the users of our smart contract will be able to
vote for. And now once we configured our transaction we can send it to the network. And here we need to
specify two parameters, the address that we will use to sign the transaction that will be sent to Infura and the
maximum amount of gas we want to spend while sending this transaction. And now, this will start an
asynchronous operation of deploying the smart contract. And we can also subscribe to the events from web3 to
get notified when this transaction either succeeds or if it fails. And to do this, we first of all can use the then
function that will be called when a contract is deployed, the catch function that will be called if a transaction
fails, but we can also subscribe to events from web3, such as a transactionHash that will be called when we get a
hash of a transaction on the network, and the confirmation, and a confirmation is an event when either a network
generates a block with our transaction or if a network generates a block after the block with our transaction.
Okay, so this is the whole implementation, and the only thing that remains to do is to run the script. And now to
run the script, we first of all need to install the JavaScript dependencies, and we can do this using the npm
install command, which will download the only two packages that our project depends on. And now we can run
our script. And to do this we will use that node command that will start Node.js and specify the JavaScript file to
run, which is deploy.js. And, as you can see, we first of all get a hash of our transaction, and if you wait for a few
more seconds, we get the block number where the transaction was included, and we got a hash of a block that
included our transaction. Now, if we copy the contract address, and if we go to Etherscan, we first of all will be
able to see our block, which is right here, and we can also search for our smart contract address. And if we click
here, we will see information about our deployed smart contract. We will see the block number, we will see the
transaction hash that we've seen, we can see the transaction fee that we've paid, and other additional
information. So, now we have our smart contract deployed on the Goerli network. And what we will do now, we
will implement another script that will programmatically interact with our smart contract.

Interacting with a Smart Contract


Now once we have a deployed smart contract, we will write another script that programmatically interacts with
it. And just as in the previous demo, we will use Infura service to interact with the Ethereum network. I've made a
small change to the .env file. I've added another variable, CONTRACT_ADDRESS, that contains the address of
the smart contract that we've deployed in the previous demo. And now we'll write a new script that will interact
with this contract. It will cast a single vote, and then it will get the results of the voting. And I will name the script
contract‑interaction, and a significant portion of the script will be very similar to what we wrote in the previous
demo. So first, we need to import dependencies and read the .env configuration. Then, we need to read the abi
of our smart contract, and we need to parse this abi to a JSON object. And notice that since we are going to
interact with the deployed smart contract, we don't need to read the pipe code of it because it is already
deployed to an Ethereum network. Then, we need to create a web3 instance and configure it to use the
INFURA_URL. Then, we also need to add our private key to web3, as we did before. And then the new thing that
we need to do is we need to create a CONTRACT_INSTANCE from the web3 library that we'll used to interact
with the deployed smart contract. And to create a Contract instance, we need to provide two parameters, the
abi of our smart contract and an address where it is deployed. Now I'll create a separate function that will
interact with our smart contract, and I'll make it an async function so we'll be able to use the await keyword when
we are sending lots of requests. The first thing that we will do, we will send a transaction, but to do this, we need
to specify the amount of gas that we're willing to spend. And to estimate the amount of gas we'll need to use,
we'll use another web3 function called estimateGas. And to use it, we need to provide what account is sending a
transaction, the address of a contract where we will send it, and we need to specify what method are we going
to call. And we specify that we will call the vote method that receives a position of an option we're voting for, and
then we specify the parameters that we are going to pass to the method that we're going to call. And we use the
encodeABI to convert it to a format that estimateGas expects. EstimateGas will return a number that contains
the amount of gas we will spend if we execute this transaction. And now having this amount of gas, we can send
a transaction to Ethereum network. First, we specify what method to call, and, again, we specify that we are
going to call the vote method that receives an integer parameter. And then we specify that we want to vote for
the first option. And then to send this transaction, we're using the send method. And we specify that we want to
send this transaction from this account, and this is the amount of gas were willing to spend. Also notice that
since send and estimateGas return promises, we use await keyword to wait until these operations finish and then
get the results. And now after we have voted, we can get the current votes from our smart contract. And to do
this, we will use the getVotes method. We don't need to provide a signature because there is no overloaded
version of getVotes. There is only one method with this name. And then we specify that we don't need to send a
transaction and that we can use the call mechanism to do this. And now this is a full implementation of the
sendTransaction function. And the last thing that we need to do is to call it. And because this is an async
function, it returns promise. So to get the results from it, we need to call the then method to be notified when
the function succeeds and the catch method to be notified if it fails. All right, so this is the full implementation
that will allow us to send a transaction to our smart contract and get the results of the voting. And to execute it,
we need to go back to the terminal and run node command, but now specify a different script. And if we run it,
first of all, you will see that the web3 has estimated that we need to spend this amount of gas, and then we need
to wait for a few seconds until this transaction is executed because we're waiting until our transaction is
included in one of the blocks. And once voting is done, we will get the number of votes. And as you can see, the
number of votes contain one vote for the first option and 0 votes for the second option, just as we expected.
And notice that getting the results of the voting took almost no time, and this is because we were using the call
mechanism instead of the sendTransaction to get the result of the voting.

Account Nonce
Now we will talk about an advanced topic related to using the web3 API, and specifically we will talk about an
account nonce. And an account nonce is just a unique ID of a transaction from a particular Ethereum account.
For the first transaction a nonce is set to 0, for the second it is set to 1, and so on. And the point of the nonce is
that it prevents a double spend. It prevents another user from resending your transaction so it can be executed
twice. And this is because if we want to send a new transaction, we need to send a new nonce, the next number,
and we would have to sign this new transaction, and only the owner of a private key can do this. And an account
nonce can be a confusing topic. It can be a source of many issues if used incorrectly, and it was handled for us
by the Ethereum software so far, so we didn't have to deal with it, but it might become an issue once you start
working with more complex applications. And the way it works is an Ethereum network stores the next expected
nonce for every Ethereum account, and when it receives a new transaction it looks at the nonce of these
transactions, and it decides what to do with it using the following algorithm. So it looks at the nonce, and the
nonce of a transaction is what it expects, then this transaction is executed. If it is higher than expected, then the
network will wait until it gets a transaction with the expected nonce. And then if it is lower than expected, one of
two things can happen. First of all, if a transaction with this nonce is still pending, then the new transaction can
replace the pending transaction, but only if it has a higher gas price. And if a transaction with this nonce has
already been executed, then the network will return an error. And here is an example of what can happen if we
skip a nonce value. So if we have a new account, we first create a transaction with nonce 0, and it is executed. If
we then send a transaction with nonce 1, it is executed as well. But if we skip a nonce in the next transaction and
set it to 3 instead of 2, then this transaction will be pending until the network processes a transaction with nonce
2. Now, using Ethereum API we can manually set the nonce, and we can also get an expected nonce from the
network. To get the expected nonce we need to use the getTransactionCount method and specify the address
of an account for which we want to get the nonce. And then we can also specify the nonce when we send a
transaction. Now, so far it seems that managing a nonce in Ethereum should be pretty straightforward, but it
might become quite complicated. First, the getTransactionCount method may return an outdated nonce value.
And if you have multiple machines sending transactions to the Ethereum network, if they use
getTransactionCount, it might return the same values for multiple callers. So, a solution for this problem is to
keep track of a nonce per account in your local database and ensure that every time we send a transaction a
nonce in the database is incremented so that every generated transaction will have a unique nonce.

Summary
In this module, we've covered a lot of information. First of all, we've learned how we can use an Ethereum
compiler and we've learned that a compiler produces two types of outputs, first a bytecode of a smart contract
and an API that contains information about the methods that the contract has. We've also learned about what is
an Ethereum client, and an Ethereum client is just an Ethereum software running on any Ethereum node. A
client stores transactions history of a network and it also might have private keys that can be used to sign
transactions. Ethereum clients also provide web3 API that users can use to interact with the network. We also
learned about what methods are provided by a web3 API and we've learned that we can use it to get
information about the network, send transactions to it, deploy contracts, etc. And we also saw how we can use a
web3.js library to use this API. We've also learned about the concept of an account nonce, and an account
nonce is a special mechanism that allows to protect from a malicious user that might try to resend the same
transaction twice. And while nonce has been managed for us by the Ethereum software in this course, we've
covered that it might become a source of problems if we set it incorrectly.

Blocks and Fees


Introduction
Hi, this is Ivan Mushketyk with Pluralsight, and welcome to the next module of this course, Blocks and Fees. In
this short module, we will take a break from learning practical skills and we will focus on the theory of how
Ethereum works under the hood. We will first lift the veil on how blocks in Ethereum are generated and why it
usually takes some time to generate a new block, and what are the reasons behind this. We will then talk about
algorithms that Ethereum uses to create new blocks. One is the current algorithm called proof‑of‑stake, and the
second one is the previous algorithm called proof‑of‑work that is still used in some blockchains. We will also
cover how fees work on Ethereum, how the gas prices are calculated, and where do these network fees go when
we pay them.

Forks
Before we talk about how blocks are generated in Ethereum, we need to talk about another concept called
forks. So far, when we were discussing blockchain, we were always drawing a single chain of blocks, but what
could happen is that different users can temporarily disagree what is the current state of the network and can
start building parallel chains, assuming that what they have is the most recent network state, and those different
chains are called forks. So forks are temporary disagreements between peers, and if a fork occurs, different users
can see different, and even contradictory states, and this is all caused by the decentralized nature of Ethereum.
Because there is no centralized master, every actor needs to make decisions on what is the current state on
their own. But eventually those forks should be resolved by the Ethereum protocol. Eventually we should have
an agreement between peers what is the current state of the network. Just to simplify things a little bit, the way
a protocol decides what is the current chain is by selecting the longest chain of blocks, and then users,
assuming that the longest chain is the current chain, they start generating new blocks on top of the current
chain. So why is this all important? Because this can cause a so‑called double spend attack. And here is how it
might work. Let's say you want to buy pizza with Ethereum. So you've paid for your pizza, you got your pizza, you
ate it, and then you decide to trick everyone and generate a longest chain, which surprisingly does not include a
transaction where you've sent the payment, and from a merchant's perspective who sold you this pizza, the
payment was reversed. They saw it on one network state and then with your longest chain it has disappeared.
Now in the current history your payment is reversed and now you can spend your Ether again and get another
free pizza. So here is a more visual way of representing this. First you send a new transaction, and a new block is
generated that contains your payment. And then you generate a bunch of new blocks, and because this is now a
longer chain, this becomes the current state of the network. And your new chain is almost the same as the old
one with the only difference that your payment is missing there, so you still own your Ether in the new chain.
Now Ethereum would be pretty useless, however, if this trick was easy to do. If anyone could add blocks at any
time they wanted, the network would not be secure. So the way to solve this problem is that we need to have a
leader that could generate new blocks. But we can't just select one permanent leader since this would ruin the
decentralization benefits of Ethereum. So the way it works is the network gives a chance to anyone to become a
leader and generate a new block. And there are two different algorithms that make this happen, and we've
already mentioned both of them. The first one is proof‑of‑work, and in proof‑of‑work to generate a new block, a
node would need to solve a complex mathematical puzzle, and to solve this puzzle we'll need to use a lot of
computational resources. The more resources someone has, the more chance this user has to generate a new
block. Proof‑of‑work is still used by some other blockchains like Bitcoin, but Ethereum now uses proof‑of‑stake,
and with proof‑of‑stake to become a leader, the user needs to put some Ether at stake, and if they try to cheat,
this Ether is then confiscated. With the proof‑of‑stake, the more Ether someone stakes, the higher the
probability that they will be able to generate a new block.

Proof of Work
Now let's talk about how a proof‑of‑work algorithm works. While Ethereum doesn't use proof‑of‑work anymore,
I've decided to include this video for two reasons. First of all, it is used by other blockchains, and second, it is
interesting to compare how proof‑of‑stake differs from proof‑of‑work. On every node that is trying to generate
blocks, there is a pool of incoming Ethereum transactions. Periodically, some of these transactions will be
selected to be included in the next block, which is called a candidate block, and this candidate block will include
transactions from the pool, a hash of the previous block, and a timestamp of a block generation. And then, when
a block is created, a participant will calculate a hash value of this block. If it is less than a special network
parameter called difficulty, that we will denote as D, then the next block is generated, and it will be sent to the
network. If however, a hash is greater than the difficulty, then the miner repeats the process and tries to create a
new block with the hash value that is less than D. And to do this, a miner has another parameter in the block
called nonce. And by changing this nonce a miner can try to create a block with the expected hash value. And
this is exactly a mathematical puzzle that miners are trying to solve. So the way it works, miners start with a block
with nonce equal to 0, and if a hash is greater than the difficulty, a miner tries another nonce. And since even a
tiny change completely changes the hash value, they increment the nonce and compare it with the difficulty
again. And this goes on and on until eventually they find a nonce which generates a block with the expected
hash or some other node generates another block, in which case the process starts all over again. And this
process is called mining. A node tries different nonces until one of them gives the required hash. It might be
confusing though when we say nonce because there are two types of nonces in Ethereum. One is a transaction
level nonce, and this is a nonce that we've discussed before. This is just a number of transactions sent from a
specific account. What we are talking about here is a block nonce that miners use to change a hash of a block.
With proof‑of‑work. once a block is generated, a miner sends this block to other peers. These peers validate if a
puzzle was solved. And it is very easy to validate because all they need to do is to compute a hash of a block and
compare it to its difficulty. And calculating a hash value is very fast. If the block is correct, they store it locally in
their storage and send it to other peers. If it is incorrect, they just reject it right away. And once we have a new
block the next blocks will be built on top of this newly mined block. Ethereum mining is a randomized process.
Any node, just by pure luck, can generate a block that has a required hash, but the probability of this is
extremely small. So to increase chances in proof‑of‑work to generate a correct block, a user might get more
machines that will calculate hashes of different versions of the same block in parallel, or they can buy better,
more expensive, more powerful equipment. In the case of Ethereum, the mining was done with powerful graphic
cards. In the case of Bitcoin, for example, it is done with specialized hardware that is only designed to calculate
hashes. And usually mining is not done by individuals, it's individuals and their mining pools that are using
collective resources to generate blocks. Now, difficulty in the network is not a fixed parameter, and it was
automatically adjusted. If more users try to mine blocks, they would find a new block faster just because they
use more resources, but Ethereum network was calibrating the difficulty to make it easier or harder to ensure
that new blocks are generated roughly every 15 seconds. But why would users go through all of this? Why
would they buy expensive hardware and spend electricity? This is because whoever generates a new block will,
first of all, get a fixed amount of Ether for a mined block, and second of all, they will get a portion of fees from all
executed transactions. And we will cover how fees work later in this module. Now one thing to note is that with
proof‑of‑work, a miner can still reverse a transaction. All they need to do is just generate a longer chain than the
existing chain. They would need to pick a block in the past and start mining blocks by themselves to generate
their own chain, and other users would switch automatically to their longer chain. However, to do this they had
to get more than half of all mining resources used by all the Ethereum users, and this is why it was called a 51%
attack. But since there were a lot of people mining Ethereum, an attack like this would have been extremely
expensive.

Proof of Stake
While proof‑of‑work was used for many years, and it is still used by some other blockchains, it has a few glaring
issues. First of all, it requires a lot of energy. Proof‑of‑work through Ethereum was consuming roughly the same
amount of energy that is used by the whole country of Kazakhstan, and this computation had a carbon footprint
of Sweden. This is a lot of used energy. And the second issue was the possibility that someone could perform a
51% attack. As we've discussed before, it can be performed by someone who has more than 50% of all total
mining resources of the network. While it is very expensive to collect that amount of equipment. The worst thing
is that if this happens, the attacker could repeat this again and again and again, because they retain equipment
and can perform an attack again. Now to put this into perspective, a single Ethereum transaction was consuming
500 kW of energy, which is the same amount of energy that is needed to perform 266,000 Visa transactions. To
solve this, Ethereum developers for a very long time were working on an alternative consensus algorithm called
proof‑of‑stake. In this algorithm, users can become block validators. Each validator can be selected to propose a
new block or vote on new blocks. There is no mining anymore, no computational puzzles to solve, and no need
for miners. To become a validator, a user needs to stake some amount of Ether, which they can't use in the
meantime, and if they misbehave, this stake will be taken from them. But why would anyone become a validator
in the first place? Well, again, because, just as with miners, a network rewards the validators. Just as with
proof‑of‑work, a validator gets a part of transaction fees and they get a block reward, but with proof‑of‑stake it is
smaller than a block reward for proof‑of‑work. To become a validator, a user can either become an individual
validator, to do this, they would need to stake at least 32 Ether, or they can join a staking pool where users can
combine their Ether to create a bigger stake and then share rewards among themselves. The more Ether
somebody stakes, the higher the chance that they will be selected to validate a new block and get a reward.
Now, Ethereum has migrated from proof‑of‑work to proof‑of‑stake in 2022 after a long migration process.
Ethereum started with proof‑of‑work in 2015, and it is a much more battle‑tested algorithm than proof‑of‑stake.
Then in 2020, Ethereum developers created a so‑called Beacon Chain that was running in parallel to the
Ethereum Mainnet, and in 2022, Ethereum switched to the new Beacon Chain that is using the proof‑of‑stake
algorithm. And this is not the end of the major Ethereum updates, and we can expect more changes coming
later. And all these changes are sometimes branded under the name Ethereum 2.0. It includes the proof‑of‑stake
algorithm that we've just discussed, but it also includes future changes, such as rollups, that will allow to move
some transaction execution from the chain, and sharding, that will allow to split a single network into multiple
chains working in parallel.

Block Limitations Revised


One thing that we have not covered yet are the limitations that Ethereum puts on the blocks. When a new block
is generated, there is a chance that not all pending transactions will be included in a new block. And this is
because Ethereum sets a limit on the total amount of gas spent by all transactions in a block. At the moment, this
limit is 30 million gas, which means that all transactions included in a block should not spend more than 30
million gas. This limit has been increased multiple times, but it still restricts the total number of instructions all
transactions in a block can execute, which in turn restricts how many transactions a miner can include in a new
block. And this limit is defined by Ethereum architecture. Ethereum designers wanted to make sure that the
block can propagate and be validated by all participants across the world by the time the next block is
generated. So, formerly miners, and now validators, can decide what transactions to include in each block. They
also can decide in what order to execute transactions. Let's imagine that we've added a new method in our
smart contract that allows to stop the voting, and if it is called, no further votes are allowed. And let's also
assume that we have a transaction pool that looks like this, where we have two transactions that are casting
votes and another transaction that is calling the Finish method. Now, one validator could decide that they want
to first execute two votes and then the finish method, and another validator could decide that they might want
to first execute one vote, then finish, and then try to execute another vote method. And what will happen is that
in the first case with the first validator, both votes will be included, while in the second case only one vote will be
included, then the votes will be finished, and the second vote will be rejected.
Fees Revised
Now once we've learned about how new blocks are created in Ethereum, it is time to discuss fees, how they're
calculated and what happens with them. And we'll first start with an older fees model, which is similar to how
Bitcoin fees still work, and then we will look into the current fees model. The old fee model worked like an
auction. Each user independently decided on the gas price they were willing to pay in their transaction, and
they were submitting their transactions with this price. How would users decide how much would they want to
pay for a single unit of gas? Well, they could look at the recent gas prices in previous transactions and decide
what they were willing to pay. The problem with that was that the gas price could change any minute and it
could change drastically. So if a user selected a gas price that was too high, it would guarantee that their
transaction would be included since miners would prioritize transactions with higher gas prices, but they would
also overpay for their transactions. If, however, users selected a gas price that was too low, a transaction could
remain stuck unexecuted for a very long time. So to sum up, the auction model has three main issues. Users
could wait for transaction execution for a very long time, using Ethereum had a poor user experience, and it was
very easy to overpay. To solve this problem Ethereum developers came up with a new proposal called EIP‑1559,
and EIP stands for Ethereum Improvement Proposal. All EIPs are technical suggestions for how to improve
Ethereum, and this particular EIP defined the way for how to fix fees on Ethereum. This EIP defined three main
changes. First, it would increase the maximum amount of gas all transactions could spend in one block. Second,
it would define an automatic way for a network to set a gas price depending on how much demand for
transaction execution there is at the moment. And third, it defined a new fee structure that split a single fee
value into two different components. Now this is how the gas price automation currently works. If in the previous
block, the total gas used by all transactions was less than 50% of the maximum block size, then the gas price
would decrease by 12.5%. On the contrary, if the total used gas was more than 50% of the maximum, the gas
price would increase by 12.5%. So with this model, if the network is overloaded, the gas price would
automatically be increased, and it would be decreased if the usage drops. The total fee in Ethereum that a user
pays now has two components, the base fee that is set automatically using the algorithm that we've just
discussed, and a tip selected by a user that can be used to incentivize miners to execute a transaction faster.
The tip is received by a miner or a validator in proof of stake, but the base fee is burned, it is not received by a
miner, this Ether just ceases to exist. From a user perspective, the adoption of EIP‑1559 had two main benefits.
First, the fees are now predictable and they cannot change rapidly from one minute to another, and second, this
EIP reduced the time it took to execute transactions, and our users don't need to wait for too long, as was the
previous model.

Summary
In this module, we've looked under the hood of how Ethereum works. And we first of all started with forks, which
are disagreements in the current network state. We discussed issues with forks, as well as some catastrophic
consequences if we allowed anyone to create new blocks at any time. To allow an Ethereum network to agree on
a single stage, Ethereum uses a consensus algorithm. Previously, Ethereum was using an algorithm called proof
of work. In this algorithm, to generate a new block, a minor had to solve a complex mathematical puzzle. This
algorithm has a few downsides. For example, it requires a lot of energy and a lot of specialized hardware. The
new algorithm used by Ethereum is called proof of stake. And to generate blocks with proof of stake, a user
needs to stake some ether that can be confiscated if users try to cheat. And the benefits of this algorithm is that
it is much more energy efficient, and it doesn't require any specialized hardware. We've also discussed how fees
work in Ethereum, and we've discussed that in the current model, the fee consists of the base fee and a tip. The
base fee is calculated automatically based on the network usage, while the tip is selected by a user. The base
fee is burned on every transaction, while the tip is collected by a validator.

Truffle Framework
Introduction
Hi. This is Ivan Mushketyk with Pluralsight, and welcome to the next module of this course, Truffle Framework. So
far in this course, we were using Web3 GS to deploy our smart contract and interact with an Ethereum network.
And while this is a powerful tool to automate operations with the network, it is quite a lot of work to use it. It is
just too low level. What we need to become really productive, we need a proper development environment that
will allow us to implement and abstract contract development and deployment. And this is exactly what we will
learn in this module. We will learn Truffle framework, which is, as of today, the most popular development
environment for Ethereum. And we'll create a project for the voting smart contract using Truffle framework. Now
let's talk about what skills are we going to learn in this module. First of all, we will learn how to create a
development environment to work on smart contracts. We'll see how we can deploy smart contracts using
Truffle framework. We will write unit tests for our contract, and we'll learn how we can test our smart contracts.
We'll see how we can run a local test Ethereum blockchain that we'll use to test our smart contract. And we will
learn how we can debug smart contracts using Truffle. Now, without any further delay, let's get started.

Getting Started with Truffle


While we could continue using web3.js to test and deploy our smart contract, it is just too much work, and we
need a better tool. What we actually need is to create a development environment for our smart contracts, and
the tool we will we use for it is somewhat similar to Maven or Gradle, if you're familiar with Java, or npm if you're
familiar with JavaScript. And the tool that we are going to use in this course is called Truffle. It is built specifically
for Ethereum, and it is implemented to help with a full smart contract lifecycle including compilation, testing,
deployment, etc. This tool is written in JavaScript, and it can be configured using JavaScript. Now, as of now,
Truffle framework is the most popular tool for creating development environment for smart contracts. But what
exactly Truffle can do for us? First of all, it allows to compile smart contracts so there is no need to run or install.
So see, we can run just a simple Truffle command and it will compile all smart contracts in our project. It allows us
to run automated tests, so if we make any changes to our smart contracts, we can rerun these tests to
automatically verify that we did not break anything. Truffle framework also allows us to create a test environment,
so instead of deploying a smart contract to a real network to test it, Truffle framework allows us to deploy a smart
contract to a test environment and test in in this environment. Truffle also allows us to deploy a smart contract,
and it makes it much easier than using web3.js. It also provides package management that will allow us to use
third‑party packages written by other developers in our project. And last, but not the least, it allows us to debug
our smart contracts. It comes with a debugger that allows us to debug any transaction that happened on
Ethereum. Now let's see how we can install Truffle. To do this, we just need to run a single command, npm install,
specify the name of a package that we want to install, which is truffle, and keep in mind that we need to use the
‑g flag, which means that this package will be installed globally. And truffle command will be available from any

directory in our system. To execute Truffle, we need to run truffle and specify what truffle command we want to
execute. Now let's look at the main commands we can use with Truffle. First of all, it's truffle init, which creates an
empty project that we can use to start working on our smart contract. We can also download a pre‑existing
demo project using the unbox command, and you can download it to see how it is implemented, how tests are
written, etc. A good project to start is called metacoin, which is an example of a Truffle project that implements a
simple cryptocurrency on top of Ethereum. If you run truffle compile, it will compile all smart contracts in the
project, and if you want to run a test Ethereum environment, you can run the truffle develop command. To run all
unit tests, we can use the truffle test command. And once our smart contract is ready, we can run the truffle
migrate to deploy our smart contract. Now, all truffle projects should be organized using a certain folder
structure, and here is how it looks. The first folder is called contracts, and this is where we should put source
code for our smart contracts. The next folder is called migration, and it contains migration scripts, or we could
also call them deployment scripts. These scripts define the logic for how to deploy your smart contracts to an
Ethereum network. The next folder is called test, and it contains all unit tests for smart contracts in this project.
And these tests can be implemented either using JavaScript or Solidity. And at the root folder there should be a
configuration file for the project, and it should either be named truffle.js, or it can have an alternative name
called truffle‑config.js.
Contracts Migration
Now, once we've covered the basics of Truffle, let's look at how we can simplify the deployment of our smart
contracts. And the process of deploying smart contracts in Truffle is called a migration, and it works quite
similarly to data migration in the database world. As with database migration, we need to break down the
deployment of our smart contract into several steps, and each one of these steps can deploy a smart contract
or multiple contracts, or it can interact with them. And just as with state base migrations, each step is executed
only once. Now, to keep track of the current state of a migration, Truffle deploys a separate smart contract that
stores the number of the last executed step. Now let's look at an example of a migration step. First of all, in a
migration step we need to import an object for our smart contract that we want to deploy, and to do this, we
need to use the artifacts.require function and specify the name of the file with our smart contract. Then we need
to define a function that will implement a migration step, and we need to export it, and to export it, we need to
assign it to the module.exports field. Now this function that we define accepts a parameter called deployer. This
is an object that we can use to deploy a smart contract, and to deploy the smart contract, we need to use the
deploy method on the deployer, provide the smart contract we want to deploy, and optionally, we can provide
arguments that we want to pass to the constructor of our smart contract. And since this is an asynchronous
operation, we need to use the await keyword to wait until the deployment is finished. To interact with a deployed
smart contract, we first of all need to get an instance of the deployed smart contract using that deployed
method, and then we can call methods on our smart contract. And notice that the way we call methods on the
smart contract in Truffle is much more compact than the one we're used to with web3.js. And this is because
Truffle contains a truffle‑contract API, a more high‑level API to interact with smart contracts. If you recall, to use
web3 you would have to get the methods object, then provide the arguments for this method, and then call the
send method to actually send a transaction. Now with truffle‑contract, all we need to do is to call a method on a
contract object, provide arguments, and we can also provide additional parameters, such as what account to
use. Now when we know how a single migration step looks like a truffle, let's look at a bigger picture. In a
migration folder, we need to provide a list of steps for our migration, and the name of each file should contain a
number and a name of a migration step. Now, the name is just for human readability, and number in front of the
name is used to order migration steps. If we run truffle‑migrate, it will execute each step only once, and it will
execute them in the order of numbers at the beginning of the name of each file. Now, if after this we run truffle
migrate again, then Truffle will do nothing because it has already executed both migration steps. Now, if we want
to make additional changes, first of all, we need to create a new migration step, and if we run truffle migrate after
this, it will only execute the new migration step.

Multiple Networks
It is very likely that a single Truffle project will have to work with multiple Ethereum networks throughout its
lifecycle. Eventually, it can be deployed to the main network where Ethereum users could use it, but it could also
be deployed to a test network like Goerli for testing. Or it also can be deployed on a test environment which just
emulates an Ethereum network. Now to connect to different networks, we need to specify configuration
parameters like hostname and port of an Ethereum client that we need to use for each network. And this is
exactly what we can define in the truffle‑config.js file. So let's see how we can do this. Truffle js or truffle‑config.js
files contain an object that represents a Truffle configuration for a particular project. And in this object, there is a
network object property that defines configuration for different networks. Now, if we want to specify
configuration for a particular network, in this networks object, we need to create a new field. And in this field, we
can specify parameters for how to connect to an Ethereum client that has access to this network. So for
example, we can specify a hostname of an Ethereum client. We can specify a port that we should use to connect
to this client. Next, we need to specify an ID of an network that we want to connect to. And network ID is a new
concept for us that we did not discuss before. Every network on Ethereum has a network ID. For example, the
main network has an ID of 1, and we can also specify an address of an account that we should use to deploy
contracts to this network. Once we have multiple networks, we can specify what network we want to deploy a
smart contract to. If we run truffle migrate without any additional arguments, by default, it will deploy to the
network that's named development, but we can also change it and deploy a smart contract to a different
network. And to specify what network we want to deploy our smart contract to, we need to use the network
argument and specify the name of the network. And by the way, this name is the same name as the name of the
field in the truffle configuration file. When we are writing code for smart contracts migration, we can also
implement network‑specific large in migration steps. To do this, we can use the second parameter to the
migration function that is called network, and this parameter contains the name of a network where this
migration step is deploying our smart contract. Talking about migrations, we can also restart a migration. What it
does, it ignores the current state of the smart contract and allows us to go through the deployment steps from
scratch. And to do this, we need to run truffle migrate with the reset flag. If we want to reset a deployment for a
particular network, we can again provide the network name using the network argument.

Test Environments
So far in this course, when we wanted to test our smart contracts, we were either using Remix with its embedded
test environment or we were using Goerli, an Ethereum test network. But none of these methods were very
convenient, especially with the Goerli network, where we had to have an account with Ether, deploy our smart
contracts, wait, etc. But with existing Truffle tools, it is easy to create a test environment for Ethereum. This test
environment will be just a single process running on our machine and it will implement the same web3 API as the
regular Ethereum client implements. And these test environments are very convenient. They will emulate a
whole network with multiple accounts and fake Ether. Now when it comes to selecting a test environment, there
are two main options. The first one is Truffle Develop, which is bundled with Truffle, and the second one is
Ganache, which is a separate application that we'll have to install separately. Now both of them have the same
purpose. They emulate an Ethereum network and they allow us to test our web3 code or our smart contracts.
Now, the biggest difference is that Truffle Develop is a CLI‑only tool, while Ganache supports both CLI and UI.
And in this course, we will be using Ganache. We will deploy our smart contracts to Ganache, and we will
interact with Ganache instead of interacting with a test network. Now if you want to use Truffle development
environment, we need to run truffle development command and it will start an interactive console for the Truffle
development environment. If you want to use Ganache instead, you will have to download it and install it, and we
will do it in just the next demo.

Running Ganache
In this demo, we will install and start a testing environment using Ganache, and then we will explore its UI, and in
the next demo, we will use Ganache to test our smart contract. To install Ganache, you need to go to this
website, trufflesuite.com/ganache and click on the Download button. And here, I can download Ganache for
macOS because this is the OS that I'm using, but you will see a download button for your operating system. So
now I've downloaded Ganache, and I can install it as a regular application. And now, once I have Ganache
installed, I can start it. Once Ganache is started, it asks me to create a workspace, and a workspace is like a
project that we'll work with at Ganache. It has two options, a quickstart, so just to start a test blockchain on
Ganache, or it has an option to create a new workspace, and this allows us to link a Ganache workspace with a
Truffle project. Since we don't have a Truffle project just yet, I will just go with a quickstart option. And just as a
note, Ganache supports both Corda and Ethereum block chains, but we will use Ethereum. Now, this is how the
Ganache interface looks like, and here we have 10 test accounts, and each one of them has 100 E's. And we're
going to use these test accounts when we interact with our test network. We also have some additional
information here about our test network. So first of all we have the current block number, which is 0 because no
new blocks have been mined, we have a gas price and a gas limit per block, and we have a network ID, and we've
discussed that every Ethereum network has an ID, and this test Ethereum network has this ID, 5777. We also
have a URL that we would need to provide to web3.js if we want a web3.js code to connect to this test network.
And down below, we have a mnemonic for the private key for this account, and we've seen this already before
when we were creating an account with MetaMask, and this is the same concept, this is just a way for Ganache
to show the private key for this account. Now, another interesting field in this interface is called HD Pass, and we
did not discuss this before, but just to give you a very quick overview, this field defines how to create multiple
accounts from a single private key. And, this goes beyond the scope of this course, but the idea is that we can
back up just a single private key, and then from this private key we can create multiple Ethereum accounts. And,
if you want to know more, I will suggest to google for BIP 32 and BIP 44, and BIP stands for Bitcoin Improvement
Proposal, and this proposal has been implemented for both Ethereum and Bitcoin. Now let's explore the rest of
the interface of Ganache. First of all, we have a list of blocks that have been mined in Ganache and we only have
the first block with number 0, which is our genesis block. We also have a list of transactions that have been
executed with Ganache, and as we can see, at the moment we have no transactions. We also have a list of
contracts, and if we deploy any contracts to this test network, we'll see here all the contracts that have been
deployed. But, what we would need to do is to link a Truffle project with this Ganache workspace, and we will see
how we can do this in just the next demo. The next up here is events, and we have not covered this in this
course yet, but, just to give you a brief overview, events is a mechanism that allows us to store additional
information about a transaction execution, and we will see how we can use them in one of the next modules.
And the last step is called logs, and it just contains debug logs for Ganache that we can use to troubleshoot
Ganache. Okay, now when we had an overview of the Ganache interface, let's see how we can use it to test our
smart contract.

Creating Truffle Project


Now, once we have Ganache installed, we can deploy our smart contract to it. And in this demo, we will first
create a Truffle project, then we will configure this project to deploy our smart contract to Ganache, and then
we will see how we can interact with our contract in Ganache. First of all, I've removed all unnecessary files in our
project, and I only have our Voter contract. So now let's try to create a Truffle project for it. I already have Truffle
installed, so if I just type truffle, it gives me a list of commands I can use with Truffle. To create a Truffle project, I
will run the truffle init command. And it has created a folder structure for our project, so let's take a look. So as
you can see, it has created the contracts folder for our contracts, the migrations folder for migration steps, the
test folder, which is empty and it is for tests, and the truffle‑config.js for configuring our project. First of all, we
need to move our contract to the contracts folder. And as you can see, this folder already has another smart
contract. This is a smart contract that Truffle will use to store the state of migrations in our project. Migrations
folder already contains the first migration step, which is called initial_migration, and this step just deploys the
migrations contract that we just saw. Now to deploy our smart contract using Truffle, we need to add another
deployment step, and it needs to start with number 2 since it should be executed after the initial migration. And
I'll call it deploy_voter. And the implementation of the step will be quite straightforward. What we'll do, we will first
import our Voter smart contract, and then we will use deployer.deploy to deploy this Voter smart contract with
just two options that a user can vote for. We are now almost ready to deploy our smart contract, but we need to
configure how to connect to our Ganache instance. And to do this, we need to go to the truffle‑config.js file,
scroll down, go to the networks object, and provide configuration for ganache. The host and the port number
here configure Truffle to connect to Ganache and I've copied these values right from the Ganache UI. And the
network_id, we'll just specify it as *, which means that this can be any network. But before deploying our smart
contract, I just want to create a new workspace in Ganache, and the reason for this is I want Ganache to know
about the smart contracts that we're going to deploy. I'll just use the default workspace name, and I'll click ADD
PROJECT, and I'll select the truffle‑config file for our project. And with this, I can click SAVE WORKSPACE, and I'll
have the exact same UI. Everything is the same except this Ganache workspace knows about our Truffle project.
So now we can deploy our smart contract. We have a migration step. We have a configuration for Truffle to use
Ganache, and we have a Ganache workspace that knows about our project. And the only thing that I need to do
is to run truffle migrate ‑‑network ganache. And there were no errors. So first of all, it has deployed the
Migrations smart contract, and it has deployed our Voter smart contract. And if you look at the Ganache UI, if we
look at the contracts, we will see the addresses of the deployed smart contracts. And if we look at the
transactions, we can see that there were four transactions. First of all, Truffle has deployed the migrations smart
contract. Then it has interacted with the migration smart contract to record the current status of the migration.
Then it deployed our smart contract, and then it updated the current status of the migration to specify that it
has executed the second migration step. Now we can interact with our smart contract, and we have two options
for how to do this. First of all, we can run a web3.js script so it would connect to Ganache instance and will
interact with it as with a real network. The other option is to run Truffle console, and Truffle console allows us to
connect to a network defined in the truffle‑config and interact programmatically with smart contracts on a
particular network. So we will connect to the Ganache network, and now we can programmatically interact with
our contract. First, we need to get its instance. And to get an instance of the deployed smart contract, we should
use the deployed function, just as we would do in the migration step. And this function will return an object that
allows us to call methods on our smart contract deployed on Ganache. And then we can call getVotes to get a
list of votes from this smart contract, and we can get the first vote. This will return an object instead of a
JavaScript number. So we first need to convert it into a number using the toNumber method. And as you can
expect, there were no votes for the first option because our contract has been just deployed. Okay? So as you
can see with Truffle and with Ganache, we can deploy our smart contract. We can interact with our smart
contract, and this is much easier compared to using web3.js.

Unit Tests for Smart Contracts


So far, in this course, we were testing our smart contracts manually, but now it is time to learn how we can write
automated tests for our smart contracts, and Truffle allows us to test smart contracts without deploying them to
a test network. Now, we can run these tests as many times as we want, and we can do this without spending any
real or test Ether. And we can write those tests either in Solidity or in JavaScript, and while both have their pros
and cons, we'll first look into how to write these tests in JavaScript. Now, let's look at an example of a simple test.
To write a test that interacts with a smart contract, we first of all need to import our smart contract using the
artifacts.require function, and then we need to define a group of tests using a function called contract. And we
need to provide a name for this group of tests, which we will call Voter, and then we need to provide a function
that will itself define individual tests. Now, notice that this function accepts an accounts parameter which
contains a list of test accounts that we can use in this test. Now, to define a single test, we need to use the it
function, provide the name of the test, and then provide a function that will implement the test itself. In this test
function, we can first of all deploy our smart contract, and the smart contract won't be deployed to any real
network or test network, instead it will be deployed in the test environment of these unit tests that is isolated
from everything else that we have set up. And when we deploy a smart contract, we can provide arguments to
the smart contract constructor, and then once we have a smart contract deployed, we can then interact with
the smart contract, we can call methods on it, we can send transactions to it. The most important goal when
writing tests is to verify that the smart contract that we are working with is in the right state; it is in the state that
we expect it to be after every interaction. So, for example, we might need to check that the vote that a user has
casted is actually recorded. And now with Truffle, we will use the Chai library, and this library provides a number
of functions that we can use to implement checks in tests. It provides several styles that can be used to
implement those checks, and in this course specifically, we will use the expect style, and we will see how it works
in just a second. Here is a simple example of how we can use the Chai library to test the state of our smart
contract. Let's say somewhere in our test we have an integer variable and we want to ensure that this variable is
equal to 2. Here is what we need to do. We need to call the expect function and pass the value that we want to
validate, which is num in this case. And then to check that it is equal to 2, we need to call this .to.equal method
and provide the value that we expect. If a variable is equal to 2 and we want to ensure it is equal to 2, then
nothing will happen, so this statement will just do nothing. If, however, our variable is not equal to what we
expect it to be, then Chai library will throw an exception and this will fail this test. Now, one gotcha that you need
to be aware of is how to compare numbers in Truffle test. If we call a method on a smart contract and this
method returns a number, you would expect that you can just call the expect .to.equal and compare it to a
JavaScript number, but it just won't work. And this is because a number returned by a smart contract actually
has a type of BigNumber, which is a special type that can store large numbers, and so we can't compare it this
way with a regular JavaScript number. Now, to work around this, there are two possible options. First of all, we
can convert our expected value into a BigNumber using the toBigNumber function, and to compare
BigNumbers we need to use .to.deep.equal because in this case we are comparing objects, and this comparison
will compare all fields of both objects. Or alternatively, we can use toString or toNumber methods on the
BigNumber, which will convert it to a string or a number, respectively, and then we can compare it to expected
values. In this course, we will barely scratch the surface of what you can do with the Chai library, but you can
explore more of what this library can do on their official website, chaijs.com. Once we start writing our tests, we
will notice that our tests repeat more or less the same pattern with every test. First of all, we need to create a
smart contract, then we need to interact with it, and then we need to verify its state. Now, it would be nice if we
can avoid the duplication of creating a smart contract, and we can do just that using the beforeEach method
that allows us to implement a common initialization logic for all tests. And here's how it works. To define a
common initialization logic, we need to call the beforeEach function, and as a parameter, provide a function to it
that will be called before an execution of each test. In this function, we can, for example, create an instance of
our smart contract and assign it to a variable that will be available to all our tests. Now when we write a particular
test, we can use that created smart contract and we provide more tests. Then this beforeEach block will be
executed before each one of them and each test will have a clean slate. They will get a new contract instance in
a default state that they can interact with.

Writing Unit Tests


Now, once we've covered the theory of how to write unit tests for our smart contract, let's go ahead and write
our first unit test in JavaScript. And once we have our unit tests, we'll see how we can execute them using
Truffle. To add a new test, we need to go to the test folder and add a new file, and I will call it voter.test.js, and it
doesn't really matter how I call this file. Now first of all, let me add some boilerplate code, and we have already
discussed most of it. So first of all, we need to import our smart contract using the artifacts.require, specify the
name of our smart contract, and then we need to define a group of tests using the contract function. We provide
a name for our group of tests, and we also provide a helper function that we'll use later. And this helper function,
it takes an array of big numbers that will be returned by our smart contract, and it converts it into an array of
JavaScript numbers. And to do this, it uses the map function that converts every single big number individually
by calling the toNumber on each object. The first thing that we need to do in our test is to create a smart
contract that we're going to test. And to do this, we will use the beforeEach function that will create a new
instance of the voter smart contract before each test execution, and it will pass this array of options to our smart
contract. Basically it will provide two options for which we can vote in our tests. Now let's implement the first
test, and in this test we will check that when the smart contract is created, there are no votes recorded. First of
all, we will get the number of votes for each option using the getVotes method, and since this is an
asynchronous operation, we need to use await to wait until we get the votes. And once we get the votes, we first
convert them to JavaScript numbers and then we specify that we expect that we have 0 votes for option one
and 0 votes for option two, okay? So, now we have our first test and let's see how we can run it. And, to run our
tests, what we need to do is to run truffle test, that's it. And it has executed our only test, which was named has
no votes by default, and this green checkmark here means that the test was executed successfully and its
checks were passed. Now let's see what happens if our expectation doesn't match what the smart contract
returns. Let's say that maybe by default we expect that the first option should always have one vote, and this is
clearly not what our smart contract returns by default. So, let's run our test again and see what happens. And as
you can see, now Truffle returned an error, and what it says here is that we expected that an array with two 0s
does not equal an array with 1 and 0. So this is basically how you would know that there is a problem with a
particular test. So now let's fix it back and implement a few more tests. Let's try to vote for a particular option
using its string name, and this test is a bit more involved, but what we do, we first of all get an address of the first
account in the list of test accounts and we store it into this variable, and then we cast a vote using the method
that accepts a name of an option. And because in our smart contract we have two methods that have the same
name basically because we use function overloading, we need to use the slightly weird way of calling this
method in Truffle. We need to get the methods field, pass the name of our methods and the types that it
accepts, and then we need to provide arguments for it, and optionally, specify from which account do you want
to perform this transaction, and we only need to do this if we call an overloaded function. If we call a function in
the smart contract that has a unique name, we can use a normal way of calling it, like this one, and once this is
done, we can just get the list of votes as before, and as you can see, we expect that a vote for option one will be
recorded. Now let's try to run this test, and now we have two tests executed and both of them were executed
successfully. Okay, now let's add the last test that we will define in this demo, and we will check that we can vote
using the position of an option, and this test will be almost exactly the same as the previous one. We get an
address of the firstAccount, we vote using the vote method that accepts an integer, we specify that we vote for
the first option, and then we get the votes, and we again expect that there will be a vote cast for the first option.
Notice that the votes cast in this test does not affect the second test, because for every test we create a new
instance or a smart contract, and these tests are independent. Now let's run our test again, and as you can see,
all our tests are passing, just as we expected.

Errors Checking
So far, we were only writing tests that we're sending valid arguments to our smart contract, and we never had
the case when calling a method would result in an error. But in this demo, we will add additional unit tests that
cover the error cases of our smart contract. First, let's see what happens if we get an error from our smart
contract. And to trigger an error, all we need to do is to try to vote twice from the same account. Because if you
recall, our smart contract only allows one vote from one account. Now let's try to run our tests and see what will
happen. As you would expect, the test execution has failed. And we got this error that there was a VM Exception
while processing transaction, and we have an error message, which is Already Voted. And notice that this is the
same error message that we return in this line if the same account tries to vote twice. So our contract has the
right behavior, but how do we write a test for it? And to test this, we'll have to change our test in the following
way. First of all, we'll have to wrap our test in try catch block because if a smart contract reverts a transaction
execution, Truffle contract API will throw an exception. And we catch this exception, and we check that the error
message is the same error message we return in our smart contract which has already voted. Now the last thing
that we need to do is we need to check that exception was actually thrown. And to do this, we called the
expect.fail method that if executed will fail the test right away. And this is exactly what we want. If we manage to
get to this line, it means that our smart contracts have not reverted a transaction, which means that we have a
bug, and this test should fail. Now let's try to run our tests again. And as you can see now, all of our tests are
passing. Just for completeness, we will add another test on this module that will check if two different accounts
can cast two votes. And this test will look almost exactly like the one we had before with the only difference that
now we get two addresses. And we sent the first transaction from the first address and the second transaction
from the second address. And we expect that both votes will be recorded. Let's run our test again. And now we
have all five tests passing just as we expected.

Unit Tests in Solidity


So far in this course, we wrote all our tests in Truffle using JavaScript, but we can also write tests in Solidity, and I
think it has a few advantages. First of all, we don't need to use async/await, so it makes our code a bit cleaner,
and because of this, transactions and calls are a bit easier to read. Now, there are a few disadvantages. We can
only use a single account when we are interacting with a smart contract, and second, we cannot use a plethora
of JavaScript libraries that are available if we write our tests in JavaScript. Here's an example of how a unit test in
Solidity looks like. We'd first need to import the contract that we want to test, and we need to import a library
with assertions. These assertions are similar to the child library that we're using so far, but they are implemented
in Solidity instead of JavaScript. We then need to define a contract, and its name should start with Test to signify
that Truffle should run this contract as a test. Then we need to define a test itself, and the name of the test
should also start with a string test, again, to specify to Truffle that this function implements a test. And then in
the body of this function, we can then implement our single unit test. We can create a smart contract, we can
interact with it, for example, get a number of votes, and then we can use asserts to compare the state of a smart
contract with what we have expected.

Debugging with Truffle


So far in this course, we did not have to use a debugger to debug our Solidity code. But, once the smart
contracts become complex enough, you would need to use a debugger to troubleshoot a transaction or a
method call. In addition to all its other features, Truffle provides a debugger that allows to debug past
transactions. Now, it can run against any network, and it can run for past transactions. One option that we have is
to use a CLI debugger, we can run it using the truffle debug command, specify the name of the network, and the
transaction hash we want to debug. Now, this will start a CLI process, and it looks like this, it shows the current
line where the debugger has stopped, and it prompts us to provide a command to control the debugger
behavior. And, in this CLI debugger, we can control it using commands like o to step over to the next line, or b to
tackle a breakpoint to set a point in the code that debugger will automatically stop at, or h to display help to get
the list of all commands we can execute. Now, CLI is not the only available option, Truffle also has a Visual Studio
Code plugin that allows us to run debugger from Visual Studio Code, and it has exactly the same idea, but it has
a graphical user interface that makes debugger way more easier to use.

Summary
In this module, we've learned Truffle, an important tool for smart contract development. We saw that we can use
it to implement a comprehensive development environment. With Truffle, we can build our smart contracts, we
can test our smart contracts, and when they're ready, we can deploy our smart contracts to a test or to a real
Ethereum network, and we can also debug our smart contracts using either Truffle CLI debugger or using Visual
Studio Code plugin. To use Truffle, we need to organize our project using a certain structure. We need to put all
our smart contracts into the contracts folder. Migration scripts should go to the migration directory. All of our
tests should go into the test folder, and these tests can be either in Solidity or in JavaScript, and we can
configure our project using a JavaScript configuration file, which we can call either truffle.js or truffle‑config.js.
Truffle deploys smart contracts using migration steps implemented in JavaScript, and each migration step is
executed only once. And to make any changes, we need to add another migration script and then run truffle
migrate again. Now this concludes this module on Truffle framework, and in the next module, we will dive deeper
into Solidity and learn how to build even more sophisticated smart contracts.

Developin
Contracts g Advanced Smart
Introduction
Hi. This is Ivan Mushketyk with Pluralsight, and welcome to the next module of this course, Developing Advanced
Smart Contracts. So far in this course, we're mostly using core Solidity features. But in this module, we will dive
deeper into Solidity and learn more advanced features of this language. And to put our skills into practice, we
will first implement a smart contract that will be using all of these new advanced features we are going to learn.
And in one of the later modules, we will see how we can build a web front end, a web application that will be
using our smart contract. Now, here's what specifically we are going to learn. First of all, we will see how we can
work with time in smart contracts, and this is a topic that we have been avoiding so far. Then we'll see how we
can send payments using smart contracts and how we can receive payments. We will then learn how we can
reduce code duplication in our functions by defining custom function modifiers that, for example, allow us to
conveniently reduce validation logic. We will then see how we can implement smart contracts interaction, how
smart contracts can call or deploy other smart contracts. And finally, we will see how we can use events, and
events is away in Ethereum to record additional information about transaction execution.

Crowdfunding Contract
Before we dive into learning more about Solidity, let's briefly discuss what application are we going to build? And
in this module, we will build a crowdfunding application, which allows to collect funds for a specific cause, and it
will be somewhat similar to Kickstarter application. Our application will only implement the basic crowdfunding
flow. Every crowdfunding campaign will have a deadline, and by this deadline, it expects to collect a
predetermined amount of funds. If it is successful, if the money are collected before the deadline, then these
funds will be transferred to a beneficiary, and if the campaign was unsuccessful, then the collected money will
be refunded. Now, here is how it's going to work. First, we would have to deploy a smart contract for each
crowdfunding campaign, and we would have to specify three parameters, the amount of money we want to
collect, the deadline of the campaign, and an Ethereum address of the beneficiary that will receive money if the
campaign is successful. Now, other users on the network can contribute and send ether to this campaign. Now, if
the campaign is successful, then the beneficiary who control this address will be able to collect the funds. If,
however, the campaign was unsuccessful, then the users can get the refunds for their payments and the
beneficiary will get nothing.

Time in Smart Contracts


We will start the current module with the topic of time and how we can work with it in smart contracts. This is
important because one of the features that we will need to implement in our smart contract is a campaign
deadline, and we would need to check if we have reached it. And to do this, we would need to figure out how to
get the current time in a smart contract. Unfortunately, that's a bit tricky in decentralized applications. That's
because all contracts execution should be deterministic. However, every participant in the network will have a
slightly different time, and if they just take the current time when they validate transactions, then they might get
different results because slight changes in time might result in different transaction results. To solve this, we can
use the timestamp of the block generation in Solidity, and this is what we can use instead of the current time. To
get the block time, we need to use the block object and then use the timestamp field on this object to get the
block generation time. And the timestamp field will contain the block generation time, in seconds, that
happened from 1st of January, 1970. And once we have it, we can use this current time just as any other
variable. For example, we can compare it with a deadline and decide what our smart contract should do. Now
speaking about the block object, it also contains some other fields. In addition to the timestamp, it contains the
Gas limit field that allows us to get the gas limit for the current block. It contains the Block number, the
Validator's address, and so on. Now, speaking about time, there are a few tricky issues with it in Solidity. The first
thing is that the block time is controlled by whoever creates the block. They can set completely arbitrary
timestamp values. Ethereum protocol sets certain limits on this since it knows that a block is generated roughly
every 12 seconds. Ethereum protocol uses the previous block timestamps to enforce limits on the current block
timestamp. But we still should not treat the current block timestamp as absolutely precise because it can be
manipulated to a certain degree, and you can assume that if the validator may benefit from manipulating a
current time, then they will. So you need to be defensive when you use current time and take this into account
in your smart contracts. Solidity also has a special feature that allows us to convert between different time units.
For example, we can convert 60 minutes into seconds by writing 60 space and keyword minutes. And we can
also use other time units, such as days or hours. Now the limitation of this feature is that we need to know the
time duration in the compile time for time units to work. However, if we have a variable like this, we can't use
keyword minutes or hours, etc. to convert this into seconds. To do this, we should instead multiply our variable
by 1 minute. And in this case, it will work, it will convert the number of minutes in this variable to seconds. Talking
about time units. We also have Ethereum units, and it allows us to convert between different Ethereum
denominations. And just to remind you, in one of the previous modules, we were talking about serial
denominations, like we usually talk about Ether, but there are also denominations like Wei, which is the smallest
fraction of an Ether. And there are also other denominations as well. Using Ethereum units, we can convert
everything to Wei. For example, 10 Wei will just return an integer 10. But the Ether keyword, in this case, will
convert 30 Ether into weis. And we also have Ethereum units to convert other denominations into Wei, like
Finney. And 1 Finney is one‑thousandth of an Ether. And just as with time units, we can only use expressions that
are known in the compile time, so if we want to, for example, convert a variable that contains a number of Ether
into Wei, we need to use a construct like this.

Enums
So far we have not covered one more value type in Solidity called Enum, and similar to other languages, Enum
allows us to define a custom type that can have a fixed set of predefined values, and it is useful in many cases.
For example, we can have an Enum type that represents a day of the week and it will have seven different
possible values. Or we can represent a state of a contract in Enum, for example, in our contract we'll have
different states for different stages of crowdfunding campaign, and we'll represent it using Enums. Now, we
could also use integers for this, for example, we could have just a number representing a particular day of the
week, but using Enums is more readable and much safer. Let's see how we can use Enums. First of all, to define
an Enum, we need to use the enum keyword and provide the name of our type, and then in curly brackets we
need to list all possible values an Enum type can have. We can then define a variable of this new type and assign
one of the Enum values to it, and of course, we can also read this value later, for example, to compare it with an
expected value. As I mentioned before, we will use Enum types to represent the current state of our
crowdfunding campaign, and to do this we will use an Enum type that will have the following states. First of all,
the Ongoing state will represent that the smart contract is still accepting donations. From this state, it can either
go to the Failed state if we fail to connect the necessary amount of funds, or to the Succeeded state, otherwise.
And once the collected funds are received by a beneficiary, the contract state will change to PaidOut. To
represent the state, we will have a variable in our smart contract of an Enum type that we will define, and we will
use it to decide what operations are allowed in each state. For example, we can have an Enum type that
represents a day of the week and it will have seven different possible values.

Using Enums and Units


In this first demo, we will start working on our crowdfunding smart contract, and in this demo we will create a
smart contract and we will create a constructor to initialize it. And we will use some of the new Solidity features
that we have learned, such as ether units, time units, and enums. And throughout this module, we will be writing
unit tests for our smart contract, and in this demo we will write a test that checks that our smart contract was
initialized correctly. For this module, I have already created a Truffle project and have added an empty
crowdfunding contract and an empty test file that we will start working on in this demo. And notice that I've
created a separate folder for the Truffle project, and this is because later we will create a web application which
will be placed in a separate folder. And now let's start working on our smart contract. First of all, as we've
discussed, I will define an enum type that will represent the state of a campaign, and it will be either Ongoing,
Fail, Succeeded, or PaidOut. Then I'll define the state variables for this smart contract, and we will need the
following variables. First of all, the name of our campaign that will be just a string value. The target amount in a
way that a campaign should collect to be successful. A funding deadline, so this is a time by which the smart
contract should collect the target amount. The address of the beneficiary, and this address is payable so we
should be able to send a payment to this address if the campaign is successful. And the state field that
represents the current state of the campaign. I'll also define a small helper function currentTime that will allow us
to get current Ethereum time using the block times time field, and I'll use it just in a moment to implement the
final bit we will complete in this demo, which is a constructor of our smart contract. And here is full
implementation. It will receive four parameters, the campaignName, that we will just assign to the name field, the
targetAmount in ether, and we will pass it in ether just to make tests and then using the smart contract a bit
easier, but we'll have to convert it into way. And to do this we'll have to multiply it by number of ways in one
ether that we can just get using this construct. The third parameter will be DurationInMin, and we again need to
first of all convert this duration in minutes into seconds, and then we will have to add it to the current time so we
will get the time of the deadline for this campaign in seconds. The final parameter to this constructor will be the
beneficiaryAddress that will receive the collected funds if the smart contract is successful. And we again just
assign it to the beneficiary field. And the last field that we need to initialize is the state of our smart contract that
will always start in the Ongoing state, meaning that our campaign can receive donations. Now, this is the whole
implementation that we will do for this demo. Now let's go to the test file and implement a test for our
constructor. First, I'll define two variables, the first one will contain a reference to our smart contract that we'll
create in the beforeEach block, and the second one is the beneficiary address, and it will always be, just for
simplicity, the first account we'll get from Truffle. Then we get a few constants. The ONE_ETH constant will
represent the number of way in one Ether, and we will use it in tests later. We'll also define four constants for four
states of the smart contract that we'll use then later to check what state our smart contract is in. Then, in
beforeEach, we'll create an instance of a smart contract that will expect to collect one Ether in 10 minutes, and
we'll set this address as a beneficiary. And now once we have all of this, we can implement our only test in which
we'll check if all the variables of our smart contract were initialized correctly. Because in this test we'll already
have an instance of our smart contract, we can just call all of the methods for corresponding fields and get the
value of the target amount, which should be one Ether. We can check what is the name of the campaign, which
should be campaign name. We can check that the beneficiary address is set up correctly. And finally, we can
check if the state of the smart contract is ONGOING_STATE, as it should be. So, this is our test, and now let's go
and try to execute. As before, I'll just run the truffle test command, which have executed our test, and it is
passing. So now we have a good start for our smart contract, and we will see how we will be developing it step
by step in later demos.

Payments in Smart Contracts


One of the important features of Ethereum is that it has its native currency, and we can use this currency for
payments, we can send this currency to other users, just as we did in one of the first modules. But we can also
control it programmatically, we can define smart contracts that can accept and send payments in ether, and we
will learn how to do this in this lesson. First of all, let's look into how we can send ether from a smart contract. To
send ether, we need to have a payable address, and we can also convert any kind of address into payable if we
use the payable function. Once we have a payable address, we can either call the transfer method and specify
an amount of WHEY we want to send to this address (and I want to note this again, this amount here is in WHEY,
not in ether), or we can call a send method, and the difference between those is that if transfer method fails, it
will throw an exception. If the send method fails, it returns false. So if we use the send method, we should always
check the return value. Now, because we need to be extra careful with using send and check its return value,
send is considered unsafe and should be avoided because what can happen you can easily forget to check a
return value and erroneously assume that ether transfer succeeded. Now once we've discussed how to send
ether, let's talk about how we can receive ether. By default, every account, every smart contract, has a 0
balance. Users can send ether to a smart contract, and other smart contracts can send ether to users or other
smart contracts. And when a contract receives a payment, it can either accept it or reject it. If smart contract
does nothing, if it doesn't implement any special code, then all funds it receives will be accepted by default.
Users and smart contracts have two options to send funds. They can either send them without calling a method,
just as we did in one of the first modules when we were sending ether to another account, or they can call a
method and send funds with a method call. But not every method can accept payments. Only methods that
have a special payable modifier can accept payments. Contracts can inspect how much ether was sent to them
in an incoming transaction, and this can be done using the msg object. Now, here's how to accept a payment in
a smart contract. We first of all need to define a function, but we also need to add the payable modifier. Once
this method is called, we can inspect how much ether was sent and decide if we want to accept it. And if a
transaction is not reverted, the payment will be accepted by default. To handle a regular ether transfer without
calling a method, we need to define a special receive function. And notice that to define it, we need to use the
receive keyword without the function keyword, and this function should be external, meaning that it can only be
called from the outside of the smart contract. And then we can implement the logic of this function, decide if we
want to accept the payment, maybe update an internal state of a smart contract to process an incoming
payment, and so on. And if this function is not defined, then smart contract will accept all payments that are sent
directly to its address. We can also get an ether balance of any address on the network. To read the balance, we
need to use the balance field on any address, and notice that this account balance will be in the way. And, if we
want to get the balance of the current contract, we can take the this variable, convert it to an address, and use
the balance field on it. Just to wrap up the topic of payments in Solidity, there is one more thing to keep in mind
if you read older Solidity code. Solidity has a concept of a fallback function, and before version 6.0, this function
had two purposes, to receive payments, and it was called if a user tried to execute an undefined function. But
now these purposes are separated. The fallback function only handles unmatched function calls, while now
there is a separate receive function that we've covered already that handles payments sent to the contracts
address. To define a fallback function, we only need to use the fallback keyword without the function keyword,
and it will be called if an undefined function is executed. We can also define it with a single input parameter byte
array that allows to receive input passed to a function call.

Call Function
Just to finish on the topic of how we can send payments from a smart contract, we need to talk about another
way of doing this apart from send and transfer. The issue with using send and transfer is that these functions
impose a gas limit. A receiving smart contract can only spend up to 2,300 gas when it processes incoming
transaction. So this is just enough gas to receive a payment and quickly update a state of a smart contract in
response to a payment. But unfortunately, a receiving contract can easily run out of gas because that's quite a
small amount of gas to spend. As a workaround, we can use the call method, and a call function is a general
purpose function that allows us to call an arbitrary method on any smart contract. So it wasn't added specifically
to send payments, but the benefit of using it is that it does not impose a limit on how much gas a receiving
contract can use. And because of this, this is a recommended way of sending ether. Now, here's how we can use
the call function. If we have an address, we can call the call method on it, and if we want to send some ether, we
should use the value parameter and specify how much ether to send. With call method, we also need to provide
a method to call, and if we don't need to call any method and just want to send ether, then we need to provide
an empty string as this parameter. Call method can do more than that, we can use it to call an arbitrary method
on a smart contract. If we want to call a method called foo that receives a single uint parameter, then we need to
specify a method signature, an argument that you want to send, then wrap it using the encodeWithSignature
method, and pass the result of this method to the call function. And the call function will see that you want to
call this specific method and it will also send one ether when it calls a method. Now, at this stage, you might be
wondering, should you just use call all the time, and if it has any downsides apart from this slightly odd syntax. As
it turns out, there is a downside and it is called a reentrancy attack. We will see how it works, why it is dangerous,
and most importantly, how to defend against it. Now, one thing to keep in mind is that when we send ether to an
address, we don't know who we're sending it to. It can be user, an externally owned account, or it can also be
another smart contract. And as we know, smart contracts can execute code when they receive payments, and
they also can call the smart contract that sent ether to them, and this will all be happening as a part of a single
Ethereum transaction. Well, this doesn't sound too bad, isn't it? But it can lead to some dire consequences. As
an example, let's say that we have a smart contract, and users can contribute ether to this smart contract. It also
keeps track of how much each user has contributed, and users can withdraw ether when they want to. To
implement the withdrawal, a smart contract can have a method like this, that when it receives a transaction, it
first checks if a balance for a user is greater than 0, and if it's greater than 0, then it transfers all balance to the
sender, and to do this it uses the call method. And instead of using the whole call method syntax, let's imagine
that transferWithCall does just that. After this amount was transferred, then we can set a balance for this user to
0. Now let's see how this method can be executed. Let's say that somebody calls this method, and on the first
call our smart contract gets the balance, it's greater than 0, so everything is fine, and then it transfers the full
amount to the caller. But it turns out that the caller is not the user, but the smart contract, and when it receives
this transfer while processing an incoming payment, it sends another call to the withdraw function. Now, what
will happen in this case? We'll again get the balance, we'll check if it's not 0, and because we did not set it to 0
the last time, it is still not 0, so we will allow to send the same full amount again for the same user that should
only get one transfer. And I completely understand that it might be tricky to wrap your head around this from the
first time, it is quite a difficult topic to grasp. So, if you have trouble understanding it, I would suggest to watch
this video again and walk through this example again, or ask questions in the question section of this course. But,
how bad can the reentrancy attack be? One notable example of the reentrancy attack was the so‑called DAO
hack. A hacker used this attack to steal 60 million ether from users, and it also caused a split in Ethereum into
two different chains. Now, we won't have time in this course to go over this attack, but if you're interested in
more details, I will suggest to read The Infinite Machine that covers the history of Ethereum, and the DAO hack
specifically. But now let's go back to the practical side of things. How do we protect ourselves against the
reentrancy attack? Now, a common pattern is structure a method into three blocks. Pre‑conditions, where we
check if this method call is valid. Then, Change state, where we update the state of our smart contract. And
Interactions, where we call other smart contracts, send payments, etc. So we can structure the withdraw method
in the following way. First of all, get the balance and check if it's greater than 0, then first set the balance to 0,
and only then send the payment. So if an attacker will try to call this method again during our call, the balance
will be 0 and the attack will fail. But let's just recap what we've just discussed. To protect from reentrancy attack,
we can use send or transfer. They set a limit to the gas amount that a receiver can use, and because the amount
of gas is so small, this cannot cause a reentrancy attack. Call, on the other hand, doesn't set a limit to the amount
of gas that a receiver smart contract can use, the only limit is how much gas a user set when they sent a
transaction. But, on the other hand, using call can cause a reentrancy attack, so we need to be careful with that.

Function Modifiers
When we write smart contracts, a lot of code will be dedicated to checking pre‑conditions, such as can the
sender send these parameters? Or is a contract in a valid state? And this can cause quite a lot of code
duplication because we might need to implement the same checks in different methods. Fortunately, Solidity
has a nice feature that allows us to avoid this code duplication. And to see how it works, imagine that we have a
contract like this. Let's say we have a contract that has a special address with extra privileges that is called
owner. And let's say we have two methods, removeContract and updateContract, and we only allow the owner
to perform these operations. Now, to reduce code duplication, we can create a function modifier and then apply
these modifiers on the methods of our smart contract. And here is how they work. To define a modifier, we first of
all need to use the modifier keyword and then provide the name of our modifier, and in the curly brackets, we
need to specify the code that should be executed when this modifier is called. A modifier can contain an
arbitrary code, but our modifier will check if a caller of the method is the owner of the smart contract instance.
And then in modifiers, we can use the special underscore syntax, which means execute the rest of the function
on which this modifier is applied. To apply modifier, we need to put the name of the modifier between the list of
parameters and the body of this function. And the way it works, if this function is called, first of all, it will call the
modifier function, execute the require statement, and then it will execute the body of the function. We can also
have modifiers that accept parameters. For example, let's say we now have different roles in our smart contract
and we want to restrict different method calls to different roles. To do this, we can define a modifier that accepts
a parameter, and in the body of this modifier, we can check that the caller of the method is equal to the value of
the parameter that was sent to this modifier. And when we apply a modifier, we can pass the value for this
parameter as if we called a function. There is no restriction that we can only use one modifier on the function, we
can actually apply multiple modifiers. So for example, in this case we have two modifiers, one checks who is the
sender of a transaction, and another one checks the state of our smart contract. And, if we have a function, we
can apply both of these on the same function, in which case, first, it will execute the isOwner modifier, and then
the gameStarted modifier.

Receiving Payments for Crowdfunding


In this demo, we will take the next step in the implementation of our smart contracts and we'll implement the two
new features. First of all, we will implement a new function modifier that will allow us to verify that the contract is
in the proper state when a particular function is called. And finally, we will implement a function that will allow our
smart contract to receive donations from other users. To implement all of this, I'll have to first add two more state
variables. The first one is a mapping from address to an integer, and this mapping will store an amount of how
much each user has contributed to this crowdfunding campaign, and we might need it in case if the campaign
has failed and we want to know how much we want to refund to each user. And the other field is a Boolean flag
called collected that will represent if we have already collected the target amount for this campaign. We will first
start with adding a modifier that we will call inState, and this inState modifier will check if a particular function is
called in the expected state of our smart contract. It will receive the only parameter, which is the expected state
of our enum type that we have defined before, and it will check if the current state of the smart contract is equal
to the state that we expect. And if it's not equal, then a transaction will be reverted, or if our smart contract is in a
state that we expect it to be, then it will execute the function this modifier is applied on. Next, I'll define a
function that allows us to receive payments from other users, and I'll define it not as a regular method, but I'll
define it as a receive function. We only want to allow other users to send payments to it if our smart contract is
inState Ongoing. If it is in the Ongoing state if this check has passed, then first of all we need to record in our
map how much a user has contributed to a campaign, and to do this, we record the amount we have for the
msg.sender address by the amount that they have transferred to the smart contract. And then we need to
check if we have already collected the targetAmount, and to did this, we compare the totalCollected amount
with the targetAmount and it will implement the totalCollected function in just a second. If it is more or equal,
then we set the collective flag to true. And now we just need to implement the totalCollected function. And this
will be relatively straightforward. We have already covered that we can get an Ethereum balance for any address
and we also can get an Ethereum balance for our smart contract as well. And the only thing that we need to do
is first convert this reference to an address so we can get the balance from it. Now once we have the new code
for our smart contract, it is time to implement tests for it, and we'll add the only test that checks if our smart
contract accepts contributions. To do this, we will first send a transaction to our smart contract and we want to
specify that we want to send ONE_ETH to it. And to verify that it worked as expected, we need to do two things.
First of all, we need to check that we have recorded an amount sent by this address, and second, we want to
check that this payment was actually accepted by the smart contract. If we check the latter, we'll get the
amount recorded for this address, and it will return the amount collected by this account in a wei. And because
truffle‑contract returns this as a BigNumber, we first need to convert it to string and then compare it to ONE_ETH
that we will convert to string as well. And second, we can check the total balance of our smart contract, which
we can get using the totalCollected function. And, again, it will return BigNumber that we need to convert to
string to compare it to ONE_ETH. Okay, now having this new test, we can run our tests again. And as we could
expect, both tests are now passing, so we can now send donations to our campaign so it will accept those
payments and it will record how much was contributed by each user.

Emulating Time in Truffle


As you remember, our smart contract behavior depends on current time, for example, we expect that the full
campaign amount should be collected before the deadline, but we did not discuss how to test such a smart
contract. How can we advance time in Truffle tests? Well, to do this, we can use a combination of 2, or perhaps 3,
methods to set time in tests. The first one is called evm_increaseTime, which allows us to advance current time in
the test environment in Truffle tests, and the second one is evm_mine, that allows us to mine a new block with
the current time that we have after we have increased it with increaseTime. And if we call these methods in
succession, we will be able to control time in a smart contract and test how our contract behaves depending on
current time. And here's how we're going to do this. First of all, we will need to get a web3 reference, and then
we would need to call the send method and specify specifically that we want to call the evm_mine web3
method. And we also would need to pass a Callback function that will be called when a method execution
completes, and this Callback receives either an error if it failed, or a result if it succeeded. And we would call the
evm_increaseTime in a similar way, we would just use a different method name. Now, one technicality related to
JavaScript and web3 is that in our test we use async/await, and if you recall, async/await behind the scene uses
promises. But the problem is that web3 does not return a promise, and instead it accepts a callback that we
need to somehow convert to a promise to make it work in our tests, and here's how we can do this. First of all, we
need to create a new instance of a promise, and if you recall, the promise represents an asynchronous
operation, and to define it we need to provide a function that implements this asynchronous operation. And it
receives two parameters, resolve and reject, that allows us to specify if this promise succeeded or failed. Now in
this function we will call this web3.js method and we will also pass our Callback. And in this Callback, we will
either call the reject method if we got an error, or we we will call the resolve method if we got the result from this
web3.js call. Now, one last tricky thing is if we got an error and if we call the reject, we then need to return from
the function so we wouldn't accidentally call both reject and resolve.

Testing Time Dependent Contracts


In this demo, we will update our smart contract in the way that its behavior will depend on the current time, and
then we will write additional tests to validate this new behavior. So to start, I'll first add two more helper
functions, and here they are, beforeDeadline and afterDeadline. And as the name suggests, beforeDeadline
returns true if we still have not reached the campaign's deadline; and afterDeadline is the opposite; it returns
true if we've passed the deadline. Now let's add another method to our contract that allows us to finish the
crowdfunding campaign. And first of all, this method requires that it is called only afterDeadline, which makes
sense. We only can finish the crowdfunding campaign after deadline. And in this method, we will, first of all,
check if we have collected the required amount of funds, and if we have not collected the required amount,
then the state of our campaign will be set to fail. Alternatively, if we manage to collect the required amount, then
its state will be set to succeed it. We need to also change how handling incoming payments depends on current
time. And what I'll do here, I'll require that all payments are sent before the deadline, which again, corresponds
to our requirement that all payments should be sent before the deadline. Now, before we add any test that does
this time‑dependent behavior, what we need to do is to add two helper functions. The first one is increaseTime
that will allow us to increase the current time in our test environment, and this function will receive the only
parameter, which is by how many seconds do we want to increase current time? And we use this parameter to
call the evm_increaseTime web3 method on our test environment. And as we've discussed before, we need to
convert this into a promise so we can use it in the async/await code. Now that's not all. We also should be able to
mine a new block with a new time. And for this, we will add another helper function called mineBlock, which
looks very similar to increaseTime with the only difference that it calls a different method. So now having these
functions and having the updated smart contract, let's add a few more tests. And in the first test, we will check
that we can only send contributions before the deadline. To do this, we need to first of all increase current time
and mine a new block, and the reason why we pass 601 seconds to increaseTime is because the deadline of our
smart contract is 10 minutes, or 600 seconds, so we just go a little bit over the deadline. And then we send the
transaction that attempts to send ONE_ETH to our smart contract, and we expect that this transaction will fail.
Now let's add another test that checks that if our campaign has not collected the required amount, then the
state of the campaign will be failed, and what we'll do, we'll get the new crowdfunding campaign with no
contributions, we'll increase the time, we'll finish the crowdfunding, which should be possible at this state
because the deadline has passed, and it will check that the current state of the smart contract is equal to
FAILED_STATE. Now once we've covered the FAILED_STATE of the campaign, let's check if it can go to the
SUCCEEDED_STATE. And to do it, we'll do almost exactly the same thing as in the previous test, except we'll
send ONE_ETH to our smart contract, which will reach the target amount, increaseTime, finishCrowdfunding, and
with this, our smart contract should be in SUCEEDED_STATE because it managed to collect the required target
before the deadline. And then the final test that we should implement is that we can no longer contribute after
the deadline, which again, should be very similar to all the previous tests. We increased time, so we're now past
the deadline, we set a transaction, and this transaction should return an error because the deadline for our
campaign has already passed. Now let's see if our smart contract works. And as you can see, our tests and our
smart contract now work just as we expected, and with this, we're able to practice, first of all, how to write a
smart contract, which behavior depends on current time, and second of all, how we can write tests for such a
smart contract.

Sending Payouts
In this demo, we will wrap up the implementation of our smart contract. We will add two new methods, one to
receive refunds, and another one to send funds to a beneficiary. And as always, we'll add unit tests to check that
our smart contract works just as we expect. So first, let's add a new method that will allow us to send the total
collected amount to the beneficiary, and this is how we will implement it. First of all, we need to check if the state
of the campaign is succeeded. So we only send funds to the beneficiary if we've managed to collect the full
amount before the deadline. And then we'll use the send method to send the fullCollected amount to the
beneficiary address, and if we've managed to do this, then the state of our campaign will be set to PaidOut. But if
we fail to pay for whatever reason, then we will set the state of the smart contract to Failed to allow the
contributors to get refunds. And finally, we will implement the withdraw method that will allow to collect refunds
in case if the campaign has failed. It will only be possible to call it in the Failed state of the campaign, and in this
method, we'll first of all check that the caller has contributed some funds to the campaign, and if they did
contribute anything, then it would get the amount that they sent, and we'd use a transfer method to send the
amount of contributed back to them. Now let's add two more tests to check this behavior. We'll start with the
test that checks if the beneficiary can collect money from the campaign, and to do this, first of all, we contribute
the target amount, we increase time past the deadline, and then we finish the crowdfunding campaign. And
after this, we call the collect method to collect the received funds, but we want to check if these funds are
actually sent to the beneficiary so we get the balance for the beneficiary address before and after the call, and
then we'll check that the difference in the balance is equal to ONE_ETH, which is the amount that we've
contributed during this test campaign. And we also check that the state of the smart contract after this method
call is set to PAID_OUT. Now for the last test of this demo, we will check that the refund functionality works as
well. So here we send the amount that is less than the target amount, then finish the campaign, and then we first
of all check that the campaign has failed, and then we try to withdraw the required amount using the withdraw
method and check that the state of our smart contract was updated, and we no longer have a positive balance
for this account.

Contracts Interactions
So far, in this course, all contracts we have implemented were working in isolation, but to get the real power of
smart contracts, we need to learn how they can interact with each other, and smart contracts can deploy other
smart contracts, they can send payments, or they can call methods on other smart contracts. And learning how
we can implement interactions between smart contracts opens a lot of possibilities for developing even more
sophisticated applications. Now let's see how we can call a method on another smart contract, and let's say we
have a smart contract that implements an online shop, and we also have another smart contract that
implements a single item in this shop, to call a method on another smart contract. But first of all, we need to
know its address, and then we need to convert this address into the instance of our smart contract. And to do
this, we need to use the name of the smart contract we want to call, and in parentheses provide the address of
the smart contract. And once we have this variable, we can then start calling methods on this smart contract.
Smart contracts can also deploy new smart contracts. And again, let's say we have a similar example when we
have an online shop and it wants to deploy an instance of the shop item smart contract. And to do this, we need
to use the new keyword, specify the name of the smart contract we want to deploy, and provide the parameters
for the smart contract's constructor. And then this will again return an object that we can use to interact with our
smart contract, and as before, we can start calling methods on it. An issue was calling a method on a smart
contract or deploying a new instance of a smart contract is that both can fail and throw an error. And to handle
just that, Solidity has a try/catch statement that allows us to handle errors when interacting with other smart
contracts. This is a relatively recent feature that was only added in version 0.6 of the language. And before that,
if there was an error during a transaction execution, the whole transaction would fail. But now, we can handle
these errors using the try/catch statements, and they're somewhat similar to try/catch statements in other
programming languages, with some differences. This construct has some limitations in Solidity. First of all, it can
only work on external calls or contract creations. And as of now, it supports a limited set of error types, to handle
an error when we are calling a method on another smart contract, but first of all, we need to use the try keyword,
then to specify the method call, and then using the return statement, specify the return type of this expression.
Then, with this, we need to provide two blocks. The try block will be executed if there was no error calling this
method, and then we need to provide the catch block, and the catch block will be executed if there was an error
when calling this method. We can do a similar thing when we are deploying a smart contract, but instead of
calling a method before the try block, we need to deploy an instance of a smart contract, and then using the
returns keyword, we need to specify the return type, which is the type of this smart contract. And as before, if
there were no errors creating this smart contract, the try block will be executed, and if there were any errors,
then Solidity will execute the catch block. Using the catch block, we can catch different error types using
try/catch, but so far, we have only a limited set of errors; we can catch. If we write a catch block like this where
we write an error, which has a single string field, then this block will be able to catch errors created by revert or
the require statement. If we catch a panic error, this will be able to process errors from the assert function. To
handle any other error type, we need to catch a byte array like this. And if we don't provide the type of an error, if
we just write the catch block, no error type, and the block to execute, this will catch any error that was thrown.
And we don't need to write a single catch block, we can combine catch statements. So, for example, in this case,
we have two catch statements, and the first one will be executed if an error was caused by revert or require
functions, and if the error was caused by anything else, then Solidity will execute the catch block that will catch
any other error.

Events
Now let's talk about another Ethereum concept called events. And events is a mechanism that allows us to
notify about an event that happened during a transaction execution. Web3 clients can subscribe to these
events and monitor when particular events happen to a smart contract. Those events are also stored
permanently in the blockchain history so we can read them later. The major downside, however, is that contracts
themselves cannot subscribe to events, only web3 clients can do this. Events also allow us to store additional
information to the blockchain history, and the reason why we might do this instead of using a regular state field,
storing an event is cheaper than storing it in a contract state. Now let's see how we can use an event in Solidity.
First of all, we would need to define an event type, and to do this, we need to use the event keyword, specify the
name of the event, and then list parameters of an event. To generate an event, in the smart contract, we need to
use to emit keyword, provide the name of an event that we want to emit, and provide arguments for the
parameters of an event. Now in web3.js, we can subscribe to events, and to subscribe to a particular event, we
need to get the events object, dot, the name of our event type, and then we want to specify additional
parameters, what events of this type do we want to read, and we can specify fromBlock, which is the number of
a block from which we start reading the list of generated events, and toBlock, which is the number of the block
to which we want to read the list of events. And these two are optional, so we don't need to provide them if we
don't need to. But we also need to provide a callback function, and this callback function will be called on every
event that web3.js reads. Now, sometimes we might want to filter events not just by block numbers, but also by
the values of their attributes, and to do this, we need to use indexed attributes. These indexed attributes allow
us to filter events by particular attributes' value, and all we need to do in our events definition is to use the
indexed keyword. Here's how it works. If we want to define an event with an indexed attribute, we would just use
the indexed keyword when we define an attribute, and then we can emit an event in exactly the same way as
before. And then to filter events by a particular attribute value, we'll first of all subscribe to them as before, but
then we can provide the filter parameter where we'll specify what attributes do we want to filter by, and in this
case, we specify that we are only interested in events where the value of the type attribute is either 0 or 1. And
then to get this list of events, we need to define the callback function that will be again called on every event.

Using Events
In the last demo of this module, we'll define an event type, and we'll emit this event from our smart contract. And
as always, we will write a unit test that checks that this event was correctly emitted. First, let's start by defining a
new event type. And in this contract, we will define a new event type that will signify that a crowdfunding
campaign has finished. Our event will be called CampaignFinished, and it will have three attributes, the address
of the campaign, the total collected amount, and the Boolean succeeded flag that will specify if the campaign
finished successfully or if it has failed. And to emit this event, we will go to the finishedCrowdfunding method.
And in this method, we will emit this new event. And to do this, we will convert this reference to the contract
address, get the total collected amount using the totalCollected method, and to decide if the smart contract
was successful, we'll just use the collected flag, which will be true if the campaign managed to collect the
necessary amount of funds and false otherwise. And now let's implement our final test for the smart contract.
And this test will verify that our smart contract correctly emits this event. We'll first of all move time past the
deadline, we'll finish the campaign, which should fail at this stage. But notice that when we execute the
finishCrowdfunding method, we'll get the receipt object from this. And receipt object in Ethereum basically
contains the transaction's outcome, and we can get it either for a transaction that we execute or we can get it
for any of the historical transactions. On this receipt object, we can get the logs field. And the logs field contains
the list of events that were emitted during the transaction execution. And we want to verify that this transaction
has generated one event. And then we can get this event, and first of all, we want to check that the name of this
event is campaignFinished, which is the name of the event that we have emitted. And then we can check that
the arguments of this event were correct. We check that the address of the smart contract is set correctly, that
the total collected amount is equal to 0, and that it has failed, meaning that the succeeded field is equal to false.
Okay, and now having this, we can perform the last test's execution in this module and check if our smart
contract works correctly. Okay, so all of our tests are passing, which means that we have a smart contract that
can accept contributions, that can perform payouts, refunds, and it also can generate events, and it can
correctly work with time, meaning that its behavior depends on the current time.

Summary
In this module, we've covered quite a lot of important topics. First of all, we've covered how to work with time in
smart contracts. We saw how to use time units in Solidity and how to test smart contracts that rely on current
time. We have dedicated a big portion of this module to working with payments, and we've learned how to
accept payments and how to send payments, and we've covered three different methods for sending payments.
And we also covered reentrancy attacks and how to defend from them. We also saw how we can implement
custom method modifiers and how to use them to reduce code duplication. We then learned how to implement
smart contract interactions, call other smart contracts, create smart contracts, and how to handle errors in
Solidity. We finished this module by covering events in smart contracts and how we can record additional
information about transaction execution using events.

Reusi ng
ContractsCode in Smart
Introduction
Hi, this is Ivan Mushketyk with Pluralsight, and welcome to the next module of this course, Reusing Code in
Smart Contracts. And in this module, we'll cover two ways of reusing code in our smart contracts. One is
inheritance in smart contracts, and using inheritance, we can create a new smart contract that derives from an
existing smart contract and can reuse some of its code. We will also cover a related topic of polymorphism, a
mechanism when an actual method being called in a smart contract is decided in the runtime when a smart
contract is executed. And we will also talk about how we can use libraries in Solidity. We'll see how we can define
our own libraries, and we will learn how we can use libraries created by other developers, and we will learn how
we can import these libraries into our project using Truffle.

Contracts Inheritance
Let's start this module with discussing inheritance in smart contracts. And you might be wondering, what is
inheritance? The core idea is that it allows us to define a new smart contract by reusing code of an existing
smart contract. And if you're familiar with object‑oriented programming languages, then this concept should be
familiar to you. Just as we can inherit classes in these languages, we can inherit new contracts from existing
contracts. But the way inheritance is implemented in Solidity is most similar to Python. When we inherit smart
contract from an existing smart contract, we will reuse the code of an existing smart contract, but we can also
add new methods to the new smart contract, we can replace methods, etc. Now let's look at a simple example of
smart contract inheritance. Let's say that we have a smart contract called Restricted, and it has two methods,
allowed and changeState. And when changeState is called, it will first use the allowed method to check if the
caller of this method can perform this operation. And by default, Restricted will allow all callers to perform this
operation. But we can also define a new smart contract called AllowsOwner, and using the is keyword to specify
that it inherits the Restricted smart contract. Now, if we leave it at that, if we don't define anything in the body of
the smart contract, it will just have the same methods and the same state as the Restricted smart contract. But
we can also replace implementations of some of the methods that we get from this smart contract. For example,
we can replace the implementation of the allowed method and change it so only the owner of the smart
contract can perform this operation. So if we deploy AllowsOwners smart contract, it will still have two methods,
the changeState from the restricted smart contract, but allowed will be replaced with its own implementation.
One important bit of terminology that we'll use for the rest of the module is that a contract that inherits another
contract is called a child, and a contract being inherited is called a parent. We can also inherit smart contracts
with constructors. So let's say we have a parent smart contract called Auction, and it has a constructor with one
parameter, the number of rounds in an Auction. If we inherit this contract, we need to provide the values for its
constructor. And to do this, when we define a constructor for a child contract, we need to write the name of the
parent contract and provide the value for its only parameter. So far, we're only discussing how to inherit a fully
defined smart contract, but there's also another interesting concept called an abstract contract. And abstract
contracts are contracts that cannot be deployed and can only be inherited by other smart contracts that we
can deploy. Abstract contracts usually define just the part of the functionality, and they serve like a template for
implementation, leaving some methods unimplemented. When we inherit an abstract contract, child contracts
can define and specify the remaining implementation. Here is an example of an abstract contract where we have
a method called pay, but it has no definition. So, we cannot deploy a contract like this, but we can inherit the
smart contract, we can create a new smart contract that implements all unimplemented methods from its
parent, and then this smart contract we can deploy. Now to wrap up the topic of inheritance, let's talk about the
concept of access modifiers and how they are related to contract inheritance. If you recall, in one of the earlier
modules, we were discussing two similar modifiers, internal and private, and they're very similar. If we use these
modifiers, a method can only be called from the inside of the smart contract. It cannot be called from the
outside. If we have a method with the internal modifier, it can be called by the contract itself or by any of its child
contracts. On the other hand, method with the private modifier can only be called by the contract where it is
defined.

Polymorphism
When talking about inheritance, it is almost impossible to avoid the topic of polymorphism. And in a nutshell,
polymorphism is a mechanism that affects how we can interact with smart contracts that use inheritance. And if
you've never encountered polymorphism, it is easier to explain how it works using an example. Before we dive
into any theory, let's say we have a smart contract called ShopItem, and it has a single method. And this method
does not have an implementation, so we can't deploy this smart contract. And also let's say that we have
multiple child smart contracts that inherit ShopItem, and they implement this startSale method. For example,
here we define the logic for starting an auction when somebody wants to sell an item. Now where it becomes
interesting is if we have a reference to a parent smart contract, the ShopItem. And you might say, wait, we know
that the ShopItem is an abstract smart contract, we cannot deploy it, and that would correct. But we can define
a reference to an abstract smart contract, and we can then assign a reference to the child smart contract in the
place where we expect the parent smart contract. And then we can use the ShopItem reference and call the
method using this reference, but it will call the method of the child smart contract. So just to reiterate this again,
we have a reference to the parent smart contract, but when we call the method, it will call the method of the
smart contract it points to. So when we write this code, we actually don't know what method will be called at this
point. The exact method is defined during the execution of the smart contract. So now that we saw a particular
example, let's describe a general rule. First, if we have anywhere in our code a reference to a parent smart
contract, we can pass there a reference to a child smart contract. And this reference can be a state variable, a
function parameter, etc. And once we have a reference of the parent contract type, if we call a method on it, it
will call a method of a contract it refers to, and this will be despite the type of the reference. It will always call the
method on the smart contract the reference is pointing to. But you might be wondering why is this useful, how
we can realistically apply this. And the concept of polymorphism allows us to implement the code that interacts
with some smart contract. But then the same code can work with different implementations, even if a particular
implementation doesn't exist yet. And we can use polymorphism with regular contracts or we can use abstract
contracts. And we can even use polymorphism with contracts that have no implemented methods and only
have methods definitions. And these smart contracts that only have method definitions are called interfaces.
They can define methods that other smart contracts need to implement, and then we can write code against
them. And this code will work with any implementation. And the concept of interfaces in Solidity is very similar to
similar concepts in other languages, like Java, TypeScript, C#, etc.

Using Third-party Code


So far in this course, we were developing all code by ourselves. But of course, just as languages, Solidity allows
us to use third‑party libraries from other developers, and using third‑party libraries has a few advantages. First of
all, we don't need to reinvent the wheel. We can save time by using the code that was written by somebody else.
And we also can get access to well‑tested code and avoid some bugs that we might have introduced to our
smart contract if we were to implement this functionality ourselves. Now, in the following demo, we will see how
we can use an OpenZeppelin library in our smart contract. But before we dive into this, let's talk about what
OpenZeppelin is. OpenZeppelin is a company that provides a set of products to enhance security of smart
contracts, and one of their most known products is a library with the same name that focused on securing smart
contracts. Now, in this module, we will use one of their utility classes in this library called Ownable, and we will
see how we can use it in a second. But the overall idea of this class that it allows to set an owner address for a
smart contract that might have some special privileges. Before we look into what this Ownable smart contract
can do for us, it is important to keep in mind that we will inherit our smart contract from this Ownable smart
contract. So, essentially we will add all the methods from this smart contract into our smart contract. So, what
methods are defined in there? First, it stores an address of the current owner. We can get the address of the
current owner using the owner function. We can also check if the caller is the owner of the smart contract. And
to do this, we need to use the checkOwner method that reverts a transaction if the sender is not the owner. The
last thing is Onwable allows to transfer ownership from one address to the other, and to do this, there is another
method that is now public that allows to transfer ownership to a new address, and this method can only be
called by the current owner. Now, we also need to figure out how to add the OpenZeppelin library to our Truffle
project. And surprisingly, to do this, we need to use the npm command. First, we'd need to create an NPM
package in our Truffle project, and this will allow us to add additional dependencies later. So we need to run this
npm init command and provide the ‑y flag that will help us to skip all the prompts about how to configure this
initial package. And once we have this, we can use the npm install command to download the OpenZeppelin
library. And while you might be more familiar with using npm to install JavaScript packages, we can also use it to
download Solidity libraries, like here we use it to download @openzeppelin/contracts. Now in this course, we'll
barely scratch the surface of the OpenZeppelin functionality, but you can also read more about other smart
contracts from this library in their official documentation.

Using OpenZeppelin
In this demo, we will add OpenZeppelin library to our project, and then we enhance the functionality of our
smart contract using this library. As we discussed before, to use third‑party code in a Truffle project, we first of all
need to run the npm init command. And this command will create an NPM package that will then allow us to
download search party packages with Solidity code. Npm init command wrote this configuration to the package
JSON file and having this, we can now add third‑party code to our project. And to do this, we would use the npm
install command. And that's it. Now we have the OpenZeppelin smart contract library in our project, and we can
use it to improve our smart contract. Now to find out what OpenZeppelin can do for us, we can go to the official
OpenZeppelin website, go to Contracts, then go to the docs. And this page has a list of all the smart contracts
that are available in OpenZeppelin. And if you go to the left to the Access page, it will contain the
documentation for the Ownable smart contract that we will use in this demo. And if you're interested, you can go
through these methods and see what is available in this smart contract. Now it also includes a code snippet that
we can use to import the smart contract into our code. Now in our project, we first of all will paste this code, so
now we have access to the Ownable smart contract. And then we can inherit our smart contract from Ownable.
So at this stage, our smart contract will have methods and State from Ownable, and we can start using them in
our smart contract. What we'll do, we'll implement a new method that will allow us to cancel the crowdfunding
before the deadline, and it will only be available in the Ongoing state and beforeDeadline, but we also specified
that only the owner of the smart contract can do this, and we do this using the onlyOwner modifier defined in
the Ownable smart contract. If the owner calls that cancelCrowdfunding method, we change the state of the
smart contract to Failed, which will stop the campaign and will allow users to get refunds. Now, the only
remaining thing that we need to do is we need to transfer the ownership of the smart contract when we deploy
it. And to do this, we will use the transferOwnership function that will transfer the ownership of this smart
contract to the beneficiary address. Okay, so now when we have updated our smart contract, we can add two
simple tests. In the first test, we will check that the beneficiary can cancel the crowdfunding. So we'll call the
cancelCrowdfunding method, and then we'll check that the state of the campaign is now FAILED. In the second
test, we'll check that only the owner can cancel a crowdfunding campaign. We will try to call the
cancelCrowdfunding method, but we will do it from a different account. And in this case, we expect that it will
fail and we'll get an error from the OpenZeppelin library, caller is not the owner. Okay, now, let's see if our smart
contract works as we expect. And as you can see, all of our tests are passing. So we've added third‑party code to
our project, we've inherited from one of its contracts, and we've used that functionality to enhance our smart
contract.

Libraries In Solidity
So far in this course, we're putting all logic of our applications into smart contracts. These contracts were either
developed by us or by a third party like OpenZeppelin. But with Solidity, there is another way to reuse and
deploy our code, which is libraries. Libraries in Solidity, they work similarly to a contract that doesn't have any
state and just works as a collection of functions that we can call. Now, here's an example of a simple library. To
define a library, we need to use the library keyword, then the name of the library, and then in the body of this
library, we can define our functions. And in this case, this will be a function that just returns the maximum of two
numbers, a and b. Having this trivial library, we can then use it in one of our smart contracts. To do this, we need
to use the import statement and specify that we want to import our library, and then to call our method, we need
to specify the name of the library, then dot, and then the name of the method we want to call. Solidity has also
another way of using library functions. It allows us to add a library method to an existing type. So, for example,
let's say we have this library, and it has a single method that receives the only parameter of integer type, and this
function specifically will just return the opposite number to what was passed to it. Having such library definition,
we can add this method, or in Solidity terminology, attach it to the integer type. And to do this, we need to use
the using keyword, specify the library that you want to add, and specify on what type they will want to add
functions from this library. And once we specify that we want to have functions from this library on the integer
type, we can just call the methods of this library on integers as if they were defined in Solidity itself. But notice
that since we only added this library for integer type, we cannot call these methods on any other type apart
from integers. So, for example, we cannot use it for Boolean type.

Linked Libraries
We've already covered how we can create libraries, but it turns out that there are two ways to deploy a new
library with Solidity. One way is to embed the code of the library in the smart contract that uses it. So, in this
case, if we have multiple contracts that use the same library, then the library code will be embedded in each one
of these deployed smart contracts. The other way is when a library is deployed separately. So, in this case, we
deploy a library just as we deploy a smart contract, and if we have multiple smart contracts that depend on it,
then they will use the same deployed instance. And what might be quite confusing is that what defines how
library is deployed is what access modifiers we have on library methods. So let's look at an example. If we have a
library and all of its methods have the internal modifier, then the code of this library will be embedded in other
smart contracts that use it. However, if we have a function with the public modifier, then this library will be
deployed separately. And in libraries, functions can be either internal or public and what modifiers we use
defines how this library is being deployed. Now, let's talk about the concept of deployable libraries. A deployable
library is just another type of smart contract. It has no storage, meaning that it doesn't have any state variables,
like we had in smart contracts. A deployed library, just as any other smart contract, will be available for anyone to
call. And the main benefit of deploying a library is that it allows us to make contracts that use it smaller, which
allows us to save gas when deploying smart contracts. When we deploy a library, it only makes sense to have a
single instance. This is because, first of all, a library doesn't have a state, and they cannot be changed, so there is
no need to have multiple instances. If we deploy a library to use this library, Truffle has a special mechanism
called linking that allows us to connect a deployed library with a smart contract, and essentially, what this linking
means is that Truffle will write the address of the library into the smart contract's code. And here is how this
process looks like. First of all, we need to deploy a library with Truffle. And once we do this, we will have an
address of this library. Then we need to define a smart contract that uses this library. And with this compiled, we
won't be able to deploy it yet because, at this stage, it still won't have the address of the library that it will be
using. To connect this contract to a library, we need to link them together, which means that Truffle will write the
address of this library into this unlinked smart contract. And as a result of this process, we will have a deployable
smart contract. And when it is deployed, it will be using this library. To link a library with Truffle, we need to define
a new migration step. We need to import the library that we want to use and the smart contract that depends on
it. Then in the migration‑step definition, we need to deploy the library just as we deploy any other smart
contract, and then we need to call the link function and specify that we want to link this library with this smart
contract. We can also link an existing library with a smart contract in Truffle. And to do this, we need to go
through the same steps. But in the migration step, we need to use the at function that specifies that we don't
want to deploy this library, we want to use an existing library at this address, and then we can link our library to a
smart contract just as before.

Implementing Libraries
In this demo, we will write a simple library in Solidity, and it will be almost trivial. We'll just implement two
conversion methods for time and ether values, but it will allow us to see how we can use a library in our smart
contract and how we can configure it in Truffle. To implement a library in our project, we first need to create a
new file for it, and I'll call it Utils. And first we need to add the definition of our library, which includes the same
pragma statement as before, the same license‑identifier as before, but instead of using the contract keyword, we
will use the library keyword. And in this library, we will add two methods. The first method etherToWei, will allow
us to convert an amount of ether into wei, and to do this, we'll multiply sumInEther by 1 ether value. And the
second method will be very similar. It will allow us to convert minutes into seconds, and to do this, we'll multiply
timeInMin by 1 minute. Now to use this library, we need to go back to our smart contract. And first, we need to
import our library. And second, because both methods in this library received a single parameter of uint, we can
attach these methods to the uint type. And to do this, we are using the using keyword and specify that we want
to add all methods from the Utils library on the uint type. Now the only thing that's remaining is now to use those
methods in our smart contract. And I'll use them in the constructor where we convert ether values and minutes
into weis and seconds. Okay, this is it. We have updated our smart contract, and because we did not change any
functionality, our tests should just pass as they are. So let's try to run our tests. But unexpectedly, our tests are
failing, and what it says is that Crowdfunding contract contains unresolved libraries. And what we need to do, we
need to deploy and link these libraries before we can use them. And it also specifies the name of the library that
is unresolved, which is our library. And just as we discussed before, we need to add a new deployment step that
will link our library to our smart contract. And I'll add a new migration step, deploy_utils. And here is the definition
of the deployment step that we need to use. First of all, we input the Utils library and the Crowdfunding contract
into the step, and then in the definition of the step itself, we first deploy the Utils library, and then we'll link it to
our Crowdfunding contract. And now this migration step will also be used by our tests. And if we run our tests
again, and as you can see, now all of our tests are passing So in this demo, we have added a new library to our
project. And this library has to be deployed and linked to our smart contract, which we've done in a new
deployment step.

Summary
In this module, we've looked into how we can reduce code in smart contracts. First of all, we've learned how we
can use smart contracts inheritance to define a new smart contract with similar behavior. We've also learned
about polymorphism in Solidity that allows to dynamically select a method to call during the contract execution.
We then saw how we can use third‑party code in Truffle projects. And we've added OpenZeppelin library in our
project. We inherited our smart contracts from one of the contracts in this library and used it to enhance
functionality of our smart contract. We've also learned how to define our own libraries in Solidity, and we've
learned that there are two types of libraries, embedded libraries, when a code of the library is included in the
smart contract that uses it, and deployed libraries that are deployed as other smart contracts, with the only
difference that these smart contracts don't have any state and only have methods that we can call. All right, so
this module finishes the implementation of our smart contract. But in the next module, we will see how we can
build a web application that is built on top of it.

Web Applications with Ethereum


Introduction
Hi. This is Ivan Mushketyk with Pluralsight, and we finally reached the last module of this course, Web
Applications with Ethereum. And as the name suggests, we will see how we can build a web application for our
smart contract. In this module, we will build a full‑fledged decentralized application. It will have a web front end,
and this web front end will use a smart contract deployed on an Ethereum network. The application that we will
develop will be relying on a crowdfunding smart contract that we were working on in the last few modules, and it
will provide a user interface for users to interact with it. The application that we will build will only support the
basic features of our smart contract. The user will be able to view the campaign information by fetching data
from Ethereum and displaying it in the UI. And the user will be able to contribute to a campaign by sending ether
into it. We will also cover the common UX issues that you will encounter when you're working on your
decentralized applications. For example, we will see how we can implement the connect to MetaMask feature
that we saw in one of the first modules. Now, it's important to keep in mind that we won't build a full‑fledged web
application. We will keep focused on the concept that we want to learn, and we won't implement some of the
things that you might expect in a professional web application, like we'll have minimum input validation or we
also won't implement any error checking. So our application will be pretty bare bone, and this is because I think
that implementing those features will distract us from the main goal of this module. And the main goal of this
module is to learn the essential building blocks for building Ethereum web applications. All right., and now
without any further ado, let's get started.
Decentrazlied Applications
Before we go and start building our decentralized application, let's talk about how it will be structured. And to
explain that, let's compare it with a traditional web application. A bare‑bones traditional web application looks
like this. We have a web browser that users use to send requests to a web server. This web server processes
incoming requests, and in turn, it can read and write data to a database or some other data store. A
decentralized application works differently. Instead of relying on the web server, if a browser can interact with an
Ethereum metric directly, it can send transactions to it and it can read data from smart contracts in it. This
approach, when a user directly interacts with an Ethereum network has an important advantage. There is no
intermediary. Users store their private keys. They don't share them with anybody, and nothing, no actions in the
application can happen without users consent. In this module, we will build what is known as a single‑page web
application. The browser will download CSS and JavaScript off our application from a web server. And then using
this application, a user will interact with an Ethereum network. The user then will be able to send transactions to
our smart contract or read data from an Ethereum network. When working on this module, I had to make a
choice of what UI technologies to use for our web application. And I decided to go with some of the most
popular UI technologies at the moment. So first of all, we'll use React library, which is a popular JavaScript UI
library. We will use React Router to implement multiple pages in our application and navigate between them. We
will use Semantic UI, which is a popular CSS framework, which will allow us to save a lot of time on defining CSS.
And last but not least, we will use MetaMask, which is the plugin we've used in previous modules, and it will store
user's private keys, and it will allow users to interact with an Ethereum network. I understand that you might not
be familiar with technologies like React or Semantic UI, and to address this, I will give a very short introduction to
these so you can follow along. But keep in mind that you can use any web technologies to implement your
decentralized application or you can use no frameworks at all. But the concepts that we will learn will work
regardless of what technologies you will use.

React Overview
Since we're going to use React to implement our web front end, it's important for you to know at least the basics
of React. And that's why I added this clip, so you will be able to later follow along as we develop our web
application. And this won't be a course about web development in React, and we'll just cover the bare minimum.
If you want to know more about React, there are a lot great courses on Pluralsight you can watch after this one.
If you are a React expert, you can skip this clip since we're not going to cover anything related to Ethereum or
Web3 here. But specifically, we will cover functional components in React, and we will cover React hooks. And if
you're familiar with both of these, you can skip this clip. Well, the basic idea of React is that we always surrender
or generate our UI from the application state. So our application has a particular state, and React renders the
current UI from the state using the code that we define. If we need to update this UI, for example, if the user's
done something with it, we don't update the UI directly. Instead, we always change the state of our application
and React will notice this and rerender our application accordingly. So, all we need to do is React to find how to
render our UI from the application state and then update the state when necessary, and React will do the rest.
To define how to render UI in React, we need to break down our application into components. And currently, the
most popular way of defining components is called functional components. To define a functional component,
all we need to do is to define a function. And you see it's name is intentionally starting with a capital letter since
this is going to be the name of our new component. This component receives data that it should render, which is
called properties, or props for short. And in the implementation of this component, we can use regular HTML
tags to define how our component should be rendered. We can all surrender nonstatic content such as values
of the properties of our component. And to do this, we can inject bits of shell script code. But to inject them, we
need to put them in curly braces like here where we render the value of the counter property. We can also use
components in other components. For example, if we want to define another component that relies on the
Counter component, we need to use this HTML‑like syntax where instead of the name of an HTML tag, we use
the name of our component. And to configure our component, we need to provide values for its properties
using, again, HTML syntax. So if we add the property Counter here, it will appear in the props object when our
component is rendered. Unless we're building a very simple application, we would have to break it down in the
multiple components. For example, in our case, we might have a page to display information about a particular
campaign. We can implement it using two other components. One would have the sole purpose of displaying
information about the campaign and the other one would display controls to interact with it, for example, to
allow to contribute to campaign if it isn't going. These components can in turn be built from other components,
such as tables, text inputs, buttons, etc. We can also use third‑party components. And in this module, we will use
Semantic UI library that implements a number of third‑party components. To use a component from another
developer, we need to first import it, like in this case, when we import an Input component from Semantic UI
React library, and then we can use it when we define a our own component. We can also configure how it should
be displayed, and here we provide properties for how this component should be rendered. And each
component in Semantic library has a ton of properties that allows us to configure them. So far, we're looking at
components that receive data to display from other components. But each component can have its own state as
well if we want to have it. In modern React, to implement this, we use a mechanism called hooks. And we won't
delve too deeply into this, but the reason why they're called hooks is because they sort of allow to hook into the
React's lifecycle, the lifecycle of components in the React library. And to manage state per component, we need
to use that useState function. And let's briefly see how it works. So here's an example of a component that has
its own local state, and we define it using the useState function that allows us to define a single state field. To call
this function, we need to pass the initial value of this field, and this call will return two variables. The first one is
the current value of the state field, and the second one is a function that allows us to set the new value for this
field. Having this, we can do two things. First of all, we can display the current value of this field, and to do this,
we need to use an expression in curly brackets. And second, we can update the state field using the function
that useState has returned. And as soon as we update the state, React will notice that the state was updated
and it will rerender this component and display new data.

Creating a Web Application


In this demo, we'll create a React application for our decentralized application, and I'll go through the code of
this application just to explain to you what every part of it means so then you will be able to follow along in the
follow‑up demos. And in this particular demo, there will be no Ethereum‑related code. We will just develop the
basis of our application that we will keep working on in the upcoming demos, where we will add logic to interact
with our smart contract, interact with MetaMask, etc. To create a React application, I will use the Create React
App tool. But I first need to install it on my machine, and I use this ‑g flag to specify that I want to install this
application globally. And this tool allows us to create an empty React app that we'll then use to implement our
application. And to run it, I also need to provide the folder in which this template React application should be
created. The Create React App has created a preconfigured React application, and it also includes a few helpful
commands. And one of them is npm start, which allows us to start a development server for our application. If we
run this command, npm will open the browser with the preconfigured React application. But as we can see, the
whole application is just an image with some text. Now I'll add some UI code for our application, and we will walk
through it. So I've added all the official components for our application, but they didn't implement any
Ethereum‑related logic. So let's first walk through how our application will look like, and then I'll go through the
code to explain the most important parts of it. So first of all, this is the Home page of our application where a user
can provide a Crowdfunding campaign address. And if we click Submit, the application goes to the Campaigns
page, where it displays information about a campaign using this table. At the bottom, there is a component that
allows us to contribute to this campaign, but at the moment, it doesn't do anything. If we write a number and
click Contribute, then the final version of our application will send this amount of Ether to the contract. But at
the moment, it just displays a message. We also have the Home button over here, and if it goes to an invalid URL,
then our application will display an Error page. And now let's go to the ID and see how this application is
implemented. So, first of all, in package.json, I've added dependencies for our project. These dependencies
include semantic‑ui, which is a library of third‑party UI components, and react‑routers that allow us to implement
multiple pages and navigation in our application. And the rest, these are standard React dependencies that
were added by the Create React App script. If we go to the src file, this is a source of our application. A lot of
these files were created by React out of the box. The file that I've changed is App.js, that implements the routing
logic of our application, and I've also added the components directory that contains the list of components that
our application will use. In the App.js itself, we define the routes of our applications. So if user goes to localhost/,
then we'll display the Home page of our application. If user goes to /campaigns address of our campaign, then it
will display a Campaign page using the Campaign component. And if a user goes to any other route, then it will
display that NotFound component that displays an error. The Campaign component is responsible for displaying
information about the campaign. First, we define a single State field that will contain information about the single
campaign. We define it using the State hook. We will later update our application to read data from smart
contract and store it into a local state. But for now, we will just initialize it with a placeholder value. UseState
returns the current value of the contract state and a function to update it that we will use later. Then in this
component, we display information about campaign, and to do this, we use the Table component. We define the
header of this table with two columns, Name and Value. And then for every bit of information, we display a row of
the table, where we display the name of the campaign, the targetAmount for the campaign, and so on. At the
bottom section of the table, we display a section that will allow a user to interact with the campaign. And to
render this section, we use this function, that depending on the state of the campaign, we'll display one of these
components. If the campaign is going, a user will be able to contribute through the ContributeInput component.
If the campaign has failed, a user will be able to get the refund using the FailedStateInput, and so on. We will also
look at the ContributeInput component. All it does at the moment is displays a text input. It configures this text
input using all these parameters. When the user updates the value for the amount of Ether they want to
contribute, we'll write it into the local state of this component, and we also implement some simple error
validation. So that's the whole application, it just has a handful of components, and I went through the most
important components. But if you want to know more about how to use these Semantic UI components, how
you can configure them differently, or how you can implement to your application, then you need to go to this
website react.semantic‑ui.com, where you can get the documentation for all the components in the Semantic UI
library. And to get this documentation, you go to a component that you are interested in, such as Button, then
you can look at all the properties that are available on this component, it's just the documentation for it, or
instead, you can just look at the examples here. And if you like some of these examples, you can click on the Try
it button and copy and paste this example to get a particular result. And now once we have the foundation for
our React application, we can see how we can connect it with MetaMask and integrate it with our smart
contract.

Interacting with Ethereum


Now let's talk about the most interesting part of this module, how we can programmatically access an Ethereum
network from a browser. And we'll first talk about the role of MetaMask plugin in this process, and then we'll see
how we can use the web3.js library to interact with Ethereum using MetaMask. When we want to interact with
Ethereum from a browser, we first need to install a MetaMask plugin or other wallet plugin. MetaMask plugin
includes a provider to connect to an Ethereum network. And this provider is a component that we've created
manually in one of the previous modules, and it knows how to connect to a particular Ethereum network. In our
application, to interact with the Ethereum network, we will use web3.js. And we will point our web3.js library to
the provider provided by MetaMask. And this will allow us to connect to the network that a user has selected in
MetaMask, have access to accounts in MetaMask, the transactions, etc. And then our React components will use
the web3.js library that is connected to MetaMask to interact with the Ethereum network and interact with smart
contracts on it. If you recall, MetaMask allows us to switch between different networks, and when we switch it in
the MetaMask UI, its provider starts to point to a different network. This can be a main network, a test network, or
it can be a testing environment like Ganache where we will deploy our smart contract using Truffle. And by using
MetaMask provider field, our code can interact with the network that the user has selected. If a user switches to
a different network, our code will automatically start interacting with it. Here's how we can connect the web3.js
library with MetaMask. First of all, we need to import the Web3 type from the web3 library. Then we need to get a
provider from MetaMask. And to get it, we need to use the ethereum field on the window object. And window
object is a global object in any browser, and it is available to all JavaScript code. And MetaMask adds its provider
to the window object so it will be available to all other applications. And then we can create a Web3 instance,
and to do this we need to pass a provider that we got from MetaMask. And once we have this Web3 instance,
then we can use it exactly as we did in previous modules to send transactions, read data from smart contracts,
deploy smart contracts, etc. Now one thing to keep in mind that when developing decentralized applications on
Ethereum, we need to handle a few Ethereum‑specific edge cases. First we need to check if a user has a wallet
plugin installed since if they don't have it, our application won't be able to access Ethereum, and we need to
warn the user that they need to go and install the plugin. Second, we need to check if MetaMask is connected
to our application. We saw how this process works from the user's perspective in the very first module of the
course, but now we will see how we can implement it. And we will see how to implement it in one of the later
demos. And third, we need to keep in mind that a user might switch networks or change an account at
MetaMask, and we need to be able to handle this as well. So we will solve this one by one, but we'll start with the
simplest one. To check if a wallet plugin is installed, we need to check if the Ethereum field is defined on the
window object. If MetaMask was installed, we will have the ethereum field on the window object. So then this
expression will evaluate to true, and we can implement some code for the case when it is installed. If, however, it
was not installed, this expression will be false and then we can react to this case, maybe display a warning for a
user.

Check MetaMask
In this demo, we will add a check to our application if a wallet plugin is installed in the user's browser, and then
we will also display an error if a plugin like MetaMask is not installed. To implement this feature, I will add a new
component that will only display a Campaign page if a plugin is installed, or it will display an error if a plugin is not
installed. So add a new file here, I'll call it CampaignPage, and here is the implementation of this component. So,
here we define two functions, the function that implements our component and a helper function. And let's start
with the helper function. So the helper function is called isWalletPluginInstalled, and, as the name suggests,
checks if we have a plugin like MetaMask installed, and if it does, it returns true if the ethereum object is defined
or false otherwise. And to do this it uses this weird JavaScript trick when it uses this double exclamation mark.
And what it does, it converts any expression into true or false. If ethereum is defined, it will convert it into true, if
ethereum is undefined, it will convert it into false. And then we use this function in the definition of our
component. If the plugin is not installed, then it will display a text saying wallet is not available and ask a user to
install a wallet. If the wallet is installed, we just display the Campaign page, and we have already gone through
how the Campaign page is implemented. Now, the last remaining thing is that we need to use this component in
our router. To do this, we go to the App file. We don't need to use the Campaign here anymore, so instead we will
use the CampaignPage. And instead of displaying the Campaign component we will display the CampaignPage
component over here. So if a user goes to this address, we'll display in the CampaignPage, which will either
display the campaign itself or the error message. Let's test our code. And to test this code we can either remove
our plugin, but it will also remove the account that we have created, so a better way is just to disable the plugin
and refresh the page. To do this, we need to go to the Manage Extensions page and click on this button to
disable MetaMask. So now it will look as if MetaMask is not installed, but will still keep all the data in our plugin.
Let's refresh the page. And as you can see, we got our message, we got this Wallet not available error. And to
see if it really works, we can just re‑enable the extension. And if we refresh the page, the error disappears. So it
behaves just as we want. And using the code like this, we can instruct the user to install the MetaMask plugin or
other wallet plugin if they don't have it in their browser.

Connect to MetaMask
For our application to interact with Ethereum, we first need to connect it with MetaMask. And essentially, what
this process of connecting to MetaMask means is that a user needs to specify what accounts can be used with
what centralized applications. And by default, MetaMask does not allow any accounts to be used with any
applications. These permissions are given on the per account basis. To connect to MetaMask, we need to call
the requestAccounts method on the user object. And when we call it, MetaMask will display a model window
where the user can select which accounts can be used with the current application. A user can check these
check boxes for accounts that they allow to be used and then click Next or they can click Cancel if they don't
want to to connect any of the accounts to our application. And this requestAccounts method is only available
with a provider from MetaMask or a similar browser plugin. And if our application is already connected to
MetaMask, then this method won't display a model window, and instead, it will return an array of accounts that
are already connected with MetaMask. Just to wrap up this topic, MetaMask has two different ways of getting
the current account. We've already covered the requestAccounts method that can either return a list of
accounts or open the Connect With MetaMask window. But MetaMask also has another method called
getAccounts, which either returns current MetaMask accounts or it returns an empty array if no accounts are
connected. And this last method is useful if we want to get a list of accounts from MetaMask if our application is
already connected and at the same time don't trigger the connect flow if we're not connected yet.

Implementing Connect to MetaMask


In this demo, we'll see how we can implement the connect to MetaMask functionality in our application, but
before we start and dive deep into how to do this, I want to talk about another React feature called useEffect.
UseEffect is another hook in React that allows to execute an arbitrary code when a component is rendered. And
to use it, all we need to do is to call useEffect and provide the function that will be called when the component is
rendered. So in this case, when this Example component has been rendered by React, React will execute this
function and fetch data from this URL. Now we can also use a slightly more advanced useEffect to execute it
conditionally. For example, if we have a state in a component that stores the current account, we can call
useEffect and provide that we want to re‑execute it every time the account is being changed. Basically, we
provide a list of dependencies here, and if one of the dependencies has been changed, this function will be
re‑executed. Now once we have this out of the way, let's see how we can use MetaMask in our application. So
first of all, I've added dependency to web3 library, and this library will then allow us to interact with our smart
contract. Before we make any changes to our UI code, I'll add a utility function that we will use later. And to do
this, I'll add a new folder called ethereum, and then I'll add a new file called utils. And in this file I'll add a single
utility function called getWeb3, and this function will create an instance of web3 using the current MetaMask
provider, which as we discussed, we can get using window.ethereum. Now let's go to the Campaign component
and update it to implement connect to MetaMask. First, I'll add some dependencies. I'll add a dependency to
the useEffect hook that we will use later, and I'll add a dependency to the getWeb3 function that we've just
defined. Now, in our Campaign component we will first get the instance of web3 from MetaMask, and then we'll
define another bit of state using useState, and this bit of state will store at the currentAccount, the current
Ethereum account, that our application is using. And the default value here will be null for the case when we
don't have the current user's account. I'll also add two additional helper functions. One is connectWallet. That is
calling the requestAccounts method from MetaMask, and this function will trigger the connect to MetaMask
flow. I'll also add another function, getCurrentConnectedAccount, that just gets the current account from
MetaMask. But if our application is not connected, then it will just return an empty list. And notice that in both
cases each function returns a list of accounts, but we only use the first account. And this is intentional, this is
how MetaMask API works. It returns a list of accounts, but it always returns a single account in a list. And
MetaMask does this for potential future‑proofing of their API. Okay, now when we have these two functions, I'll
also add this bit of code. And what it does, it says if the currentAccount is not selected, if it's null, then in this
case we'll display this message that the website is not connected to Ethereum. And it will also have a button
with the label Connect Wallet that will allow to trigger the connect to MetaMask flow, and if it is clicked, it will call
the connectWallet function. Now we're almost done, but there's one more thing that we need to do. We also
need to use the useEffect hook to try to get the current connected account when the user goes to the
Campaign page. And now it might be confusing, but let me try to walk through this once again. Once this
component is rendered, React will call this useEffect, will try to get the current connected account, and if there
are no accounts connected, the currentAccount will be null, and the user will see this page. If the account is
already connected, then we will get the currentAccount, and the user will be able to use our application. If the
user sees this message, they can click on the button and can trigger the connect to MetaMask flow. Now let's go
to our application and try to go to the Campaign page again. And as you can see, because our application is not
yet connected to MetaMask, we see this message. And if we click on the Connect Wallet, we get a notification
from MetaMask that this application wants to connect in this account for which we can click Next and then
Connect. And our application is now connected to MetaMask. And if we refresh the page, it will be able to get a
connected account without triggering the connect flow. Now, the very last thing I want to cover related to
currentAccount in MetaMask is that we can ask MetaMask to notify us when a user changes their current
account. And to do this, we can subscribe to the accountsChanged event and provide a function that should be
called when this event happens. And if a user changes their account, we can set this account in the component
state. And with MetaMask, we can also subscribe on other events, like if the user changes a network, we can also
get notification from MetaMask and we can React to this accordingly.

Deploying Crowdfunding Application Revised


In the next few demos, we will see how we can read data from our smart contract, and we'll see how we can
send transactions to it from a web front end. But before we can do this, we need to deploy our smart contract.
And this is exactly what we're going to do into this demo. We will deploy our smart contract to Ganache using
Truffle, and then we'll see how we can connect MetaMask to Ganache and how we can use it to work on our
application. So first things first, we need to update our Truffle project to deploy our smart contract to Ganache.
And to do this, first of all, we need to go to truffle‑config, scroll to networks and add configuration for Ganache.
And this is the same configuration that we've used in one of the previous modules. In addition to this
configuration, we also need to add a new migration step. If you recall, we have a migration step for initial
migration. We have migration step to deploy our library, and now we need the migration step to deploy our smart
contract. And I'll call it deploy_crowdfunding. And this is what our deployment step will look like. We will deploy
the crowdfunding campaign. We will name it Test campaign. We will specify that the target to collect in this
campaign is 1 ether and that the deadline for the campaign is 5 days in minutes. And we also specify the
beneficiary address, which is an address of the account we've created at the beginning of the course. Now to
deploy our smart contract, we also need to start Ganache. And to do this, I'll click on the NEW WORKSPACE
button, and I'll add our Truffle project. Okay, we can save the workspace, and now we have the Ganache running
that we can use to deploy our smart contract. So we can go to the CLI and run the truffle deploy command. And
as you can see, our smart contract was deployed, and now we have an address of our smart contract. But if you
recall, our MetaMask plugin is still connected to the Goerli network. So what we need to do, we need to connect
it to our Ganache instance. And here's how we can do this. We need to open MetaMask and then click on the
Add network button. And here we can specify parameters for MetaMask that it will use to connect to Ganache.
And for the network name, I'll call it Ganache, and for the URL, I will use the same URL that we've used in the
truffle config. But we also need to provide the Chain ID. And this is a confusing parameter, but basically this is a
parameter that is used for transactions sign in to send transactions to Ganache. Surprisingly, you can find it
anywhere in the Ganache UI, but it should be set to 1337, and this is just the way it is configured by default. And
we also need to specify the currency symbol that can be pretty much anything. And now with this configuration,
we can click Save and connect to a new network. Here specifies that we have connected to the Ganache
network. But the only problem is that the account that we have created before, it doesn't have any ether on the
Ganache network, and we won't be able to send transactions to our smart contract if we don't have any ether.
To work around this, we can use one of these accounts that are available in Ganache. And the question is how
we can import, how we can get access to one of these accounts from MetaMask. Fortunately, there is a way to
use one of these test accounts. To do this, we need to click on this button. And if we click there, we will get the
private key of the account we are interested in, and we can just copy this private key. We can go back to
MetaMask, and we can import the test account in MetaMask. So I'll just paste the private key, ensure that the
Type selected here for importing the account is Private Key because this is what we are providing, and then click
Import. And now we have MetaMask that is connected to Ganache, and we have an account from Ganache so
we can go and test our application. We have plenty of ether to test it, and we are connected to the right
network. One last thing is that back here in this application, we need to specify that we want to use a different
account to work with our application. This is because this new account is not yet connected to our application.
And if you recall, we need to connect these accounts on the per account basis. Here, we will manually connect
this account to our application. And to do this, we need to click on this button, select our new account, then
click on Connect. And this will connect our account to MetaMask without actually using the Connect To
MetaMask flow. Now, as you can see, we're connected to our application, and we're ready to go to the next
demo where we will try to read data from our smart contract in our web front end.

Display Contract Data


In this demo, we will see how we can interact with an Ethereum network from our web front end. And specifically
what we'll do, we'll fetch and display information about the current campaign. To interact with a smart contract,
we need to add an ABI of the smart contract for a web ____ what methods are available on it. And I'll do it in a few
steps. So first of all, I'll go to the ethereum folder in our web application, and I'll add another file. And I'll call it
crowdfundingAbi.js, which will contain the ABI for our smart contract. And this is all that I will define for now, that
array called crowdfundingAbi, and I'll export it from this file so that other files will be able to use it. Now we just
need to get the ABI of our smart contract. And with Truffle, the way we can do this is go to the build folder, find a
JSON file for our contract, and here is the ABI of our contract. And all we need to do is to copy it like this, go
back to our file, and paste it. And here we go. We now have the ABI for our contract that we can use to interact
with it. Now I'll also add another util function, which I'll call getContract. That will create a web3 contract object
that we will use then to interact with our smart contract. And this function receives two parameters, the web3
object that we'll create using the getWeb3 function and the address of the contract that we want to interact
with. To create the contract, it also needs the crowdfundingAbi, which we will import from the file we just
created. Okay, now we can go to the React component that we have and update its logic to actually fetch data
about our smart contract. But before we can do this, we need to do one more thing. We need to get the address
of the smart contract that we want to display information for. And if you recall, we pass the address of the smart
contract in the URL of our application. And to get the URL parameter, we will use the useParams method that
gets it from our URL from the Router library that we use. Now when we have the address of our smart contract,
we can finally fetch information from it. And I'll use this complicated looking bit of code that we'll break down bit
by bit right now. So first of all, we use the useEffect function. As we've discussed before, useEffect function is a
hook that will be called every time a component is rendered. So when we open the campaign page, when the
campaign component is displayed, this function will be executed, and it will try to fetch information from our
smart contract. If there is no current account, meaning that if our application is not connected to MetaMask, it
will do nothing. If there is a current account, it will first of all get the contract using the util function we just
created, and then it will send a few method calls to our smart contract. It will get the name of the campaign. It
will get the target amount, the total collected amounts so far, etc. Having this data is overwrited into the
component state using a single object containing all bits of information we have collected. All of it will be
wrapped in the try catch block. If any of these steps failed, we will setContractInfo to null. Now we need to do a
few more things here. First of all, we need to import the getContract function and add getContract here. Now
we also need to do a few very React‑specific things. First of all, to use useEffect, we also need to provide an
array of dependencies. And this is just a React requirement to specify all the things that this function depends
on. So if any of them changes, this useEffect hook will be reexecuted. Another even more obscure React thing
that I won't delve too deep into is that we need to use the useMemo hook here. In short, it allows to ensure that
we create a Web3 instance only once and don't recreate it for each component rendered, which reduces the
number of times React codes use effect. And we also need to import this function here. And the last thing that I
want to do is I want to add just a bit of error handling. And what I'll do here, if the contract info is not defined, if
we failed to fetch it for any reason, I'll just display an error here. Now let's go back to our application. First of all,
I'll copy the contract address that was deployed in one of the previous demos. I'll paste the smart contract
address. I'll click Submit. And as you can see, now we get information about our crowdfunding campaign. We get
the Name, we get the Target amount, and we get all other information that we fetch from Ganache. And if we're
using any other Ethereum network, we could do it in exactly the same way, except we need to connect our
MetaMask to a different network.

Sending a Transaction
Now for the last demo of this module and this course, we will see how we can send a transaction from our web
front end to our smart contract. And specifically, what we are going to do, we will try to implement the logic for
contributing to our crowdfunding campaign. I've did some minor changes to our smart contract. In the
ContributeInput component, I have added two more properties, the contractAddress that we will interact with
and the current Ethereum account selected in MetaMask, and I've also passed these parameters from the
Campaign component to the campaignInteractionSection and then to the component itself. Okay, now to send
a transaction to our smart contract, we need to do a few things. So, first of all, we need to import the getWeb3
function. Then here we need to create an instance of Web3. And then, we already have a function called
onContribute. And to just remind you, this is a function that is called when a user clicks on the Contribute
button. At the moment, it just displays a message, but we can replace this with sending transaction to our smart
contract. And here is a full implementation in this function. The first thing that we do, we get the
contributionAmount that is specified in Ether because a user just inputs the amount in Ether and converts it to
Wei using the toWei function. Second, we estimate the amount of gas that we need to perform this transaction,
and we do this using the estimateGas function on web3. And finally, once we have the gasEstimate and the
amount to send in Wei, we call the sendTransaction method on the Web3. And notice that we don't need to use
the getContract function to get the Contract object to send a transaction to it as we did in the previous demo,
where we were trying to read data from the smart contract. This is because we're not calling any methods on the
smart contract, we're just sending a payment from the CurrentAccount to the contractAddress. We also specify
the amount we're going to send and the gasEstimate. In the final bit of this function, we subscribe to different
events that we can get from Web3. We'll get an event when we get the transaction hash, when we get a receipt,
and when we get a confirmation. Having this, we can go back to our application, specify the amount of Ether that
we want to contribute, click Contribute, and you will get a MetaMask notification that asks us to confirm this
transaction, and I'll click Confirm. I'll refresh the page, and as we can see, the Contributed amount changed from
0 to half an Ether, which is this amount in a Wei. And this wraps development of our decentralized application
that now has a smart contract backing it and the web front end that we've just developed.

Getting Contract Address


One thing that we have avoided so far is how the users get addresses for crowdfunding campaign contracts. At
the moment, users have to copy and paste contract addresses to the UI, which is definitely not a convenient
option. So, they're at least three different ways to solve this problem. Number one, we could use contract events
so every time we deploy a crowdfunding campaign and then a list of events to get a list of all available
campaigns. Second option is to store all addresses of all campaigns in a separate contract. We can have a new
contract that has two goals, deploy instances of crowdfunding campaigns and store addresses of created
campaigns that we could use later. And this approach is usually called a factory pattern. The last, but not the
least, we could use ENS. ENS is a decentralized application that allows to give human‑readable names to smart
contract addresses. So when someone deploys a crowdfunding campaign, we could register the address of this
campaign in ENS and then users can share human‑readable names from ENS instead of sharing raw addresses.

Summary
Congratulations, you finally reached the end of the course. And in this course, we went through quite a journey.
And in this last clip, I would like to sum up what we've learned in this course and in this module. So, we spent
most of the time learning about how to build decentralized applications, and decentralized applications have
quite a different architecture from regular applications. In the case of Ethereum, these applications run on top of
the Ethereum network. And Ethereum is a platform provided by a network of peers that provide infrastructure
for the network, but they cannot control the network itself. The underlying data structure that allows this is
called the blockchain. And a Blockchain is just a chain of blocks, every block contains a list of transactions that
were executed in this block, and it contains a reference to a previous block. This chain of references goes on
and on until it reaches the first block, that is called the genesis block. Ethereum works as an
application‑development platform based on top of the blockchain, and it allows to build various applications on
top of it. To execute code in Ethereum, we need to define and deploy smart contracts to the network. To interact
with the Ethereum network, we need to use the Web3 API. That allows us to read data from the network, deploy
smart contracts, send transactions, etc. This API is provided by Ethereum clients, and together, the network of
interconnected clients is what creates Ethereum network. Executable logic in Ethereum is provided in the form
of smart contracts. We write these smart contracts in different languages, such as Solidity and Vyper. But to
deploy a smart contract to the network, we first need to compile a smart contract into a bytecode using a
compiler for corresponding language, and then we can deploy a smart contract to any Ethereum network. In this
module, we've implemented a single‑page web application that interacts with a smart contract. It downloads
CSS and JavaScript resources from a web server and then interacts with the smart contract by sending
transactions to it and by reading data from it. To interact with an Ethereum network, we had to install the
MetaMask plugin. And this plugin provides a Provider object that is connected to an Ethereum network. This
provider was then utilized by the web3.js library used by our React components that we've implemented to build
the interface of our application. And that's it. Thank you for watching the course. However, I would like to ask you
for a small favor. If you've enjoyed the course, I would really appreciate if you could give it a good rating on
Pluralsight, share it with your friends, share it on social media, and let other people know about it. I also have
other Pluralsight courses that you might be interested in, so I encourage you to look at the Pluralsight library and
see if you can find something interesting there. You can also be notified when I release a new course. So if you
click on the Follow button on my Pluralsight Profile page, you won't miss any more of the good stuff. I hope that
you've enjoyed this course, and see you next time.

Course author
Ivan Mushketyk
Ivan is a Principal Software Engineer and a Tech Lead who is passionate about Big Data and Cloud
Computing. He has worked for numerous big IT companies including Samsung and Amazon Web Services.
He...

Course info
Level Intermediate
Rating  (29)
My rating 

Duration 5h 48m
Released 3 Nov 2022
Reviewed 31 Dec 2022

Share course
  

You might also like