Building on Flow: 3 Com Issues and How to Solve Them
This past week we kicked off the first ever Fast Floward bootcamp. In week 1, we noticed three com issues bootcamp attendees encountered. In this post, we’ll discuss those issues and the solutions for each.
This past week has been a blast as our team at Decentology kicked off the first ever Fast Floward bootcamp. The bootcamp helps web2 developers learn about the basics and get started in the web3 (decentralized) world. In this 3 week long bootcamp we are focusing on Flow. In week 1, we noticed three com issues bootcamp attendees encountered. In this post, we’ll discuss those issues and the solutions for each.
a) destroy the resource if you no longer need it by using the destroy keyword, or...
b) move the resource to somewhere else, whether it be account storage, an array, dictionary, another resource, or anywhere where the resource can live after the function call/transaction has concluded.
Let’s take a look at an example here…
I have defined a simple contract that has a resource called Test, and a function called createTest that simply creates a Test resource and returns it to the caller. Let’s set up a transaction to call createTest…
Ah, look! We get a “loss of resource” error. But we know how to fix this. Let’s look at both methods a) and b) to solve this issue.
And remember: to move resources, you must use the move syntax (<-) to explicitly “move” the resource.
Issue #2: Unwrapping an Optional
The second most com issue participants have encountered has been removing a value from an optional type. In Cadence, an optional is declared using the ? syntax. For example, if we have: let x: Int?, this means x is either an Int or nil. A com error participants have encountered is something along the lines of, “expected Int, got Int?”. All this means is we haven’t “unwrapped” the Int from it’s optional yet.
Let’s take a look at an example using the contract from Issue 1, but now let’s add a function that returns the Test resource as an optional…
We can write a transaction that calls this function, but let’s purposefully try to get an error…
What went wrong? Well, we declared testResource as a HelloWorld.Test, but we received a HelloWorld.Test? because that’s what HelloWorld.createTestOptional() returns. How can we fix this? The answer is we can use the force-unwrap operator !, which will either return the value if it’s there, or nil. Let’s see how we can use it in our example…
As you can see, there is no longer an error about mismatched types. Hoorah!
Issue #3: Prepare Phase vs Execute Phase
Lastly, although not a big issue, it is important to address the difference between the prepare phase and the execute phase of a transaction. It is best practice to put the “setup” of a transaction in the prepare phase, and all the logic/functional components in the execute phase.
There are two main things that constitute the “setup” of a transaction:
Everything that has to do with the authorizers AuthAccount. This is required. The only way we can access the authorizer’s account storage is with the AuthAccount. Because we no longer have access to the AuthAccount in the execute phase, it is required that we borrow references from the AuthAccount’s account storage in the prepare phase. Similarly, if we want to load resources from storage, it must take place in the prepare phase as well.
Retrieving capabilities. Although not a requirement, it is usually best practice to get any capabilities from public accounts in the prepare phase and then use them in the execute phase. Let’s look at a quick example, assuming we are using the contract code defined in the playground example linked above:
Conclusion We’ve learned a lot as a community and are looking forward the next couple of weeks ahead. I hope this content is helpful as you learn more about web3, Flow, and Cadence. The best way to learn is by hitting errors and working through them. We’re excited to continue helping guide bootcamp attendees as they learn how to build on Flow.