We’re going to build two applications:
- An on-chain one: a set of smart contracts deployed on Ethereum.
- An off-chain one: a front-end application that will interact with the smart contracts.
While the front-end application development is part of this book, it won’t be our main focus. We will build it solely to demonstrate how smart contracts are integrated with front-end applications. Thus, the front-end application is optional, but I’ll still provide the code.
Ethereum is a blockchain that allows anyone to run applications on it. It might look like a cloud provider, but there are multiple differences:
- You don’t pay for hosting your application. But you pay for deployment.
- Your application is immutable. That is: you won’t be able to modify it after it’s deployed.
- Users will pay to use your application.
To better understand these moments, let’s see what Ethereum is made of.
At the core of Ethereum (and any other blockchain) is a database. The most valuable data in Ethereum’s database is the state of accounts. An account is an Ethereum address with associated data:
- Balance: account’s ether balance.
- Code: bytecode of the smart contract deployed at this address.
- Storage: space used by smart contracts to store data.
- Nonce: a serial integer that’s used to protect against replay attacks.
Ethereum’s main job is building and maintaining this data in a secure way that doesn’t allow unauthorized access.
Ethereum is also a network, a network of computers that build and maintain the state independently of each other. The main goal of the network is to decentralize access to the database: there must be no single authority that’s allowed to modify anything in the database unilaterally. This is achieved through consensus, which is a set of rules all the nodes in the network follow. If one party decides to abuse a rule, it’ll be excluded from the network.
Fun fact: blockchain can use MySQL! Nothing prevents this besides performance. In its turn, Ethereum uses LevelDB, a fast key-value database.
Every Ethereum node also runs EVM, Ethereum Virtual Machine. A virtual machine is a program that can run other programs, and EVM is a program that executes smart contracts. Users interact with contracts through transactions: besides simply sending ether, transactions can contain smart contract call data. It includes:
- An encoded contract function name.
- Function parameters.
Transactions are packed in blocks and blocks are then mined by miners. Each participant in the network can validate any transaction and any block.
In a sense, smart contracts are similar to JSON APIs but instead of endpoints you call smart contract functions and you provide function arguments. Similar to API backends, smart contracts execute programmed logic, which can optionally modify smart contract storage. Unlike JSON API, you need to send a transaction to mutate the blockchain state, and you’ll need to pay for each transaction you’re sending.
Finally, Ethereum nodes expose a JSON-RPC API. Through this API we can interact with a node to: get account balance, estimate gas costs, get blocks and transactions, send transactions, and execute contract calls without sending transactions (this is used to read data from smart contracts). Here you can find the full list of available endpoints.
Transactions are also sent through the JSON-RPC API, see eth_sendTransaction.
Multiple smart contract development environments are used today:
Truffle is the oldest of the three and is the least popular of them. Hardhat is its improved descendant and is the most widely used tool. Foundry is the new kid on the block, which brings a different view on testing.
While HardHat is still a popular solution, more and more projects are switching to Foundry. And there are multiple reasons for that:
- Foundry doesn’t run a node during testing. This makes testing and iterating on features much faster! Truffle and HardHat start a node whenever you run tests; Foundry executes tests on an internal EVM.
That being said, we’ll use Foundry as our main smart contract development and testing tool.
Foundry is a set of tools for Ethereum applications development. Specifically, we’re going to use:
- Forge, a testing framework for Solidity.
- Anvil, a local Ethereum node designed for development with Forge. We’ll use it to deploy our contracts to a local node and connect to it through the front-end app.
- Cast, a CLI tool with a ton of helpful features.
Forge makes smart contracts developer’s life so much easier. With Forge, we don’t need to run a local node to test contracts. Instead, Forge runs tests on its internal EVM, which is much faster and doesn’t require sending transactions and mining blocks.
Forge lets us write tests in Solidity! Forge also makes it easier to simulate blockchain state: we can easily fake our ether or token balance, execute contracts from other addresses, deploy any contracts at any address, etc.
MetaMask is an Ethereum wallet in your browser. It’s a browser extension that creates and securely stores private keys. MetaMask is the main Ethereum wallet application used by millions of users. We’ll use it to sign transactions that we’ll send to our local node.
To set up the project, create a new folder and run
forge init in it:
$ mkdir uniswapv3clone
$ cd uniswapv3clone
$ forge init
If you’re using Visual Studio Code, add
forge init --vscode. Forge will initialize the project with VSCode-specific settings.
Forge will create sample contracts in the
script folders–these can be removed.
To set up the front-end application:
$ npx create-react-app ui
It’s located in a subfolder so there’s no conflict between folder names.