Skip to main content
Version: 0.42

2. Hello World

In this tutorial, we'll write and deploy our first smart contract!

tip

Open the starter code for this tutorial in the Flow Playground:

https://play.onflow.org/af7aba31-dee9-4477-9e1d-7b46e958468e


The tutorial will ask you to take various actions to interact with this code.

warning

The playground code that is linked uses Cadence 0.42, but the examples use Cadence 1.0 to show how each contract, transaction and script is implemented Cadence 1.0. The link will still work with the current version of the playground, but when the playground is updated to Cadence 1.0, the link will be replaced with a 1.0-compatible version.

Action

Instructions that require you to take action are always included in a callout box like this one. These highlighted actions are all that you need to do to get your code running, but reading the rest is necessary to understand the language's design.

What is a smart contract?

In regular terms, a contract is an agreement between two parties for some exchange of information or assets. Normally, the terms of a contract are supervised and enforced by a trusted third party, such as a bank or a lawyer.

A smart contract is a computer program stored in a network like a blockchain that verifies and executes the performance of a contract (like a lawyer does) without the need for any trusted third party anywhere in the process, because the code itself is trusted.

Programs that run on blockchains are commonly referred to as smart contracts because they mediate important functionality (such as currency) without having to rely on a central authority (like a bank).

Cadence is the resource-oriented programming language for developing smart contracts on the Flow Blockchain.

This tutorial will walk you through an example of a smart contract that implements basic Cadence features, including accounts, transactions, and signers.

Our "Hello World" smart contract will:

  1. Create and initialize a smart contract with a single field of type String
  2. Initialize the field with the phrase "Hello, World!"
  3. Create a function in the contract that returns our greeting

We will deploy this contract in an account, then use a transaction to interact with the contract, and finally discuss the role of signers in the transaction.

How to Use Playground

For this tutorial, you'll be using the Flow Playground, an interactive web interface that lets you write and run smart contracts in a test environment. It also allows you to save and share your work with others so that you can test smart contracts collaboratively.

When you work with accounts in the Flow Playground, you start with five default accounts that you can change and reconfigure. Each account in your environment has a unique address, and you can select an account in the bottom left toolbar, which will open up the contracts that are saved for that account. The HelloWorld contracts are loaded by default for each account unless you load an existing playground project with other saved contracts.

For this tutorial, you'll be working with only the first account 0x01

Implementing Hello World


You will start by using a smart contract that contains a public function that returns "Hello World!".

Like most other blockchains, the programming model in Flow is centered around accounts and transactions. All state that persists permanently is stored in accounts and all accounts have the same core functionality. (users, smart contracts, data storage). This is unlike other blockchains like Ethereum where there are two types of accounts (smart contract accounts and user accounts).

The interfaces to this state (the ways to interact with it, otherwise known as methods or functions) are also stored in accounts. All code execution takes place within transactions, which are blocks of code that are authorized and submitted by external users to interact with the persistent state, which includes directly modifying account storage.

A smart contract is a collection of code (its functions) and data (its state) that lives in the contract area of an account in Flow. Each account can have zero or more contracts and/or contract interfaces. A contract can be freely added, removed, or updated (with some restrictions) by the owner of the account. Now let's look at the HelloWorld contract that you'll be working through in this tutorial.

Action

If you haven't already, you'll need to follow this link to open a playground session with the Hello World contracts, transactions, and scripts pre-loaded:

https://play.onflow.org/dbc06b40-d0b1-42da-9e0d-686bc9972e65

Playground Intro

Action

Open the Account 0x01 tab with the file called HelloWorld.cdc in the Contract 1 space.
HelloWorld.cdc should contain this code:

HelloWorld.cdc

_23
// HelloWorld.cdc
_23
//
_23
access(all)
_23
contract HelloWorld {
_23
_23
// Declare a public field of type String.
_23
//
_23
// All fields must be initialized in the initializer.
_23
access(all)
_23
let greeting: String
_23
_23
// The initializer is required if the contract contains any fields.
_23
init() {
_23
self.greeting = "Hello, World!"
_23
}
_23
_23
// Public function that returns our friendly greeting!
_23
// Specified as `view` to declare that it does not change any state
_23
access(all) view
_23
fun hello(): String {
_23
return self.greeting
_23
}
_23
}

The line access(all) contract HelloWorld declares a contract that is accessible in all scopes (access(all), typically known as public). It's followed by access(all) let greeting: String which declares a state constant (let) of type String that is accessible in all scopes(access(all)).

You would have used var to declare a variable, which means that the value can be changed later on instead of remaining constant like with let.

It is an access control specification that means an interface can be accessed in all scopes, but not written to in all scopes. For more information about the different levels of access control permitted in Cadence, refer to the Access Control section of the language reference.

The init() section is called the initializer. It is a special function that only runs when the contract is first created. Objects similar to contracts, such as other composite types like structs or resources, require that the initializer initializes all fields that are declared in a composite type. In the above example, the initializer sets the greeting field to "Hello, World!" when the contract is initialized.

The last part of our HelloWorld contract is a public function called hello(). This declaration returns a value of type String. The view keyword means that it is a function that only reads state and does not modify anything. Anyone who imports this contract in their transaction or script can read the public fields, use the public types, and call the public contract functions; i.e. the ones that have access(all) specified.

Soon you'll deploy this contract to your account and run a transaction that calls its function, but first, let's look at what accounts and transactions are.

Accounts and Transactions


What is an Account?

Each user has an account controlled by one or more private keys with configurable weight. This means that support for accounts/wallets with multiple controllers is built into the protocol by default.

An account is divided into two main areas:

  1. The first area is the contract area. This is the area that stores smart contracts containing type definitions, fields, and functions that relate to common functionality. There is no limit to the number of smart contracts an account can store. This area cannot be directly accessed in a transaction unless the transaction is just returning (reading) a copy of the code deployed to an account. The owner of an account can directly add, remove, or update/overwrite contracts that are stored in it.

  2. The second area is the account storage. This area is where an account stores the objects that they own. This is an important differentiator between Cadence and other languages, because in other languages, assets that accounts own is always stored in the centralized smart contract that defines the assets. In Cadence, each account stores its assets as objects directly in its own account storage. The account storage section also stores code that declares the capabilities for controlling how these stored objects can be accessed. We'll cover account storage in more detail in a later tutorial.

In this tutorial, we use the account with the address 0x01 to store our HelloWorld contract. Outside the Playground context, account addresses on Flow are completely unique.

Deploying Code


Now that you know what an account is in a Cadence context, you can deploy the HelloWorld contract to your account.

Action

Make sure that the account 0x01 tab is selected and that the HelloWorld.cdc file is in the editor.
Click the deploy button to deploy the contents of the editor to account 0x01.

Deploy Contract

You should see a log in the output area indicating that the deployment succeeded.

Deployed Contract To: 0x01

You'll also see the name of the contract show up in the selected account tab underneath the number for the account. This indicates that the HelloWorld contract has been deployed to the account. You can always look at this tab to verify which contracts are in which accounts. In the Flow Playground environment there can be any number of contracts for each account. To create an additional contract, either open up one of the other ones or click the plus (+) button next to the contracts section in the playground.

Creating a Transaction


A Transaction in Flow is defined as an arbitrary-sized block of Cadence code that is authorized by one or more accounts. When an account authorizes a transaction, the code in that transaction has access to the authorizers' private storage. An account authorizes a transaction by performing a cryptographic signature on the transaction with the account's private key, which should only be accessible to the account owner. Therefore, authorizers are also known as signers. In addition to being able to access the authorizer's private assets, transactions can also read and call functions in public contracts, and access public domains in other users' accounts. For this tutorial, we use a transaction to call our hello() function.

Action

Open the transaction named Simple Transaction
Simple Transaction should contain this code:

SayHello.cdc

_10
import HelloWorld from 0x01
_10
_10
transaction {
_10
_10
prepare(acct: &Account) {}
_10
_10
execute {
_10
log(HelloWorld.hello())
_10
}
_10
}

This transaction first imports our HelloWorld smart contract from the account 0x01. If you haven't deployed the smart contract from the account, the transaction won't have access to it and the import will fail. This imports the entire contract code from HelloWorld, including type definitions and public functions, so that the transaction can use them to interact with the HelloWorld contract in account 0x01.

To import a smart contract from any other account, type this line at the top of your transaction:


_10
// Replace {ContractName} with the name of the contract you want to import
_10
// and {Address} with the account you want to import it from
_10
import {ContractName} from {Address}

Transactions are divided into two main phases, prepare and execute.

  1. The prepare phase is required but we don't use it in this tutorial. We'll cover this phase in a later tutorial.
  2. The execute phase is the main body of a transaction. It can call functions on external contracts and objects and perform operations on data that was initialized in the transaction. In this example, the execute phase calls HelloWorld.hello() which calls the hello() function in the HelloWorld contract and logs the result(log(HelloWorld.hello())) to the console.
Action

In the box at the bottom right of the editor, select Account 0x01 as the transaction signer.
Click the Send button to submit the transaction

You should see something like this in the transaction results at the bottom of the screen:


_10
Simple Transaction "Hello, World!"

Congratulations, you just executed your first Cadence transaction with the account 0x01 as the signer.

In this tutorial, you'll get the same result if you use different signers for the transaction but later tutorials will use more complex examples that have different results depending on the signer.

Reviewing HelloWorld

This tutorial covered an introduction to Cadence, including terms like accounts, transactions, and signers. We implemented a smart contract that is accessible in all scopes. The smart contract had a String field initialized with the value Hello, World! and a function to return (read) this value. Next, we deployed this contract in an account and implemented a transaction to call the function in the smart contract and log the result to the console. Finally, we used the account 0x01 as the signer for this transaction.

Now that you have completed the tutorial, you have the basic knowledge to write a simple Cadence program that can:

  • Deploy a basic smart contract in an account
  • Interact with the smart contract using a transaction
  • Sign the transaction with one or multiple signers

Feel free to modify the smart contract to implement different functions, experiment with the available Cadence types, and write new transactions that execute multiple functions from your HelloWorld smart contract.