Accounts
In Flow, each account has two areas:
Contract areas: where stores smart contract code and interface. Unlike the Ethereum blockchain, where smart contracts are deployed to separate accounts, many smart contracts could be stored in one account and even deployed simultaneously on the Flow blockchain. In addition, Flow also allows the owner of an account directly add, delete, or update contracts that reside in it.
Account storage: analogous to a traditional filesystem where objects are stored. Objects can be linked from a path, also known as capabilities, which include a domain and an identifier. There are three valid domains in account storage:
- /storage/: Since only the account owner can access this domain, this is the safe place to store resources (amazing features in Candence that can represent fungible tokens and NFTs).
- /private/: acts as a private API, only accessible by the account owner or accounts that have access rights. Capabilities that link to resources that are saved in /storage/ domain are stored here.
- /public/: account owners can link capabilities that point to their stored resources here so anyone else can interact with them.
Basic smart contracts
In the next part, let's explore how a simple smart contract is written in Cadence.
pub contract HelloWorld {
pub let greeting: String
init() {
self.greeting = "Hello, World!"
}
pub fun hello(): String {
return self.greeting
}
}
In the line of code above:
"pub" means public (can be accessible by anyone) - similar to the keyword "public" in Solidity.pub can replace by "access(all)".
"pub let greeting: String" declares a public state named "greeting" of type String.
"let" means constant (state cannot be changed after "init()"). If we want to declare a variable in Cadence, the "var" keyword must be used.
"init()" is the initializer -similar to "constructor()" in Solidity
"pub fun hello(): String" declares a public function called "hello" that returns a value of type String. In Cadence, if a function wants to return value, it must follow this syntax.
Also, if a contract wants to refer to its member functions and states, the keyword "self" should be used.
Overall, the above smart contract is similar to the line Solidity code below:
pragma solidity >=0.8.0;
contract HelloWorld{
string public greeting;
constructor()
{
greeting ="Hello world";
}
function hello() public view returns(string memory)
{
return greeting;
}
}
Transactions and scripts
In Flow, a transaction is a block of code that will interact with smart contracts, including reading or modifying the state of the blockchain. You have to pay a fee to execute a transaction.
This is an example of a simple transaction in Cadence.
import HelloWorld from 0x01
transaction {
prepare(acct: AuthAccount) {}
execute {
log(HelloWorld.hello())
}
}
To create a transaction, the "transaction" keyword must be used. In general, each transaction requires two phases:
- "prepare" phase: Only in this phase the account who signs the transaction can access or modify the /private/ and /storage/ domain of their account storage. To do these actions, "AuthAccount" types must be used. The reason is that "AuthAccount" objects have permission to access anywhere of the account storage and also have the right to create or destroy capabilities.
- "execute" phase: In this phase, the main logic of a transaction is executed, and you are no longer able to access your private resources stored in the account storage.
In addition, there are two more optional phases which are pre-phase and post-phase. They are used to verify some specific conditions before and after the transaction is executed, for example:
pre {
sendingAccount.balance > 0
//verify the balance of sendingAccount>0
}
In addition, there is a special type of transaction in Flow called script. It is used to just view data on the Flow Blockchain. You don't have to pay a fee to run a script. It's completely free.
A script must follow this "syntax pub fun main():returnType{}". For example:
import HelloWorld from 0x01
pub fun main() {
log(HelloWorld.hello()) //print “Hello world”
}
Resource
Definition and properties
The resource is one of the most powerful features of Cadence and the reason why it is called resource-oriented language. The resource is similar to a struct because it can have many fields or functions. However, it has some special properties:
- Resources can only exist in one place at one time. For example, if you have an NFT, it can only live in your account, and it can not live anywhere else. Then, if you transfer it to another account, it will be owned by that new account, and no longer live in your account
- Resources are not copiable. They can only be moved from one location to another location.
- When using a resource, you cannot leave it hanging in your code because Cadence will forbid you to do that. For example, if you pass a resource to a function, you have to either pass it to someone else or destroy it. A resource cannot be accidentally lost or deleted thanks to these properties.
With a lot of amazing properties, the resource is the perfect type to represent NFT in Cadence.
The below example is the syntax to declare a resource in Cadence.
pub resource HelloAsset {
pub fun hello(): String {
return "Hello, World!"
}
}
Resource with smart contract
Let's create a new contract HelloWorld. When initializing the contract, we will create a new resource, HelloAsset.
pub contract HelloWorld {
pub resource HelloAsset {
pub fun hello(): String {
return "Hello, World!"
}
}
init() {
let newHello <- create HelloAsset()
self.account.save(<-newHello, to: /storage/HelloAssetTutorial)
log("HelloAsset created and stored")
}
}
In Cadence, every resource must be created by the keyword "create".
The arrow "<-" indicates that we move the new HelloAsset resource into the constant named "newHello". You can not use "=" because the resource is uncopiable. You can only move it from one place to another. Remember that when working with the resource, you have to take some extra steps to make sure it is being handled properly otherwise, your code won't deploy. For example, if we remove this line:
self.account.save(<-newHello, to: /storage/HelloAssetTutorial)
you will see the error:
The reason is you leave the resource just dangling in the middle of "init()" without moving it anywhere or destroying it, which leads to the loss of resources. And Cadence will prevent you from deploying this contract.
So, in this case, we will save this resource to /storage/ domain in our account storage to fix the error.
Interact with a smart contract that has resources
Suppose we deploy the above contract to account 0x01, so only account 0x01 can directly access its resource. To allow other accounts in the network to interact with this contract, account 0x01 needs to create a public capability that point to its HelloAsset. For example
transaction {
prepare(account: AuthAccount) {
let capability = account.link<&HelloWorld.HelloAsset>(/public/HelloAssetTutorial, target: /storage/HelloAssetTutorial)
}
}
Remember that all the above actions must be done in the "prepare" block since, as mentioned before, only in prepare phase can AuthAccount object access our private objects in /storage/ domain and create links to them.
The below picture explains more detail about the above transaction:
Now, the link for the capability to HelloAsset of account 0x01 is stored in /public/ domain. That means other accounts in the network can get this capability (through "getCapability" method ) and use the capability's "borrow" method to create a new reference to the 0x01 account's HelloAsset resource:
import HelloWorld from 0x01
pub fun main() {
let helloAccount = getAccount(0x01)
let helloCapability = helloAccount.getCapability<&HelloWorld.HelloAsset>(/public/HelloAssetTutorial)
let helloReference = helloCapability.borrow()
?? panic("Could not borrow a reference to the hello capability")
}
That's all for basic concepts in Cadence. Most of the code in this writing is from Flow Playground, so if you find Cadence an interesting programming language and worth learning, you can explore more and more there.
References
[1] Flow Documentation, developers.flow.com, accessed 26th December 2022.
[2] Learn Cadence – Hello world on Flow, Flow Blockchain Youtube Channel, accessed 26th December 2022.