Build your first DApp on Tezos in 2-4 hours

Published 25 days ago

✨ DEMO ✨

Introduction

What is Tezos? Tezos is a blockchain network that supports formally verified smart contracts and has a unique governance feature where token holders can vote on-chain on protocol upgrades. These upgrades allow Tezos to evolve forklessly and in a decentralized manner.

What are Smart Contracts? These are small and readable programs that run on the blockchain and can transfer funds based on their logic.

What are DApps?. Distributed Applications are web applications that run in the browser and interact with smart contracts through blockchain nodes.

For this tutorial we will program a simple Hello World application: a good old-fashioned guestbook. It has only entries, authors and timestamps and consists of 1 smart contract.

Tooling

Note: the Tezos tooling ecosystem is rather decentralized, this means that there are usually several teams building different tools serving a similar purpose. Here I will suggest the ones that have worked for me, but bear in mind that there often exist equally good alternatives.

To deploy the contract to the testnet, we need to interact with a node. For this we will use tezos-client. Unofficial prebuilt binaries are found here, for e.g. macOS:
$ brew tap serokell/tezos-packaging https://github.com/serokell/tezos-packaging.git 
$ brew install tezos-client
We will be using this cli client often, lets create an alias for your shell with RPC parameters for tezos-client:
alias mainnet='tezos-client --endpoint https://mainnet-tezos.giganode.io/'
alias testnet='tezos-client --endpoint https://testnet-tezos.giganode.io/'
Create an account (will be stored under ~/.tezos-client):
$ tezos-client gen keys myAccount
$ tezos-client list known addresses
We need testnet funds. There are some free faucets, I recommend this Telegram Bot. When funds arrive, check the balance:
$ testnet get balance for myAccount

Smart Contract

There are several choices of tools you can find on the official Develper Portal, for this tutorial we will use SmartPy, a Python-based language.

Install SmartPy:
$ sh <(curl -s https://smartpy.io/cli/install.sh)
Create a guestbook.py file:
import smartpy as sp

class Guestbook(sp.Contract):
    def __init__(self):
        self.init(
            dates = sp.list([]),
            entries = sp.list([]),
            authors = sp.list([])
        )

    @sp.entry_point
    def add_entry(self, params):
        self.data.dates.push(sp.now)
        self.data.entries.push(params.e)
        self.data.authors.push(params.a)

# Tests
@sp.add_test(name = "Guestbook")
def test1():
    scenario = sp.test_scenario()
    scenario.h1("Welcome to Guestbook")
    c1 = Guestbook()
    scenario += c1
    scenario += c1.add_entry(a = 'alice', e = 'hello from alice')
    scenario += c1.add_entry(a = 'bob', e = 'hello from bob')
    scenario += c1.add_entry(a = 'charles', e = 'hello from charles')
The contract file has one default entrypoint and the contract's storage has three lists. To compile it, we call:
$ ~/smartpy-cli/SmartPy.sh test guestbook.py output

The output folder now contains Michelson code, the native stack-based language of smart contracts on Tezos, as well as the output of the tests.

Deploy the generated tz file (Tip: use --dry-run to simulate first):
$ testnet originate contract guestbook transferring 0 from myAccount \
running output/Guestbook/step_001_cont_0_contract.tz \
--force --fee 0.001 --init "Pair {} (Pair {} {})" --burn-cap 0.125

Listing contracts with testnet list known contracts should show the guestbook contract.

Call the contract to add an entry:
$ testnet call guestbook from myAccount \
--arg '(Pair "alice" "hi from alice")' \
--burn-cap 0.0085
Inspect your contract's KT address on Better Call Dev to see the operations.

Web Application

Make a web app with your favourite frontend framework. You need a library to communicate with the RPCs of a node, Taquito is commonly used. You also need a wallet, I recommend the Metamask-like Temple Wallet.

Install dependencies:

$ yarn add @taquito/taquito @taquito/beacon-wallet

Read the storage of the contract:

import { TezosToolkit } from '@taquito/taquito'
const contractAddress = 'KT1...'
const Tezos = new TezosToolkit('https://edonet-tezos.giganode.io')
const contract = await Tezos.contract.at(contractAddress)
const storage = await this.contract.storage()
// storage should now have "hi from alice"
Send a new operation with the help of our wallet extension:
import { BeaconWallet } from '@taquito/beacon-wallet'
const wallet = new BeaconWallet({
  name: 'Tezos Guestbook'
})
await wallet.requestPermissions({
  network: {
    type: 'edonet'
  }
})
Tezos.setProvider({ wallet })
const contract = await Tezos.wallet.at(contractAddress)
const operation = await (contract.methods.default(
  // parameter order should match the entrypoint in the smart contract
  author,
  message
).send())
const opResult = await operation.confirmation()
if (opResult.completed) {
  // Fetch the contract storage again to see the new entry
} else {
  // An error has occurred
}

Conclusion

DApps usually consist of several smart contracts that interact with each other, but simpler ones could consist of just one. In this tutorial we explored how to build a Hello World variant of a DApp.

Try it out with your idea and see for yourself how reasonably easy it is. I can not compare with Solidity, as I have not used it.

To me it seems the Tezos ecosystem has matured: it supports multiple high-level smart contract languages, there are several choices for libraries, frameworks and wallets. There are already interesting DApps in the DeFi and NFT spaces: Dexter, Kolibri, HicEtNunc, to name a few.

The complete code of the DApp is available on Github.

A PDF of this article has been minted as a 10-edition NFT that you can collect: https://www.hicetnunc.xyz/objkt/23525


You might need to refresh this page a few times for the Discus comments section to appear below.