How to build a Blockchain App on Flow Blockchain?

build flow app

CryptoKitties, one of the first NFT projects, brought Ethereum to a halt in late 2017 because of immense congestion. Due to this, the developers at the Dapper Labs team realized that the current blockchains were not designed to manage the huge demand.

Instead of finding an alternative for the decentralized app or waiting for Ethereum solutions to mature, Dapper decided to develop a blockchain that other developers could depend on. As a result, they came up with a blockchain platform, Flow, a purpose-built platform to support items like large-scale crypto games and NFT collectibles.

The Flow Blockchain Platform launched in 2020 enables developers to create and trade a specific type of digital asset known as non-fungible tokens. We shall discuss how to create a blockchain app on the Flow platform.

Let’s first understand what is Flow blockchain platform?

What is Flow? 

Flow is a blockchain platform designed for extensive scaling without using sharding techniques, offering low-cost and fast transactions for dApps such as crypto-based video games and NFT marketplaces.

Flow is the Dapper Lab’s product which is the company behind the CryptoKitties blockchain game. Founders decided to solve the blockchain congestion problem by building a platform for games and interactive experiences.

Based on a multi-role architecture, Flow empowers developers to build crypto-enabled businesses. Applications built on Flow allow consumers to control their data, create digital assets and develop open economies owned by users.

Smart contracts written on Flow are assembled like Lego blocks to run apps serving billions of people, from businesses to basketball fans with mission-critical requirements.

How does Flow work?

Flow leverages a proof-of-stake model that enables validators to stake a specific number of FLOW tokens to participate in the network. But, it has a unique validation method as Flow divides validation tasks into four different types of nodes: consensus, execution, collection and verification. All the nodes participate in the validation of each transaction.

  • Consensus Nodes
    They decide the order of transactions and presence on the blockchain.
  • Collection Nodes
    They improve data connectivity and network connectivity for dApps.
  • Verification Nodes
    They are responsible for checking execution nodes.
  • Execution Nodes
    They execute the computation associated with each transaction.

Splitting up tasks makes the processing of transactions more efficient. It also features upgradable smart contracts, enabling smart contracts to be deployed in beta and then improved or fixed before made immutable and being finalized.

Consensus and verification nodes are the layers of security in the Flow network and utilize crypto-economic incentives to hold the network accountable. These validators can optimize for decentralization and security.

On the other hand, collection and execution nodes perform fully deterministic tasks, making them less vulnerable to attack.

Now, let’s understand how to build an app on the Flow blockchain platform.

How to build a blockchain app using the Flow platform?

This section will explain how to develop an app that interacts with the Flow blockchain platform using @onflow/fcl. Flow client library (FCL) allows applications to integrate with all FCL-compatible wallets and other services. It provides developers with a strong foundation to compose their apps with existing building blocks. With FCL, you can:

  • Authenticate users
  • Send transactions
  • Query the Flow blockchain
  • Sign transactions via wallet integration
  • Integrate all compatible wallets without any custom code

We are using create-react-app and the app we are developing does not require any server-side code. Let’s understand the entire step-by-step process.

Step 1: Create React App and Other Dependencies

Run the following commands to start a new FCL project:

yarn create react-app my-apps

cd my-apps

yarn add @onflow/fcl @onflow/types

@onflow/fcl is the FCL’s latest build. @onflow/types is a conversion layer between Cadence and Javascript. They are used when we need to pass JavaScript into Cadence scripts and transactions.

Step 2: Configuration

It is a good practice to use environment variables for configuration. It will allow you to modify environments easily. We will then have to pass environment variables to FCL before it interacts with anything else. We will create two files: ./src/config.js and ./.env.local to hold environment variables locally and import and supply them to FCL.

touch .env.local # Create a .env.local file to store our environment variables

touch ./src/config.js # Create a ./src/config.js file where we will import our environment variables and configure FCL

Once we have our files, the next step is to add them to environment variables. Open .env.local and add the following to it:

// File: ./src/config.js

import {config} from “@onflow/fcl”

config()

.put(“accessNode.api”, process.env.REACT_APP_ACCESS_NODE)

.put(“challenge.handshake”, process.env.REACT_APP_WALLET_DISCOVERY)

.put(“0xProfile”, process.env.REACT_APP_CONTRACT_PROFILE)

Now, we have a file that configures FCL but it is not being invoked yet. Therefore, FCL still remains unconfigured in the app. In this section, the final step is to import the file as the first thing.

Open ./src/index.js and add the below code as the first line:

// File: ./src/index.js import “./config”

import React from “react”

import ReactDOM from “react-dom”

The FCL is configured, which is the first step to have a dApp built on Flow (Testnet) platform.

Step 3: Authentication

The application that we are building already has authentication. We got authentication when we configured the challenge.handshake value.  This configuration implies everything it needs to know to authenticate users on Flow with FCL compatible wallets.

Let’s understand how to interact with the current user by learning about:

  • How to log in
  • How to log out
  • How to sign up

We will get to know about them by developing a React component that will show a Log Out button and the user’s Flow address when they are authenticated. But the Sign Up and Log In buttons will show up when they are unauthenticated.

Now, we will call the component AuthCluster and it will go live at /src/auth-cluster.js. Below is the code to do the same:

// File: ./src/auth-cluster.js

import React, {useState, useEffect} from “react”

import * as fcl from “@onflow/fcl”

export function AuthCluster() {

const [user, setUser] = useState({loggedIn: null})

useEffect(() => fcl.currentUser().subscribe(setUser), [])

if (user.loggedIn) {

return (

<div>

<span>{user?.addr ?? “No Address”}</span>

<button onClick={fcl.unauthenticate}>Log Out</button>

</div>

)

} else {

return (

<div>

<button onClick={fcl.logIn}>Log In</button>

<button onClick={fcl.signUp}>Sign Up</button>

</div>

)

}

}

Let’s understand the functionalities of the following functions:

  • fcl.currentUser().subscribe(setUser)
    FCL uses the actor model, using which we can subscribe to things. For example, in this scenario, when the user changes from being unauthenticated to authenticated.fcl.currentUser() returns the current user actor and what we can do with a current user is to subscribe to its state while passing a callback function. It means if the state of the current user changes anytime, the user’s current state will be invoked with the callback.It is invoked as soon as we subscribe, but due to React’s useEffect and useState work, we need to give some default values.
  • fcl.unauthenticate()
    It is a function that is an alias to fcl.currentUser().unauthenticate() that will trigger the unauthenticated sequence inside the Current User Actor.
  • fcl.logIn() and fcl.signUp()
    Both of these functions are alias to fcl.currentUser().authenticate(). If a user wants to login and sign up on the wallets, these components will trigger and users will have to authenticate themselves again.

Using AuthCluster

We should import and add AuthCluster to the application in ./src/App.js We need to replace ./src/App.js to look like the below code:

// File: ./src/Auth.js

import React from “react”

import {AuthCluster} from “./auth-cluster”

export default function App() {

return (

<div> <AuthCluster /> </div>

)

}

Step 4: Ensuring if the Flow Account is initialized with the profile contract

Not every Flow account has a profile. However, if you are new to Flow and your account does not have a profile, we need to check if the account is initialized. We will start by creating a directory for Flow transactions and scripts.

We will call the directory flow, name the scripts with *.script.js and transactions with *.tx.js. The first script will check if an account with a particular supplied address is initialized with a profile.

mkdir ./src/flow

touch ./src/flow/is-initialized.script.js

The profile smart contract reveals a helper function that allows us to check if the address is initialized Profile.check(address) and returns a boolean value. Let’s use it in the new file ./src/flow/is-initialized.script.js.

// File: ./src/flow/is-initialized.script.js

import * as fcl from “@onflow/fcl”

import * as t from “@onflow/types”

export async function isInitialized(address) {

if (address == null)

throw new Error(“isInitialized(address) — address required”)

return fcl

.send([

fcl.script`

import Profile from 0xProfile

pub fun main(address: Address): Bool {

return Profile.check(address)

}

`,

fcl.args([fcl.arg(address, t.Address)]),

])

.then(fcl.decode)

}

You must have noticed that something new was introduced in the above file. We have used 0xProfile instead of 0xba1132bc08f82fe2  in the import statement. It is something that we added in the configuration step (config().put(“0xProfile”, “0xba1132bc08f82fe2”)).

It implies that when we use FCL, the configuration allows us to fetch the corresponding address from any configuration value where the key starts with 0x.

So, all you need to do is update environment variables to reflect the new environment and the code does not need to be changed.

Now, we have a re-usable script to ensure whether the account is initialized or not.

Step 5: Initialize an account with a profile

Initializing an account with a profile requires a transaction. Transactions are quite similar to scripts. You need a transaction when you have to change the state of the Flow blockchain permanently. It involves some cost and a Flow account has to propose the change and when you need the permission of the state owner, you are modifying.

These three aspects are known as the payer, the proposer and authorizers. The current user needs to authorize its participation.

fcl.currentUser() contains an authorization function that is used for authorizing the participation. You will need this function multiple times in a transaction. So, we can alias it to fcl.authz.

Transactions also need a computation limit and its value will be associated with the cost to the payer of the transaction.

Now, we will create a ./src/flow/init-account.tx.js file with the following transaction to initialize the account:

// File: ./src/flow/init-account.tx.js

import * as fcl from “@onflow/fcl”

import * as t from “@onflow/types”

export async function initAccount() {

const txId = await fcl

.send([

fcl.transaction`

import Profile from 0xProfile transaction {

let address: Address

prepare(account: AuthAccount) {

self.address = account.address

if (!Profile.check(self.address)) {

account.save(<- Profile.new(), to: Profile.privatePath)

account.link<&Profile.Base{Profile.Public}>(Profile.publicPath, target: Profile.privatePath)

}

}

post {

Profile.check(self.address): “Account was not initialized”

}

} `,

fcl.payer(fcl.authz),

fcl.proposer(fcl.authz),

fcl.authorizations([fcl.authz]),

fcl.limit(35),

])

.then(fcl.decode)

return fcl.tx(txId).onceSealed()

}

Now, we can call the function to initialize the current user’s account with a profile.

Step 6: Updating Profile

Updating information in a profile is a transaction.

A transaction ./src/flow/profile-set-name.tx.js borrows a resource from the AuthAccount and performs an action on the resource. It is usual to borrow a public capability from another account and utilize something from the borrowed resource. For example, sending FLOW tokens to someone else.

The AuthAccount borrows its vault resource and draws out a temporary Vault resource. The transaction will then borrow the public capability from the FLOW tokens recipient that can get the temporary FLOW token vault.

The transaction to update the name in the profile is quite smaller than the initialization transaction we have seen. The owner of a resource in storage has the right to borrow it directly and set up the Profile.Owner interface. Therefore, the only owner can set the name on the resource.

Everyone else can interact with this resource via the linked public capability that has a restricted Profile.Public interface.

// File: ./src/flow/profile-set-name.tx.js

import * as fcl from “@onflow/fcl”

import * as t from “@onflow/types”

export async function setName(name) {

const txId = await fcl

.send([

fcl.proposer(fcl.authz),

fcl.payer(fcl.authz),

fcl.authorizations([fcl.authz]),

fcl.limit(35),

fcl.args([fcl.arg(name, t.String)]),

fcl.transaction`

import Profile from 0xProfile

transaction(name: String) {

prepare(account: AuthAccount) {

account

.borrow<&Profile.Base{Profile.Owner}>(from: Profile.privatePath)!

.setName(name)

}

}

`,

])

.then(fcl.decode)

return fcl.tx(txId).onceSealed()

}

Mentioned above is a function to update the user’s name in the profile.

Step 7: Deployment 

Once we have all the files with their functionalities, they will interact with the Flow blockchain differently. To ensure that the application is ready for Mainnet, the first step is to ensure that the smart contracts you are using are present.

Presently, the Flow team approves smart contracts that get deployed, which will go away shortly. Then, it is important to update all environment variables. There will be new values of environment variables for all 3 of them:

  • REACT_APP_ACCESS_NODE
  • REACT_APP_WALLET_DISCOVERY
  • REACT_APP_CONTRACT_PROFILE

Hopefully, your application should be now working on the mainnet.

Flow Client Library allows us to create cross-platform dApps and is the foundation for a new generation of digital assets and gaming apps. With a wide range of SDKs available for different programming languages, Flow has become one of the top blockchain platforms to decentralize the business ecosystems.

At LeewayHertz, our team of blockchain developers has also started creating POCs for blockchain apps on the Flow blockchain that can scale without sharding.

 

Author’s Bio

Akash Takyar
Akash Takyar
CEO LeewayHertz
Akash Takyar is the founder and CEO at LeewayHertz. With the experience of building over 100+ platforms for startups and enterprise allows Akash to rapidly architect and design solutions that are scalable and beautiful.
Akash's ability to build enterprise-grade technology solutions has attracted over 30 Fortune 500 companies, including Siemens, 3M, P&G and Hershey’s. Akash is an early adopter of new technology, a passionate technology enthusiast, and an investor in AI and IoT startups.

Start a conversation by filling the form

Once you let us know your requirement, our technical expert will schedule a call and discuss your idea in detail post sign of an NDA.

All information will be kept confidential.

 Send me the signed Non-Disclosure Agreement (NDA)