<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andrea Muttoni</title>
    <description>The latest articles on DEV Community by Andrea Muttoni (@muttoni).</description>
    <link>https://dev.to/muttoni</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F863854%2F408a4404-6706-4f78-b375-ac31a2995a73.png</url>
      <title>DEV Community: Andrea Muttoni</title>
      <link>https://dev.to/muttoni</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/muttoni"/>
    <language>en</language>
    <item>
      <title>Let's build a Twitter clone on Web3 - A Comprehensive Guide to Building on Flow</title>
      <dc:creator>Andrea Muttoni</dc:creator>
      <pubDate>Fri, 02 Dec 2022 17:46:45 +0000</pubDate>
      <link>https://dev.to/muttoni/lets-build-a-twitter-clone-on-web3-a-comprehensive-guide-to-building-on-flow-24l9</link>
      <guid>https://dev.to/muttoni/lets-build-a-twitter-clone-on-web3-a-comprehensive-guide-to-building-on-flow-24l9</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this guide, we’ll be building a Web3 version of Twitter. By the end of it, you should have an understanding of what building “on Web3” means, how to write smart contracts that go beyond the typical JPEG NFT example, and hopefully walk away with inspiration and ideas on what &lt;em&gt;you&lt;/em&gt; can build next. &lt;/p&gt;

&lt;p&gt;You know that inspirational quote: "It's not the destination, it's the journey"?  While the finished product is a &lt;em&gt;&lt;a href=""&gt;reductio ad absurdum&lt;/a&gt;&lt;/em&gt; of a real Twitter app, the process along the way is what I want you to focus on. That is, building on-chain logic on a blockchain using smart contracts is relatively simple, and is a general purpose technology. My hope is that it helps cut through the hype and speculation, and shows you how the components work, so you can re-apply them to new use-cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is this tutorial for me?
&lt;/h3&gt;

&lt;p&gt;I had two choices when writing this: either start from a finished demo and explain how it works, or bring you along as I create the app from scratch and iterate over it and add complexity bit by bit. I've opted for the latter. &lt;/p&gt;

&lt;p&gt;In other words, this is not a quick tutorial (&lt;a href="https://developers.flow.com/tools/fcl-js/tutorials/flow-app-quickstart" rel="noopener noreferrer"&gt;here's one though&lt;/a&gt;), it's a somewhat comprehensive step-by-step guide meant to be followed in an afternoon or weekend.&lt;/p&gt;

&lt;p&gt;Does that sound good to you? Great, let's dive in!&lt;/p&gt;

&lt;h3&gt;
  
  
  Wait...What &lt;em&gt;is&lt;/em&gt; web3?
&lt;/h3&gt;

&lt;p&gt;Let's start with the elephant in the room. &lt;em&gt;Web3&lt;/em&gt;. What is it? You’ll likely get a different answer from everyone you ask. What follows is &lt;em&gt;a&lt;/em&gt; definition, which is by no means exhaustive or prescriptive. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Web3 is a way to build experiences in a way that they benefit from composability and decentralization. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Composability means anyone can build on top of any existing experience. In “web2”, the classic way to offer composability is via APIs, and while APIs are great, they need to be built, maintained and are a conscious choice. In Web3, the smart contracts are open to all, and they themselves &lt;em&gt;are the APIs&lt;/em&gt;. Even more importantly: every app built using smart contracts is effectively a “module” that you can import into your own app. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In traditional tech stacks, the libraries and packages are composable (think npm modules) - in web3, the &lt;em&gt;applications&lt;/em&gt; are composable (think Twitter). That's the paradigm shift.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Practically, it means that when we deploy our Twitter clone to mainnet (the "live" production chain), anyone else can build experiences on top of it – not just UIs, but higher-order experiences such as games and extended functionality (e.g. Rate-my-tweet or Tweet tipping, etc)&lt;/p&gt;

&lt;p&gt;Likewise, Web3’s decentralized nature means we can rest easy knowing no single entity (or billionaire) has the power to override our platform, both at the infrastructure level (the servers that run the code), as well as the content itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Flow?
&lt;/h2&gt;

&lt;p&gt;When building a web3 application, the “tech stack” is usually composed of a traditional tech stack (e.g. servers, frontend frameworks, databases, etc), as well as a web3-specific stack that allows us to interact with a blockchain (cli's, client libraries, wallets).&lt;/p&gt;

&lt;p&gt;Like all tech stacks, there’s no right or wrong tool for the job - just different ones, and each come with their unique characteristics. It really depends on what &lt;em&gt;you&lt;/em&gt; believe are the most important factors. I recommend you follow this guide regardless of what blockchain you think is best, and then try to implement this same guide on your favorite blockchain as a challenge!&lt;/p&gt;

&lt;p&gt;In this guide, we’ll be building a Twitter clone using the Flow blockchain. The main reasons behind choosing Flow are: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Flow is used by some of the most mainstream web3 applications, like NBA Top Shot, Instagram and YouTube.&lt;/li&gt;
&lt;li&gt;When it comes to smart contracts, Cadence (Flow’s native smart contract programming language) is a safer, more readable language than Solidity or Rust, and features a resource-oriented paradigm that makes working with digital assets a lot more intuitive (i.e. you can’t lose or duplicate things accidentally like you can on other chains)&lt;/li&gt;
&lt;li&gt;Flow has a very intuitive account model whereby digital assets are stored in the respective accounts that own them - not centralized in a key/value map in the smart contract like Ethereum. This distributed ownership and improves performance and security.&lt;/li&gt;
&lt;li&gt;Flow has extremely low fees, which are usually subsidized by the wallets, meaning it’s effectively free to build and transact. Perfect for creating a bustling social network!&lt;/li&gt;
&lt;li&gt;Thanks to its scalability, storage is really cheap on Flow, meaning we can build it entirely on-chain. More on that later!&lt;/li&gt;
&lt;li&gt;Most importantly: Flow was built and designed from the ground up for composability and writing complex applications powered by smart contracts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Read more about Flow &lt;a href="https://flow.com/primer" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What we’re going to build
&lt;/h3&gt;

&lt;p&gt;In this guide we’ll build a simplified version of Twitter. We'll start basic, and progressively enhance it. This will minimize the cognitive load, and help focus on novel concepts before we introduce additional abstractions/complexity.&lt;/p&gt;

&lt;h4&gt;
  
  
  What we'll cover
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Part 1 - Smart Contracts

&lt;ul&gt;
&lt;li&gt;Learn Cadence basics by writing a smart contract (3 times!)&lt;/li&gt;
&lt;li&gt;Interact with the smart contract using scripts and transactions (i.e. reading and mutating the chain)&lt;/li&gt;
&lt;li&gt;Learn how to use the Flow Playground&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Part 2 - Building an web app &amp;amp; Tooling

&lt;ul&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Flow Client Library&lt;/li&gt;
&lt;li&gt;Connect the smart contract to a simple web app in React/NextJS&lt;/li&gt;
&lt;li&gt;Develop locally using the Flow Emulator&lt;/li&gt;
&lt;li&gt;Learn about the Flow CLI and Dev Wallet&lt;/li&gt;
&lt;li&gt;Learn how to run scripts &amp;amp; transactions on the Flow CLI&lt;/li&gt;
&lt;li&gt;Deploying to testnet&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Let's dive in, shall we?&lt;/p&gt;

&lt;h2&gt;
  
  
  Smart Contract v0 - A &lt;em&gt;Very&lt;/em&gt; Basic Example: A single Tweet.
&lt;/h2&gt;

&lt;p&gt;Given that most devs are familiar with a typical web stack, we'll start with the new interesting bit first - the smart contract. Writing smart contracts usually involves interacting with the chain via commands and CLIs. We'll definitely do that, but first, we'll start our journey in the &lt;a href="https://play.flow.com" rel="noopener noreferrer"&gt;Flow Playground&lt;/a&gt;, where the chain is emulated and abstracted away for the most part, so we can focus mainly on the smart contract logic. &lt;/p&gt;

&lt;h3&gt;
  
  
  Our first smart contract in Cadence
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 What is Cadence? &lt;a href="https://developers.flow.com/cadence" rel="noopener noreferrer"&gt;Cadence&lt;/a&gt; is Flow’s native smart contract programming language. As mentioned earlier, Cadence is a safe, powerful language, and features a resource-oriented paradigm that makes working with digital assets a lot more intuitive (i.e. you can’t lose or duplicate things accidentally like you could on other chains). You might think - "Oh no, a new language I need to learn". Don't worry, it's actually quite easy to grasp, and if you're at all used to TypeScript or Swift, you'll find it's very familiar.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This very first iteration of the contract only allows to create and store a single tweet. Not exciting, I know, but it gives me a chance to explain some fundamentals before we start introducing more complexity.&lt;/p&gt;

&lt;p&gt;Before explaining what it does, try to read the code below line by line and see if you can make sense of it with out ANY context at all. I'll wait. (And yes, you are allowed to read the comments)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Twitter-v0.cdc
//

pub contract Twitter {

    // Declare the Tweet resource type
    pub resource Tweet {
        // The unique ID that differentiates each Tweet
        pub let id: UInt64

        // String mapping to hold metadata
        pub var metadata: {String: String}

        // Initialize both fields in the init function
        init(message: String) {
            self.id = self.uuid
            self.metadata = {
                "message": message
            }
        }
    }

    // Function to create a new Tweet
    pub fun createTweet(_ message: String): @Tweet {
        return &amp;lt;-create Tweet(message: message)
    }

    // Create a single new Tweet and save it to account storage
    init() {
        self.account.save&amp;lt;@Tweet&amp;gt;(&amp;lt;- self.createTweet("My first tweet!"), to: /storage/TwitterPath)
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok, let's dissect it bit by bit.&lt;/p&gt;

&lt;h4&gt;
  
  
  Contract
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;contract&lt;/span&gt; &lt;span class="kt"&gt;Twitter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this line, we created a contract. We gave it the name "Twitter" because a contract is essentially a program that lives on the blockchain. Within a contract, functions and properties can exist. We can also import other contracts and use &lt;em&gt;their&lt;/em&gt; functions and properties within our own contract, making them extremely composable. In our case, our Twitter contract will be the main contract of our application.&lt;/p&gt;

&lt;p&gt;You'll see towards the end of the contract that there's a &lt;code&gt;init()&lt;/code&gt; function. When the contract is deployed (i.e. saved on the chain somewhere), it will be initialized and the init function will be called once.&lt;/p&gt;

&lt;h4&gt;
  
  
  Resources
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="kt"&gt;Tweet&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most other blockchains have what's called a central ledger. Basically a &lt;code&gt;{key: value}&lt;/code&gt; map property within the smart contract that keeps track of all the state. This means if anyone (malicious or not) has access to the contract, they can change that map however they like and modify the global state. Cadence has something called resources, which are special objects that are stored in users' own accounts. Anything can be a resource (e.g. NFTs), and resources benefit from the resource ownership rules that are enforced by the type system, that is: resources can only have a single owner, they cannot be duplicated, and they cannot be lost due to accidental or malicious programming errors. These protections ensure that unique digital assets, whether Tweets or NFTs, or whatever else, can be safely represented on Flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// The unique ID that differentiates each Tweet
pub let id: UInt64

// String mapping to hold metadata
pub var metadata: {String: String}

// Initialize both fields in the init function
init(message: String) {
    self.id = self.uuid
    self.metadata = {
        "message": message
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A resource is similar to a contract in that it can contain properties, functions, including the lifecycle &lt;code&gt;init&lt;/code&gt; function, which will be called when the resource is created.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 All composite types like contracts, resources, and structs can have an optional init() function that only runs when the object is initially created. Cadence requires that all fields must be explicitly initialized, so if the object has any fields, this function has to be used to initialize them. &lt;a href="https://developers.flow.com/cadence/tutorial/03-resources" rel="noopener noreferrer"&gt;Source&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In our case, the Tweet resource type has 2 properties: &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;metadata&lt;/code&gt;. These are &lt;em&gt;completely arbitrary&lt;/em&gt;. It just makes sense to give a unique resource an id, and the metadata object is a blank object that we can fill with whatever we need. &lt;/p&gt;

&lt;p&gt;On Flow, all resources have a unique id automatically assigned to them, i.e. &lt;a href="https://developers.flow.com/cadence/language/resources#resource-identifier" rel="noopener noreferrer"&gt;a &lt;code&gt;uuid&lt;/code&gt; property&lt;/a&gt;, that in this case we are using to set the "official" ID of our Tweet. This ensures uniqueness. We could also create our ID from scratch, or use an incrementing counter, but &lt;code&gt;uuid&lt;/code&gt; is generally recommended (at least IMHO!). &lt;/p&gt;

&lt;p&gt;When we create the resource we're going to pass in an argument called message, which we will use to populate the metadata object with a key called message. Here's this exact process in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Function to create a new Tweet
pub fun createTweet(_ message: String): @Tweet {
    return &amp;lt;-create Tweet(message: message)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this snippet, which belongs within the Twitter contract, is a function that creates a new Tweet. The Twitter contract is so basic that we don't even need it, as we only call it once in the &lt;code&gt;init&lt;/code&gt;, but it shows you how to create a function. What's more interesting is what happens inside of it. You see we &lt;code&gt;create&lt;/code&gt; a new Tweet resource (resources have to be explicityly &lt;code&gt;create&lt;/code&gt;d or &lt;code&gt;destroy&lt;/code&gt;ed with the respective keywords), or moved (read on!)&lt;/p&gt;

&lt;p&gt;There's also bunch of weird symbols &lt;code&gt;_&lt;/code&gt;, &lt;code&gt;@&lt;/code&gt;, &lt;code&gt;&amp;lt;-&lt;/code&gt;. Let's see what they do in order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;_&lt;/code&gt;: just means it's the default argument, so we don't need to add a "message" label when we create the Tweet.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@&lt;/code&gt;: what comes after the colon in the function definition is the expected return type. In this case the @ symbol means it's a resource.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;-&lt;/code&gt;: looks like an arrow right? It is! The move operator in Cadence, through which resources are passed around the execution state. Before the transaction ends the resource must be stored somewhere or destroyed otherwise Cadence will throw an error. More on that later.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;👍 If you find any more weird symbols, just look them up in the &lt;strong&gt;&lt;a href="https://developers.flow.com/cadence/language/glossary" rel="noopener noreferrer"&gt;Glossary&lt;/a&gt;&lt;/strong&gt; (Fun fact: I contributed the first version of that Glossary when I started building on Flow because I also was confused by all the symbols!).&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Create a single new Tweet and save it to account storage&lt;/span&gt;
&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kd"&gt;@Tweet&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTweet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"My first tweet!"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/storage/&lt;/span&gt;&lt;span class="kt"&gt;TwitterPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we get to the contract's own &lt;code&gt;init&lt;/code&gt; method. Within it, the contract creates a Tweet upon initialization, containing the message "My first tweet!" and stores it within the account in a custom path called &lt;code&gt;TwitterPath&lt;/code&gt;. Think of account storage a bit like directories, we need to create our custom "folder" within which to save our resource. These names should be unique. Read more about Cadence's &lt;a href="https://developers.flow.com/cadence/language/accounts#account-storage" rel="noopener noreferrer"&gt;Account Storage&lt;/a&gt; and &lt;a href="https://developers.flow.com/learn/concepts/storage" rel="noopener noreferrer"&gt;storing data&lt;/a&gt; on Flow.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 If you want to dive a little deeper into Cadence and Flow's account-based ownership read these posts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://flow.com/post/resources-programming-ownership" rel="noopener noreferrer"&gt;https://flow.com/post/resources-programming-ownership&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://flow.com/post/flow-blockchain-cadence-programming-language-resources-assets" rel="noopener noreferrer"&gt;https://flow.com/post/flow-blockchain-cadence-programming-language-resources-assets&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Flow Playground - Deploying and interacting with our contract
&lt;/h3&gt;

&lt;p&gt;Looking at code is cool, but running it is even cooler. Let's now interact with the contract. To do that, we'll use the Flow Playground. Click on the image or the link below to go to the live Playground example. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://play.flow.com/c1ab866b-c71d-41af-a832-29d89434cc50?type=account&amp;amp;id=d8b423b1-2051-47f3-964c-61a5634a7667&amp;amp;storage=0x01" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frfvt1e2jyco5ngd28pp5.png" width="800" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://play.flow.com/c1ab866b-c71d-41af-a832-29d89434cc50?type=account&amp;amp;id=d8b423b1-2051-47f3-964c-61a5634a7667&amp;amp;storage=0x01" rel="noopener noreferrer"&gt;👉 Click me to view in Playground&lt;/a&gt;
&lt;/h4&gt;




&lt;ol&gt;
&lt;li&gt;Click on &lt;code&gt;0x01&lt;/code&gt; and &lt;code&gt;Deploy&lt;/code&gt; the contract in the top right.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frcqxfvjmwgd3x7imxn4f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frcqxfvjmwgd3x7imxn4f.png" width="596" height="148"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Once you deploy the contract you should see a confirmation like the following. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62rnwvi3brgvog3pf8d5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62rnwvi3brgvog3pf8d5.png" width="762" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What did we do? We deployed the contract to the emulated chain to the &lt;code&gt;0x01&lt;/code&gt; account. This means the contract is now "running" on that account and can be called from other accounts or imported into other smart contracts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt;: the playground is an &lt;strong&gt;emulator&lt;/strong&gt;, this means it's self-contained. If we wanted other real users to interact with it, we would need to deploy this to testnet or mainnet. We'll get to that, don't worry!&lt;/p&gt;

&lt;p&gt;Now let's "see" the resource we created. Click on the database icon on the right of &lt;code&gt;0x01&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frigc7zdnljgwe67lrrfg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frigc7zdnljgwe67lrrfg.png" width="488" height="188"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A popup should appear like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frpettnfnmhiztsd9uel7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frpettnfnmhiztsd9uel7.png" width="800" height="146"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the full JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Fields": [
    38,
    38,
    {
      "DictionaryType": {
        "ElementType": {},
        "KeyType": {}
      },
      "Pairs": [
        {
          "Key": "message",
          "Value": "My first tweet!"
        }
      ]
    }
  ],
  "ResourceType": {
    "Fields": [
      {
        "Identifier": "uuid",
        "Type": {}
      },
      {
        "Identifier": "id",
        "Type": {}
      },
      {
        "Identifier": "metadata",
        "Type": {
          "ElementType": {},
          "KeyType": {}
        }
      }
    ],
    "Initializers": null,
    "Location": {
      "Address": "0x0000000000000005",
      "Name": "Twitter",
      "Type": "AddressLocation"
    },
    "QualifiedIdentifier": "Twitter.Tweet"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing too crazy right? It's just a very verbose JSON object, containing the properties we expect of our resource. &lt;/p&gt;

&lt;h4&gt;
  
  
  Running a Transactions
&lt;/h4&gt;

&lt;p&gt;If you click on the first Transaction "Check if Tweet exists"&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjji4jx06xi842wucv0bw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjji4jx06xi842wucv0bw.png" width="490" height="182"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In general, Transactions are signed and they &lt;strong&gt;mutate&lt;/strong&gt; the chain, whereas Scripts only &lt;strong&gt;read&lt;/strong&gt; the chain, meaning they can have no side-effect on the chain itself.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Think of &lt;strong&gt;transactions&lt;/strong&gt; like authorized &lt;code&gt;POST&lt;/code&gt; requests, and &lt;strong&gt;scripts&lt;/strong&gt; like unauthorized &lt;code&gt;GET&lt;/code&gt; requests to a traditional backend.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8azixj70wkup4ryh6k9b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8azixj70wkup4ryh6k9b.png" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our case, we will run a transaction to look within our own contract and check that the Tweet resource exists. &lt;/p&gt;

&lt;p&gt;Click on "Send". &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4y7x98dx505jh5ild2h6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4y7x98dx505jh5ild2h6.png" width="792" height="162"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should see "Tweet exists" in the transaction results.&lt;/p&gt;
&lt;h4&gt;
  
  
  Tweet again or die tryin'
&lt;/h4&gt;

&lt;p&gt;Let's try to create a new Tweet, just to show you why it's not possible with our current contract.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fddxpgb78waz3eaw61iak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fddxpgb78waz3eaw61iak.png" width="492" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's a second transaction called "Create new Tweet". Here's the code for it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// (try to) Create new tweet

import Twitter from 0x01

// This transaction checks if a tweet exists in the storage of the given account
// by trying to borrow from it. If the borrow succeeds (returns a non-nil value), the token exists!
transaction {
    prepare(acct: AuthAccount) {
        acct.save&amp;lt;@Twitter.Tweet&amp;gt;(&amp;lt;-Twitter.createTweet("This is my second tweet"), to: /storage/TwitterPath)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you try to run this transaction, which is more or less identical to the code in the contract's &lt;code&gt;init&lt;/code&gt; function, we'll get an error:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1tebqgguzwdxatpjuh19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1tebqgguzwdxatpjuh19.png" width="800" height="27"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can infer from the error, when we initialized the contract, we stored our first Tweet resource in a location (&lt;code&gt;TwitterPath&lt;/code&gt;), and now that location cannot be re-used for another Tweet, as it would overwrite the other Tweet. Dang! How do we fix this? We'll cover this in the next section :) &lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Let's recap: in this section we created a super basic contract to showcase some initial key features of Cadence, and we interacted with the code in the Flow Playground, an emulated environment that abstracts away a lot of the complexity like wallets. &lt;/p&gt;

&lt;p&gt;Despite having started with a very basic example, it's a LOT to cover. So don't worry if you still don't get all of it. I've purposely created this tutorial in phases, so that at every phase, we will cover old ground and will help you &lt;em&gt;get&lt;/em&gt; it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smart Contract v1 - Basic Example: Multiple Tweets
&lt;/h2&gt;

&lt;p&gt;Alright, we've covered the &lt;em&gt;super&lt;/em&gt; basic example, now let's start going a bit deeper in the Cadence rabbit hole and introduce some new concepts. &lt;/p&gt;

&lt;p&gt;First off, let's fix one of the biggest, glaring issues with our first iteration of the Twitter contract: it only saves 1 tweet 😅&lt;/p&gt;

&lt;p&gt;Something cool about resources is that &lt;strong&gt;resources can contain other resources&lt;/strong&gt;. On Flow resources that are made to contain the same type of something are most commonly called &lt;strong&gt;Collections&lt;/strong&gt;. Collections are none other than a resource that we create that will be responsible for storing other resources (our Tweets). That way, rather than storing a single Tweet in our Twitter storage path, we will create and store a collection resource, and the collection will expose  dedicated methods to write/read/remove resources (Tweets) contained within. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👉 Fun fact: on Flow, NFT projects use collections to allow accounts to store multiple NFTs of the same project within their accounts. A completely on-chain &lt;a href="https://www.flow-nft-catalog.com/" rel="noopener noreferrer"&gt;NFT Catalogue&lt;/a&gt; helps ensure other dapps like Marketplaces or wallets know what collection (and location) to search for when trying to load a specific projects' NFTs. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Adding a Collection Resource
&lt;/h3&gt;

&lt;p&gt;In this section we will do the &lt;em&gt;bare-minimum&lt;/em&gt; to get a collection working. We'll significantly enhance it later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Twitter-v1.cdc
// Still basic, but with multiple tweets!

pub contract Twitter {

    // Declare a Path constant so we don't need to harcode in tx
    pub let TweetCollectionStoragePath: StoragePath

    // Declare the Tweet resource type - nothing changed here!
    pub resource Tweet {
        // The unique ID that differentiates each Tweet
        pub let id: UInt64

        // String mapping to hold metadata
        pub var metadata: {String: String}

        // Initialize both fields in the init function
        init(message: String) {
            self.id = self.uuid
            self.metadata = {
                "message": message
            }
        }
    }

    // Function to create a new Tweet
    pub fun createTweet(_ message: String): @Tweet {
        return &amp;lt;-create Tweet(message: message)
    }

    // NEW! 
    // Declare a Collection resource that contains Tweets.
    // it does so via `saveTweet()`, 
    // and stores them in `self.tweets`
    pub resource Collection {
        // an object containing the tweets
        pub var tweets: @{UInt64: Tweet}

        // a method to save a tweet in the collection
        pub fun saveTweet(tweet: @Tweet) {
            // add the new tweet to the dictionary with 
            // a force assignment (check glossary!)
            // If there were to be a value at that key, 
            // it would fail/revert. 
            self.tweets[tweet.id] &amp;lt;-! tweet
        }

        // get all the id's of the tweets in the collection
        pub fun getIDs(): [UInt64] {
            return self.tweets.keys
        }

        init() {
            self.tweets &amp;lt;- {}
        }

        destroy() {
            // when the Colletion resource is destroyed, 
            // we need to explicitly destroy the tweets too.
            destroy self.tweets
        }
    }

    // create a new collection
    pub fun createEmptyCollection(): @Collection {
        return &amp;lt;- create Collection()
    }

    init() {
        // assign the storage path to /storage/TweetCollection
        self.TweetCollectionStoragePath = /storage/TweetCollection
        // save the empty collection to the storage path
        self.account.save(&amp;lt;-self.createEmptyCollection(), to: self.TweetCollectionStoragePath)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break down what changed. Here's the diff to make it easier to spot the differences. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcksoewp2i7nnh9jjj7b6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcksoewp2i7nnh9jjj7b6.png" width="800" height="674"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What you'll notice is the &lt;code&gt;Tweet&lt;/code&gt; resource and &lt;code&gt;createTweet&lt;/code&gt; function have not changed. Here are the changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a Path constant (line 7) - by defining it, we won't have to hard code it in our transactions and scripts.&lt;/li&gt;
&lt;li&gt;a new &lt;code&gt;Collection&lt;/code&gt; resource (lines 26-56) along with a &lt;code&gt;createEmptyCollection()&lt;/code&gt; function to create a new (empty) collection.&lt;/li&gt;
&lt;li&gt;changed the &lt;code&gt;init()&lt;/code&gt;, to assign the newly created Path constant, and then make use of it in the next line where we create a new collection and save it in the account.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's a couple new things on the Cadence side here:&lt;/p&gt;

&lt;h5&gt;
  
  
  Collection
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="kt"&gt;Collection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// an object containing the tweets&lt;/span&gt;
    &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;tweets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;UInt64&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Tweet&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Collection resource contains a &lt;a href="https://developers.flow.com/cadence/language/resources#resources-in-arrays-and-dictionaries" rel="noopener noreferrer"&gt;dictionary of Resources&lt;/a&gt; called &lt;code&gt;tweets&lt;/code&gt; (identified by the &lt;code&gt;@{...}&lt;/code&gt;). In our case, the keys are the Tweet IDs, and the values are the Tweet resources. &lt;/p&gt;

&lt;p&gt;Now let's how we populate that dictionary.&lt;/p&gt;

&lt;h5&gt;
  
  
  Modifying a resource dictionary
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// a method to save a tweet in the collection
pub fun saveTweet(tweet: @Tweet) {
    // add the new tweet to the dictionary with 
    // a force assignment (check glossary!)
    // If there were to be a value at that key, 
    // it would fail/revert. 
    self.tweets[tweet.id] &amp;lt;-! tweet
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function called &lt;code&gt;saveTweet&lt;/code&gt;, expects a Tweet resource and saves it in the resource dictionary. You'll notice a weird exclamation mark (!) next to the move (&amp;lt;-) operator. This is called a &lt;a href="https://developers.flow.com/cadence/language/glossary#--lower-than-hyphen-exclamation-mark-force-assignment-move-operator" rel="noopener noreferrer"&gt;force-assignment move operator&lt;/a&gt; which assigns a resource to an &lt;a href="https://developers.flow.com/cadence/language/values-and-types#optionals" rel="noopener noreferrer"&gt;optional variable&lt;/a&gt;. The result of a dictionary read is optional, as the given key might not exist in the dictionary. In this case, we actually &lt;em&gt;need&lt;/em&gt; it to be nil, otherwise the force-assignment will fail.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 Don't worry, you'll get a hand for optionals as we go through the course. Also, when you see question marks in transaction code, you're likely looking at &lt;a href="https://developers.flow.com/cadence/language/composite-types#accessing-fields-and-functions-of-composite-types-using-optional-chaining" rel="noopener noreferrer"&gt;optional chaining&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's move to the second half of the Collection resource:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
    // get all the id's of the tweets in the collection
    pub fun getIDs(): [UInt64] {
        return self.tweets.keys
    }

    init() {
        self.tweets &amp;lt;- {}
    }

    destroy() {
        // when the Colletion resource is destroyed, 
        // we need to explicitly destroy the tweets too.
        destroy self.tweets
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;getIDs()&lt;/code&gt; uses a built-in property of dictionaries/maps in Cadence to return all the keys. You guessed it: it's &lt;code&gt;.keys&lt;/code&gt;. We'll use this function later to check how many tweets are saved in the account when we interact with the contract.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;init&lt;/code&gt; method we simply initialize tweets to be an empty resource dictionary.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;destroy&lt;/code&gt; method is new. If the Collection resource is destroyed with the destroy command, it needs to know what to do with the resources it stores in the dictionary. This is why resources that store other resources have to include a destroy function that runs when destroy is called on it. This destroy function has to either explicitly destroy the contained resources or move them somewhere else. In this example, we destroy them.&lt;/p&gt;

&lt;h4&gt;
  
  
  Updated Contract init function
&lt;/h4&gt;

&lt;p&gt;As mentioned above, in the init function we assign and make use of our new Path constant. Rather than creating a tweet right off the bat, we create a new collection, and we'll create Tweets using transactions in just a second!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// assign the storage path to /storage/TweetCollection&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;TweetCollectionStoragePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/storage/&lt;/span&gt;&lt;span class="kt"&gt;TweetCollection&lt;/span&gt;
    &lt;span class="c1"&gt;// save the empty collection to the storage path&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createEmptyCollection&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;TweetCollectionStoragePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alright, with the contract explained, let's play!&lt;/p&gt;




&lt;h3&gt;
  
  
  Flow Playground - Deploying and interacting with the new contract
&lt;/h3&gt;

&lt;p&gt;Let's interact with the new and improved contract. We'll of course jump back to the Flow playground, but with a new link. Click on the image or the link below to go to the updated live playground example. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://play.flow.com/95ea4027-2d75-4204-999d-c4de30083af3?type=account&amp;amp;id=67bbd568-3be9-407b-a1e1-ce03d1a705b7&amp;amp;storage=0x01" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqs68yno8od97fkdmemju.png" width="800" height="565"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://play.flow.com/95ea4027-2d75-4204-999d-c4de30083af3?type=account&amp;amp;id=67bbd568-3be9-407b-a1e1-ce03d1a705b7&amp;amp;storage=0x01" rel="noopener noreferrer"&gt;👉 Click me to go to the Playground Example&lt;/a&gt;
&lt;/h4&gt;

&lt;h4&gt;
  
  
  Creating Tweets
&lt;/h4&gt;

&lt;p&gt;Rather than creating a Tweet automatically in the contract initialization step, now we'll purely create them through a transaction. What's more, is that our transaction will accept an argument with will be the message of the Tweet. &lt;/p&gt;

&lt;p&gt;You can view the transaction code by clickin gon "Create new Tweet" in the Transaction templates of the Playground.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgu3sy8z9hssg4buyuz98.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgu3sy8z9hssg4buyuz98.png" width="245" height="127"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the code if you're lazy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Create new Tweet&lt;/span&gt;

&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Twitter&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="mh"&gt;0x01&lt;/span&gt;

&lt;span class="c1"&gt;// This transaction creates a new tweet with an argument&lt;/span&gt;
&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Let's check that the account has a collection&lt;/span&gt;
    &lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;acct&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;AuthAccount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;acct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;borrow&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="kt"&gt;Twitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Twitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;TweetCollectionStoragePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Collection exists!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// let's create the collection if it doesn't exist&lt;/span&gt;
            &lt;span class="n"&gt;acct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kd"&gt;@Twitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="kt"&gt;Twitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createEmptyCollection&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Twitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;TweetCollectionStoragePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// borrow the collection&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;acct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;borrow&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="kt"&gt;Twitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Twitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;TweetCollectionStoragePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// call the collection's saveTweet method and pass in a Tweet resource&lt;/span&gt;
        &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveTweet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;tweet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="kt"&gt;Twitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTweet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Tweet created successfully, with message "&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Right off the bat, differently from our previous transaction where we attempted to create a second tweet (which failed), this new transaction accepts an argument, called &lt;code&gt;message&lt;/code&gt;. We'll pass that argument to the &lt;code&gt;createTweet&lt;/code&gt; function. &lt;/p&gt;

&lt;p&gt;You notice we &lt;em&gt;only&lt;/em&gt; interact with the Collection resource now, and the collection resource will be responsible for managing the tweets contained within it. &lt;/p&gt;

&lt;p&gt;If we were to break up the transaction into rough logic chunks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check if collection exists in account running transaction

&lt;ul&gt;
&lt;li&gt;If collection exists, log "collection exists" (just fyi)&lt;/li&gt;
&lt;li&gt;If collection does NOT exist, create one in that account&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Borrow the collection to call saveTweet, and pass in a newly created Tweet using the createTweet function. &lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;You may be asking yourself - wait - why are we checking for a collection if we automatically create one when we initalize the contract? Well, because that only happens on the account where the contract is deployed to. &lt;em&gt;Other&lt;/em&gt; accounts can interact with the contract and create their own tweets. So if &lt;em&gt;any other&lt;/em&gt; account wants to create a Tweet, they first need a collection. So we must always check for a collection to be present whenever we are creating/saving a Tweet inside someones account. &lt;/p&gt;

&lt;p&gt;Let's create our first Tweet:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftcw6qcf5r5i8bfjcxk42.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftcw6qcf5r5i8bfjcxk42.png" width="327" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should see: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcuz8rvjxqtw9nxkx4qo7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcuz8rvjxqtw9nxkx4qo7.png" width="673" height="99"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's create our second one:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfyj8uvvqhp5fj0odgmb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfyj8uvvqhp5fj0odgmb.png" width="342" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should see:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo040hhf42n249nwgruz1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo040hhf42n249nwgruz1.png" width="678" height="153"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Counting Tweets in an Account
&lt;/h4&gt;

&lt;p&gt;Now to double check, let's run a second transaction. You'll find it right under the first one in the Playground template. &lt;code&gt;Get tweets&lt;/code&gt; which calls the Collection's &lt;code&gt;getIDs&lt;/code&gt; method. It will the length of the array that is returned by &lt;code&gt;getIDs&lt;/code&gt; all the Tweet IDs contained in the collection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Get tweets&lt;/span&gt;

&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Twitter&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="mh"&gt;0x01&lt;/span&gt;

&lt;span class="c1"&gt;// This transaction retrieves all Tweets&lt;/span&gt;
&lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Let's check that the account has a collection&lt;/span&gt;
    &lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;acct&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;AuthAccount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;acct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;borrow&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="kt"&gt;Twitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Twitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;TweetCollectionStoragePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nf"&gt;log&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getIDs&lt;/span&gt;&lt;span class="p"&gt;()?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nf"&gt;log&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Collection does not exist"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run it, you should get the following output: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5rmn4gtwzmxqftjiejko.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5rmn4gtwzmxqftjiejko.png" width="222" height="25"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: the number may vary if you created more than 2 tweets!&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating tweets with another account
&lt;/h4&gt;

&lt;p&gt;Now want to see something cool?&lt;/p&gt;

&lt;p&gt;Rather than running the &lt;code&gt;Create new Tweet&lt;/code&gt; with &lt;code&gt;0x01&lt;/code&gt;, try selecting any other account (e.g. &lt;code&gt;0x02&lt;/code&gt;) as the signer. You'll see it doesn't log "Collection exists", as it will create the collection and then create the tweet successfully. Now &lt;code&gt;0x02&lt;/code&gt; has a Tweet Collection! Yay.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fatyg1umpwjq29irc5oqf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fatyg1umpwjq29irc5oqf.png" width="310" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary &amp;amp; Limitations with our current implementation
&lt;/h3&gt;

&lt;p&gt;Great, our contracts now supports a collection and we can now create multiple tweets. &lt;strong&gt;However&lt;/strong&gt;, other accounts can't read tweets from any other accounts but themselves. This is because we are working with storage directly, which only the owning account has access to. &lt;/p&gt;

&lt;p&gt;How do we get access to other accounts' tweets? The bad news is we need to upgrade our contract (AGAIN). The good news is we get to learn some cool new Cadence features! What we need to do is to start creating &lt;a href="https://developers.flow.com/cadence/language/capability-based-access-control" rel="noopener noreferrer"&gt;public capabilities&lt;/a&gt;. Capability-based access control is one of Cadence's most powerful features and will regulate access rights outside of the contract and owning account. In our case, we want to be able to read tweets from other accounts, but not create tweets on behalf of other accounts. &lt;/p&gt;

&lt;p&gt;This will also be a great opportunity to introduce the concept of interfaces. Let's get to it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Smart Contract v2 - Less Basic: Letting other people view our tweets
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Interfaces and Capabilities
&lt;/h3&gt;

&lt;p&gt;To allow other accounts (or scripts, which are essentially un-authenticated requests) to access our tweets, we need to do two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an public-facing &lt;strong&gt;&lt;a href="https://developers.flow.com/cadence/language/interfaces" rel="noopener noreferrer"&gt;interface&lt;/a&gt;&lt;/strong&gt; that our Collection resource will conform to&lt;/li&gt;
&lt;li&gt;Create a &lt;strong&gt;&lt;a href="https://developers.flow.com/cadence/language/capability-based-access-control" rel="noopener noreferrer"&gt;capability&lt;/a&gt;&lt;/strong&gt; to access the Collection through the public-facing interface&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's tackle these in order. Here's a formal definition from the docs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 &lt;strong&gt;&lt;a href="https://developers.flow.com/cadence/language/interfaces" rel="noopener noreferrer"&gt;Interfaces&lt;/a&gt;&lt;/strong&gt;: An interface is an abstract type that specifies the behavior of types that implement the interface. Interfaces declare the required functions and fields, the access control for those declarations, and preconditions and postconditions that implementing types need to provide. &lt;br&gt;
There are three kinds of interfaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structure interfaces: implemented by structures&lt;/li&gt;
&lt;li&gt;Resource interfaces: implemented by resources&lt;/li&gt;
&lt;li&gt;Contract interfaces: implemented by contracts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📖 &lt;strong&gt;&lt;a href="https://developers.flow.com/cadence/language/capability-based-access-control" rel="noopener noreferrer"&gt;Capabilities&lt;/a&gt;&lt;/strong&gt;: if an account wants to be able to access another account's stored objects, it must have a valid capability to that object. Capabilities are identified by a path and link to a target path, not directly to an object. Capabilities are either public (any user can get access), or private (access to/from the authorized user is necessary). Public capabilities are created using public paths, i.e. they have the domain public. After creation they can be obtained from both authorized accounts (AuthAccount) and public accounts (PublicAccount).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's easier to explain by showing you the code, so if it's still confusing, keep on reading!&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating the contract with interfaces and capabilities
&lt;/h3&gt;

&lt;p&gt;Here's the new contract code. Scroll down for a diff and we'll cover each change bit by bit!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Twitter-v2.cdc
// Still basic, but with multiple tweets (and capabilities!)

pub contract Twitter {

    // Declare a Path constant so we don't need to harcode in tx
    pub let TweetCollectionStoragePath: StoragePath
    pub let TweetCollectionPublicPath: PublicPath

    // Declare the Tweet resource type - nothing changed here!
    pub resource Tweet {
        // The unique ID that differentiates each Tweet
        pub let id: UInt64

        // String mapping to hold metadata
        pub var metadata: {String: String}

        // Initialize both fields in the init function
        init(message: String) {
            self.id = self.uuid
            self.metadata = {
                "message": message
            }
        }
    }

    // Function to create a new Tweet
    pub fun createTweet(_ message: String): @Tweet {
        return &amp;lt;-create Tweet(message: message)
    }

    pub resource interface CollectionPublic {
        pub fun getIDs(): [UInt64]
        pub fun borrowTweet(id: UInt64): &amp;amp;Tweet? 
    }

    // NEW! 
    // Declare a Collection resource that contains Tweets.
    // it does so via `saveTweet()`, 
    // and stores them in `self.tweets`
    pub resource Collection: CollectionPublic {
        // an object containing the tweets
        pub var tweets: @{UInt64: Tweet}

        // a method to save a tweet in the collection
        pub fun saveTweet(tweet: @Tweet) {
            // add the new tweet to the dictionary with 
            // a force assignment (check glossary!)
            // If there were to be a value at that key, 
            // it would fail/revert. 
            self.tweets[tweet.id] &amp;lt;-! tweet
        }

        // get all the id's of the tweets in the collection
        pub fun getIDs(): [UInt64] {
            return self.tweets.keys
        }

        pub fun borrowTweet(id: UInt64): &amp;amp;Tweet? {
            if self.tweets[id] != nil {
                let ref = (&amp;amp;self.tweets[id] as &amp;amp;Twitter.Tweet?)!
                return ref
            }
            return nil
        }

        init() {
            self.tweets &amp;lt;- {}
        }

        destroy() {
            // when the Colletion resource is destroyed, 
            // we need to explicitly destroy the tweets too.
            destroy self.tweets
        }
    }

    // create a new collection
    pub fun createEmptyCollection(): @Collection {
        return &amp;lt;- create Collection()
    }

    init() {
        // assign the storage path to /storage/TweetCollection
        self.TweetCollectionStoragePath = /storage/TweetCollection
        self.TweetCollectionPublicPath = /public/TweetCollection
        // save the empty collection to the storage path
        self.account.save(&amp;lt;-self.createEmptyCollection(), to: self.TweetCollectionStoragePath)
        // publish a reference to the Collection in storage
        self.account.link&amp;lt;&amp;amp;{CollectionPublic}&amp;gt;(self.TweetCollectionPublicPath, target: self.TweetCollectionStoragePath)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Diff
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fooyfhiavbc839mwinjiq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fooyfhiavbc839mwinjiq.png" width="800" height="629"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll notice, not too much has changed. Here's what I added:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Added a new Path constant called &lt;code&gt;TweetCollectionPublicPath&lt;/code&gt;, that we will reference later to expose the Collection publically.&lt;/li&gt;
&lt;li&gt;Added a new resource interface &lt;code&gt;Collection Public&lt;/code&gt;, which I then assign to the &lt;code&gt;Collection&lt;/code&gt; resource.&lt;/li&gt;
&lt;li&gt;Created a new method &lt;code&gt;borrowTweet&lt;/code&gt; in the Collection that returns a reference to the Tweet based on a Tweet ID. &lt;/li&gt;
&lt;li&gt;Updated the contract &lt;code&gt;init()&lt;/code&gt; function to 

&lt;ul&gt;
&lt;li&gt; initialize the new Path constant above&lt;/li&gt;
&lt;li&gt; save a capability to access the collection within the scope of the Collection Public interface.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  Public Collection Interface
&lt;/h4&gt;

&lt;p&gt;Let's start with the &lt;code&gt;Collection Public&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pub resource interface CollectionPublic {
    pub fun getIDs(): [UInt64]
    pub fun borrowTweet(id: UInt64): &amp;amp;Tweet? 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we're doing here is describing a restricted version of the Collection that is for public consumption. As you can see, the only two methods included in this interface are &lt;code&gt;getIDs&lt;/code&gt; and &lt;code&gt;borrowTweet&lt;/code&gt; (a new method which we still need to look at - soon!).&lt;/p&gt;

&lt;p&gt;How do we ensure that our Collection conforms to this interface? By adding it to the Collection declaration similar to how we add types to variables.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pub resource Collection: CollectionPublic {&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Resources can implement multiple interfaces. You should see interfaces in two ways:&lt;br&gt;
1) ensure a minimum set of functionality is implemented, ensuring compatibility&lt;br&gt;
2) ensure &lt;em&gt;only&lt;/em&gt; a subset of the original functionality is within scope, ensuring that other methods or properties will not be included.&lt;/p&gt;

&lt;p&gt;In our specific case, we are using interfaces mainly for reason #2.&lt;/p&gt;

&lt;p&gt;So how do we use this interface to grant the public a restricted access to our collection?&lt;/p&gt;

&lt;p&gt;Look at the last line (90) of the contract, within the &lt;code&gt;init()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;CollectionPublic&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;TweetCollectionPublicPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;TweetCollectionStoragePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The line above creates a public capability that allows access to the stored Collection resource but only through the type &lt;code&gt;{CollectionPublic}&lt;/code&gt;, i.e. only the functionality outlined in the interface. You can think of it as &lt;code&gt;Collection&lt;/code&gt; being "stripped" of anything other than what is strictly defined in &lt;code&gt;CollectionPublic&lt;/code&gt; before it is made available.&lt;/p&gt;

&lt;p&gt;You can see how this can create powerful and flexible access controls. We can create interfaces and capabilities for various actors/counterparts within our application and Cadence will do the hard work of enforcing control.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ It's not terribly important in this example, but in the code above, &lt;code&gt;&amp;amp;{CollectionPublic}&lt;/code&gt; is the equivalent of writing &lt;code&gt;&amp;amp;AnyResource{CollectionPublic}&lt;/code&gt;. That is, any resource that conforms to the &lt;code&gt;CollectionPublic&lt;/code&gt; interface will be valid. If we want to scope it to &lt;em&gt;only&lt;/em&gt; accept &lt;em&gt;the&lt;/em&gt; collection resource that we created, we would have to re-write it as &lt;code&gt;&amp;amp;Collection{CollectionPublic}&lt;/code&gt;. This would guarantee that not only does the resource have to conform to the interface, but it needs to be the specific underlying resource. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Borrowing a resource
&lt;/h4&gt;

&lt;p&gt;So we've created a capability that allows us access to two methods of the collection: &lt;code&gt;getIDs&lt;/code&gt; and &lt;code&gt;borrowTweet&lt;/code&gt;. The latter is new, so let's take a look at it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;borrowTweet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UInt64&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="kt"&gt;Tweet&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tweets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tweets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="kt"&gt;Twitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Tweet&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚨 New symbol alert! What the heck is &lt;code&gt;&amp;amp;&lt;/code&gt;? The ampersand (&amp;amp;) represents a &lt;a href="https://developers.flow.com/cadence/language/references" rel="noopener noreferrer"&gt;&lt;code&gt;reference&lt;/code&gt;&lt;/a&gt; to a resource. Rather than loading the resource from storage and passing it back and forth, in Cadence we can create references to any object (both resources or structures). A reference can be used to access fields and call functions on the referenced object as a value type.&lt;/p&gt;

&lt;p&gt;References are created by using the &lt;code&gt;&amp;amp;&lt;/code&gt; operator, followed by the object, the &lt;code&gt;as&lt;/code&gt; keyword, and the type through which they should be accessed. The given type must be a supertype of the referenced object's type. &lt;/p&gt;

&lt;p&gt;If we zero in on the line &lt;code&gt;let ref = (&amp;amp;self.tweets[id] as &amp;amp;Twitter.Tweet?)!&lt;/code&gt;, this is exactly what we do: we create a reference of the Tweet resource at a certain ID, and cast it as a Tweet type. Since the ID could not exist, the dictionary returns an optional, so we use the exclamation mark at the end to force unwrap it. &lt;/p&gt;

&lt;h3&gt;
  
  
  Flow Playground - Deploying and interacting with the new contract
&lt;/h3&gt;

&lt;p&gt;Let's interact with the new and improved contract. Click on the image or the link below to go to the updated live playground example. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://play.flow.com/02aeaca5-3516-45f8-ae79-9f10d5db3cb5?type=account&amp;amp;id=d80cd930-fab4-4c51-a3c3-824deec36c96&amp;amp;storage=none" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9seczkmp26rcc1yxjm2x.png" width="800" height="611"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://play.flow.com/02aeaca5-3516-45f8-ae79-9f10d5db3cb5?type=account&amp;amp;id=d80cd930-fab4-4c51-a3c3-824deec36c96&amp;amp;storage=none" rel="noopener noreferrer"&gt;👉 Click me to go to the Playground Example&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;First things first deploy the contract! &lt;/p&gt;

&lt;h4&gt;
  
  
  Updating the transaction
&lt;/h4&gt;

&lt;p&gt;We still have the same transactions as last time, although you'll notice the &lt;code&gt;Create new Tweet&lt;/code&gt; transaction has an extra line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// publish a reference to the Collection in storage&lt;/span&gt;
&lt;span class="n"&gt;acct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Twitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;CollectionPublic&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Twitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;TweetCollectionPublicPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Twitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;TweetCollectionStoragePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the same line that we added to the init of the contract. This will ensure all other accounts that interact with the Twitter contract will also link the public capability.&lt;/p&gt;

&lt;p&gt;Create a couple random Tweets from &lt;code&gt;0x01&lt;/code&gt; and &lt;code&gt;0x02&lt;/code&gt; in the same way we did in the previous section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structs, and running our first script
&lt;/h3&gt;

&lt;p&gt;Scripts &lt;em&gt;query&lt;/em&gt; the chain without affecting its state. Since there is no risk of side-effects, scripts can be executed by anyone, similar to an unauthorized GET request. Similar to how in a normal server you have to expose a port and serve specific data, on Flow we used the public capability to expose our collection, which the script below will make use of.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Twitter from 0x01

pub struct TweetMetadata {
    pub let id: UInt64
    pub let message: String 

    init(id: UInt64, message: String) {
        self.id = id
        self.message = message
    }
}

// Get tweets owned by an account
pub fun main(account: Address): [TweetMetadata] {
    // Get the public account object for account
    let tweetOwner = getAccount(account)

    // Find the public capability for their Collection
    let capability = tweetOwner.getCapability&amp;lt;&amp;amp;{Twitter.CollectionPublic}&amp;gt;(Twitter.TweetCollectionPublicPath)

    // borrow a reference from the capability
    let publicRef = capability.borrow()
            ?? panic("Could not borrow public reference")

    // get list of tweet IDs
    let tweetIDs = publicRef.getIDs()

    let tweets: [TweetMetadata] = []

    for tweetID in tweetIDs {
        let tweet = publicRef.borrowTweet(id: tweetID) ?? panic("this tweet does not exist")
        let metadata = TweetMetadata(id: tweet.id, message: tweet.metadata["message"]!)
        tweets.append(metadata)
    }

    return tweets
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A very basic script only needs to implement a &lt;code&gt;pub fun main()&lt;/code&gt; function. In our script you'll notice we also define a &lt;code&gt;struct&lt;/code&gt; called &lt;code&gt;TweetMetadata&lt;/code&gt;. This is not really required, but I just wanted to show you what structs are like. &lt;br&gt;
Similar to resources, &lt;a href="https://developers.flow.com/cadence/language/composite-types#structures" rel="noopener noreferrer"&gt;structs&lt;/a&gt; are &lt;a href="https://developers.flow.com/cadence/language/composite-types#structures" rel="noopener noreferrer"&gt;composite types&lt;/a&gt;, in that they can implement interfaces and also can have an init function. The main difference is structs are regular value types meaning they don't need to be created/moved/destroyed like a resource would. &lt;/p&gt;

&lt;p&gt;In our case, we are using this struct to create an intermediate abstraction of what the contents of a Tweet should be. This means that if our contract changes, we just need to change our TweetMetadata struct and anything downstream that relies on it will just work.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: in future sections we'll continue to iterate on this contract and make the metadata even more elegant by using what's called the Metadata Standard called &lt;a href="https://github.com/onflow/flow/blob/master/flips/20210916-nft-metadata.md" rel="noopener noreferrer"&gt;MetadataViews&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The rest of the script is relatively straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get the public account object using the built-in &lt;code&gt;getAccount&lt;/code&gt; method, using the account passed in as the argument of the main function.&lt;/li&gt;
&lt;li&gt;From that account, we borrow the &lt;code&gt;CollectionPublic&lt;/code&gt; capability (if it doesn't exist, we panic, meaning the script will abort)&lt;/li&gt;
&lt;li&gt;If it exists, we call the &lt;code&gt;getIDs&lt;/code&gt; the same way we call it in our transaction&lt;/li&gt;
&lt;li&gt;using the Cadence &lt;a href="https://developers.flow.com/cadence/language/control-flow#for-in-statement" rel="noopener noreferrer"&gt;looping function&lt;/a&gt; &lt;code&gt;for ... in ... {}&lt;/code&gt; , we iterate over every ID&lt;/li&gt;
&lt;li&gt;In each iteration of the loop, we use the Collection's &lt;code&gt;borrowTweet&lt;/code&gt; method to populate a new TweetMetadata struct and append it to  a &lt;code&gt;tweets&lt;/code&gt; array which will be our return value of the script. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try running the script! Just select it in the Script Templates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F163sl8go54md49k16suq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F163sl8go54md49k16suq.png" width="248" height="87"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Similar to the transaction send window, you'll see a script execution window where we can specify any arguments. Since our script &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8pkz9nk9tpb6o2znkte.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8pkz9nk9tpb6o2znkte.png" width="298" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've created at least 1 tweet with 0x01, you should see a script result like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8acbldkvaaqaqvntmses.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8acbldkvaaqaqvntmses.png" width="800" height="59"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here it is pretty-formated:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu92j3sqdlma9pvpas79e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu92j3sqdlma9pvpas79e.png" width="622" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It seems like a complicated object, but the good news is "in real life" when we use this script in our app or via the Flow CLI, the object is "flattened" and types are inferred, so we'll work with a regular object containing the contents we expect (id and message).&lt;/p&gt;
&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;In this third iteration of the contract, we added public capabilities to our collection, allowing anyone to access a public version, so that when we build our first POC app, we can view tweets from other people!&lt;/p&gt;

&lt;p&gt;I think we've spent enough time on the Playground for now. Let's start building an app so we can see how all this fits together.&lt;/p&gt;
&lt;h2&gt;
  
  
  Building a first app with the v2 contract
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Preface
&lt;/h3&gt;

&lt;p&gt;In this section, we'll build an app and see how to interact with the chain. First, I just want to make something clear that the whole point of this tutorial is &lt;em&gt;not&lt;/em&gt; to show you how much better building on the blockchain is compared to using traditional servers. It's to help you understand blockchain concepts applied to a use-case that we're all used to, regardless of whether you're in the web3 space or not. &lt;/p&gt;

&lt;p&gt;Much like we iterated on the contract several times in the previous sections, in this section we will iterate back and forth both on the contract and web app as we add more and more features. I really hope you enjoy this "progressive enhancement" type of learning. It's more verbose than jumping right to the final version, but I think makes for a gentler introduction and helps you absorb concepts a bit more gradually.&lt;/p&gt;

&lt;p&gt;Here's a sneak peek of the app:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc0qdbaixle2q62jqrkzt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc0qdbaixle2q62jqrkzt.png" width="748" height="1036"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Our app's tech stack
&lt;/h3&gt;

&lt;p&gt;Let's pick what web stack to use. &lt;/p&gt;
&lt;h4&gt;
  
  
  Web Framework - NextJS, an "obvious" choice
&lt;/h4&gt;

&lt;p&gt;To develop our app, we'll use a web framework. &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;React/NextJS&lt;/a&gt; is the industry standard, so we'll use that.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;😅 I'm a &lt;a href="https://svelte.dev" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; fan - React has weird quirks like JSX, that mixes HTML and CSS in the Javascript..who thought that was a good idea?! I'll probably build a Svelte version of this as well in case anyone reading prefers that, and any contributions in other&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  Minimal CSS styling
&lt;/h4&gt;

&lt;p&gt;I opted to use &lt;a href="https://picocss.com/" rel="noopener noreferrer"&gt;&lt;code&gt;pico.css&lt;/code&gt;&lt;/a&gt; for the styling. It's a drop-in classless CSS framework, meaning it styles the base HTML tags, so we can use good ol' semantic HTML and have styles for free. Cool! &lt;/p&gt;
&lt;h4&gt;
  
  
  Flow Client Library - the perfect choice
&lt;/h4&gt;

&lt;p&gt;Regardless of what web framework you use, one choice is already made for us. The JS &lt;a href="https://developers.flow.com/tools/fcl-js/index" rel="noopener noreferrer"&gt;Flow Client Library&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The Flow Client Library (FCL) JS is a package used to interact with user wallets and the Flow blockchain. When using FCL for authentication, apps are able to support all FCL-compatible wallets on Flow and their users without any custom integrations or changes needed to their code. Sweet!&lt;/p&gt;

&lt;p&gt;FCL was created to make developing applications that connect to the Flow blockchain super easy and secure. It defines a standardized set of communication patterns between wallets, applications, and users that is used to perform a wide variety of actions for your dapp. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: While FCL itself is a concept and standard, FCL JS is the javascript implementation of FCL and can be used in both browser and server environments. All functionality for connecting and communicating with wallet providers is restricted to the browser. We also have FCL Swift implementation for iOS, see &lt;a href="https://github.com/zed-io/fcl-swift" rel="noopener noreferrer"&gt;FCL Swift&lt;/a&gt;, contributed by @lmcmz.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  Flow CLI - the one stop shop for all things Flow
&lt;/h4&gt;

&lt;p&gt;Lastly, one other important tool we're going to use is the &lt;a href="https://developers.flow.com/tools/flow-cli" rel="noopener noreferrer"&gt;Flow CLI&lt;/a&gt; - a command-line interface that provides useful utilities for building Flow applications. It includes several commands to interact with Flow networks, such as querying account information, deploying contracts, sending transactions and executing scripts. It also includes the Flow Emulator and Dev Wallet (which is a development version Flow wallet used when developing locally on the emulator).&lt;/p&gt;
&lt;h3&gt;
  
  
  Setting up our dev environment
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Prerequisites
&lt;/h4&gt;

&lt;p&gt;Before moving to the next step, ensure you have the following tools installed:&lt;/p&gt;
&lt;h5&gt;
  
  
  NodeJS
&lt;/h5&gt;

&lt;p&gt;Ensure you have NodeJS &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;installed&lt;/a&gt;. Version &lt;strong&gt;16+&lt;/strong&gt; is what I'm using currently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; node -v

v16.x.x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;📣 Tip&lt;/strong&gt;: Need to manage different versions of NodeJS? Try using &lt;a href="https://github.com/nvm-sh/nvm" rel="noopener noreferrer"&gt;NVM&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h5&gt;
  
  
  Flow CLI
&lt;/h5&gt;

&lt;p&gt;Ensure you have the &lt;a href="https://docs.onflow.org/flow-cli/install/" rel="noopener noreferrer"&gt;Flow CLI&lt;/a&gt; installed too. At the time of this writing, I am using version &lt;strong&gt;0.41.3&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; flow version

Version: v0.41.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Initializing our project
&lt;/h3&gt;

&lt;p&gt;Rather that have you copy and paste by hand a ton of stuff, I'm going to show you a pre-made app and explain how it works. Then we'll expand on it together!&lt;/p&gt;

&lt;p&gt;With your favorite terminal, create and navigate to a new directory like &lt;code&gt;/twitter3&lt;/code&gt;. Then clone the starter repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/muttoni/twitter3.git .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's take a look at the project directory:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fopfb883gvmkvb7o2gc4m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fopfb883gvmkvb7o2gc4m.png" width="646" height="894"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Folder Structure
&lt;/h4&gt;

&lt;p&gt;You can structure your folders however you want, the app shows a common way to do it. Here they are explained order:&lt;/p&gt;

&lt;h5&gt;
  
  
  File Glossary
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;🆕 &lt;code&gt;/cadence&lt;/code&gt;: contains all Cadence related files, like contracts, transactions and scripts. It contains respective subfolders for each one. If you open the subfolders, you'll see the exact same contract, transaction and script we created in the &lt;a href="https://play.flow.com/02aeaca5-3516-45f8-ae79-9f10d5db3cb5?type=account&amp;amp;id=d80cd930-fab4-4c51-a3c3-824deec36c96&amp;amp;storage=none" rel="noopener noreferrer"&gt;Playground example&lt;/a&gt; in the last section, with only 1 small change: the imports.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/components&lt;/code&gt;: this is standard NextJS folder to store React components&lt;/li&gt;
&lt;li&gt;🆕 &lt;code&gt;/constants&lt;/code&gt;: just a folder to save some handy constants&lt;/li&gt;
&lt;li&gt;🆕 &lt;code&gt;/flow&lt;/code&gt;: a folder dedicated to Flow-specific stuff. Currently this folder only contains a config file for the Flow Client Library, but in the future we could move Flow-logic to this folder.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/hooks&lt;/code&gt;: standard NextJS Hooks folder&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/pages&lt;/code&gt;: standard NextJS Pages folder&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/public&lt;/code&gt;: standard NextJS public assets folder&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/styles&lt;/code&gt;: standard NextJS styles folder &lt;/li&gt;
&lt;li&gt;🆕 &lt;code&gt;emulatore.private.json&lt;/code&gt;: a config snippet containing sensitive information, which we don't want added to the public flow.json.&lt;/li&gt;
&lt;li&gt;🆕 &lt;code&gt;flow.json&lt;/code&gt;: the standard Flow config file that instructs the Flow CLI what contracts to deploy&lt;/li&gt;
&lt;li&gt;...standard NextJS files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've used NextJS in the past, this folder structure looks very familiar, and only the 🆕 folders should be surprising.&lt;/p&gt;

&lt;h4&gt;
  
  
  Installing dependencies
&lt;/h4&gt;

&lt;p&gt;Next let's install dependencies and run our app in dev!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  It's alive!
&lt;/h3&gt;

&lt;p&gt;Make sure to have 3 terminal windows open:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;App terminal&lt;/li&gt;
&lt;li&gt;Flow Emulator terminal&lt;/li&gt;
&lt;li&gt;Flow Dev Wallet terminal&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In terminal 2, run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flow emulator start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In terminal 3, run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flow dev-wallet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now in terminal 1, let's start the app!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run dev:local:deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're curious as to what the command above does, check the &lt;code&gt;package.json&lt;/code&gt;. In short, it deploys/updates the contracts to the Flow Emulator as defined in our &lt;code&gt;flow.json&lt;/code&gt;, which is the standard Flow CLI config file, and then runs &lt;code&gt;npm run dev&lt;/code&gt; for our NextJS app. &lt;/p&gt;

&lt;p&gt;If you ran everything correctly you should see:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fopcjbmlwewclzqkodxsi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fopcjbmlwewclzqkodxsi.png" width="730" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on "&lt;strong&gt;Log In With Wallet&lt;/strong&gt;"&lt;/p&gt;

&lt;p&gt;You should see popup window like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fut6v64yaqh844w64gz4f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fut6v64yaqh844w64gz4f.png" width="510" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the FCL discovery service, that exposes available wallets a user may want have/want to use. What's great about FCL is that the wallet is completely abstracted from the app, and the app is completely abstracted from the wallet, so any user can use any wallet and the code and app don't need to care (usually).&lt;/p&gt;

&lt;p&gt;Since we're on the Emulator and not on Testnet or Mainnet yet, you'll want to select Dev Wallet. &lt;/p&gt;

&lt;p&gt;You'll then be presented with a Dev Wallet splash screen, where you can select which account to use:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1m4zwbgqczmn0vutpq2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1m4zwbgqczmn0vutpq2.png" width="661" height="656"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is because in the Dev Wallet you can easily create and switch between different accounts, and quickly fund accounts with imaginary FLOW. The Service account is the "base" account on Flow, and you can create as many other "normal" accounts as you want. Click on Service Account or Account A. &lt;/p&gt;

&lt;p&gt;Alright, now you're authenticated and the UI should reflect that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcbto3fh7zin7heet8glq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcbto3fh7zin7heet8glq.png" width="727" height="709"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to play around with the app first, then we'll start dissecting how it works. &lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding the Flow
&lt;/h3&gt;

&lt;p&gt;Before we look at the app code, I want to show you how to use the Flow CLI by running the exact same transaction and script we ran in our Playground example, only this time "for real" on the emulator.&lt;/p&gt;

&lt;p&gt;As mentioned in the glossary, the &lt;code&gt;/cadence&lt;/code&gt; folder contains all Cadence related files, like our Twitter contract, and the transaction and script we'll need. It contains respective subfolders for each type.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm26svq9cl1o345e1k7ch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm26svq9cl1o345e1k7ch.png" width="640" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you open the subfolders, you'll see the exact same contract, transaction and script we created in the &lt;a href="https://play.flow.com/02aeaca5-3516-45f8-ae79-9f10d5db3cb5?type=account&amp;amp;id=d80cd930-fab4-4c51-a3c3-824deec36c96&amp;amp;storage=none" rel="noopener noreferrer"&gt;Playground example&lt;/a&gt; in the last section, with only 1 small change: the imports. You'll notice the transaction and script doesn't import &lt;code&gt;0x01&lt;/code&gt; anymore, but a longer address. This is the address on the emulator that we are deploying the contracts to. You'll see how in just a second!&lt;/p&gt;

&lt;p&gt;Let's imagine we don't have an app yet, and we just have these three folders setup. How would we interact with the emulator? The answer is the Flow CLI!&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying a contract to the emulator
&lt;/h3&gt;

&lt;p&gt;In our app, the &lt;code&gt;npm run dev:local:deploy&lt;/code&gt; command does this automatically, but the underlying command it uses to deploy the contracts (or update them if they've changed) is just as simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flow project deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How does it know &lt;em&gt;what&lt;/em&gt; to deploy? The answer is in the &lt;code&gt;flow.json&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Flow Configuration - flow.json
&lt;/h3&gt;

&lt;p&gt;How does the Flow CLI know what contract to use and what account to find it in? The answer is the &lt;a href="https://developers.flow.com/tools/flow-cli/configuration" rel="noopener noreferrer"&gt;&lt;code&gt;flow.json&lt;/code&gt;&lt;/a&gt; - a project-specific configuration file. Here's what ours looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"networks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"emulator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"127.0.0.1:3569"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mainnet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"access.mainnet.nodes.onflow.org:9000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"testnet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"access.devnet.nodes.onflow.org:9000"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"contracts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Twitter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./cadence/contracts/Twitter.cdc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"aliases"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"emulator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0xf8d6e0586b0a20c7"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"accounts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"emulator-account"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"fromFile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./emulator.private.json"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"deployments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"emulator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"emulator-account"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Twitter"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration outlines what network addresses the CLI should use, what contracts are included in our application and therefore, should be deployed, and to which address. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 Read more about the flow.json &lt;a href="https://developers.flow.com/tools/flow-cli/initialize-configuration" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Sending a transaction with the CLI
&lt;/h3&gt;

&lt;p&gt;🚨 Check your transaction and scripts in this section and makes ure they are importing the Twitter contract from &lt;code&gt;0xf8d6e0586b0a20c7&lt;/code&gt; and not &lt;code&gt;0xTwitter&lt;/code&gt;. The latter is specific to FCL which we will look at later.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's start by creating a Tweet. For this we'll use the Flow CLI's &lt;code&gt;flow transaction send&lt;/code&gt; command. As a first argument it expects the path or string of the transaction, and any arguments after that will be passed as arguments to the transaction. With the command below we're creating a tweet with text "Hello" using the default account and network (emulator) as defined in our &lt;code&gt;flow.json&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Try running this in your terminal (with the emulator running):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flow transactions send ./cadence/transactions/CreateNewTweet.cdc Hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see an output similar to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmonasyu0het5ip5hawg7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmonasyu0het5ip5hawg7.png" width="800" height="635"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll notice it used the account &lt;code&gt;f8d6e0586b0a20c7&lt;/code&gt; which is the main emulator service account we saw earlier (i.e. the service account). Fun fact, the &lt;code&gt;0x&lt;/code&gt; is completely optional on Flow.&lt;/p&gt;

&lt;p&gt;The status is shown as ✅ SEALED, which means the transaction has been fully confirmed and it is committed to the blockchain. There are transaction codes for different intermediate phases (and we'll see how to use them to provide transaction feedback when we deploy the app to testnet). &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;UNKNOWN&lt;/td&gt;
&lt;td&gt;The transaction status is not known.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;PENDING&lt;/td&gt;
&lt;td&gt;The transaction has been received by a collector but not yet finalized in a block.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;FINALIZED&lt;/td&gt;
&lt;td&gt;The consensus nodes have finalized the block that the transaction is included in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;EXECUTED&lt;/td&gt;
&lt;td&gt;The execution nodes have produced a result for the transaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;SEALED&lt;/td&gt;
&lt;td&gt;The verification nodes have verified the transaction (the block in which the transaction is) and the seal is included in the latest block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;EXPIRED&lt;/td&gt;
&lt;td&gt;The transaction was submitted past its expiration block height.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://developers.flow.com/nodes/access-api#transaction-status" rel="noopener noreferrer"&gt;Source&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 The &lt;code&gt;flow transactions send&lt;/code&gt; command accepts other flags, such as what account to sign it as. &lt;a href="https://developers.flow.com/tools/flow-cli/send-transactions#flags" rel="noopener noreferrer"&gt;See here for more info&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Executing a script with the CLI
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;🚨 Check your transaction and scripts in this section and makes ure they are importing the Twitter contract from &lt;code&gt;0xf8d6e0586b0a20c7&lt;/code&gt; and not &lt;code&gt;0xTwitter&lt;/code&gt;. The latter is specific to FCL which we will look at later.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To query an account's Tweets, we can use &lt;code&gt;flow scripts execute&lt;/code&gt;, which is structured very similarly to the transaction command: first argument is the script to execute, and any subsequent arguments will be passed to the script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flow scripts execute ./cadence/scripts/GetTweetsByAccount.cdc f8d6e0586b0a20c7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's run it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fah7qsjcakbg6pf1d8nep.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fah7qsjcakbg6pf1d8nep.png" width="800" height="84"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 The &lt;code&gt;flow scripts execute&lt;/code&gt; command accepts several flags. &lt;a href="https://developers.flow.com/tools/flow-cli/execute-scripts" rel="noopener noreferrer"&gt;See here for more info&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Flow configuration - config.js
&lt;/h3&gt;

&lt;p&gt;The other important Flow configuration is within the app, and configures the behavior of the Flow Client Library. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2rmekjzugqjit02dcg3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2rmekjzugqjit02dcg3.png" width="638" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll find this in &lt;code&gt;/flow/config.js&lt;/code&gt;. This contains standard info like network, access node, as well as more app specific configuration data, like app name and icon. &lt;/p&gt;

&lt;h3&gt;
  
  
  FCL
&lt;/h3&gt;

&lt;p&gt;Alright, so you now know how to interact with the contracts, transactions and scripts via the CLI. Let's start taking a look at how these are connected to the web app via the Flow Client Library (FCL).&lt;/p&gt;

&lt;p&gt;Navigate to &lt;code&gt;/flow/config.js&lt;/code&gt;. You'll see a configuration file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@onflow/fcl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ACCESS_NODE_URLS&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../constants&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;flowJSON&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../flow.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flowNetwork&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_FLOW_NETWORK&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dapp running on network:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;flowNetwork&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flow.network&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;flowNetwork&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;accessNode.api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ACCESS_NODE_URLS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;flowNetwork&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;discovery.wallet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`https://fcl-discovery.onflow.org/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;flowNetwork&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/authn`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app.detail.icon&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://avatars.githubusercontent.com/u/50278?s=200&amp;amp;v=4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app.detail.title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Twitter3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;flowJSON&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this file we are telling FCL to:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;flow.network&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;flow.network&lt;/code&gt; is used to specific network (emulator, testnet, mainnet), as defined in the &lt;code&gt;flowNetwork&lt;/code&gt; variable populated by the .env file. In our case it's going to be the emulator. You'll notice we don't have a .env file anywhere in our project. That's because you have to look in the package.json. See below!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev:local"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NEXT_PUBLIC_FLOW_NETWORK=local npm run dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev:local:deploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"flow project deploy --network=emulator --update &amp;amp;&amp;amp; NEXT_PUBLIC_FLOW_NETWORK=local npm run dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev:testnet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NEXT_PUBLIC_FLOW_NETWORK=testnet npm run dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev:mainnet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NEXT_PUBLIC_FLOW_NETWORK=mainnet npm run dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next start"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next lint"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;code&gt;accessNode.api&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;accessNode.api&lt;/code&gt; is where we set what Access Node to connect to. This URL will change based on our Flow network. For the emulator, that is &lt;code&gt;localhost:8888&lt;/code&gt;. You can see the various API urls defined in &lt;code&gt;constants/index.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ACCESS_NODE_URLS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;local&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:8888&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testnet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://rest-testnet.onflow.org&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mainnet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://rest-mainnet.onflow.org&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;code&gt;discovery.wallet&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;FCL Discovery is one of the most &lt;em&gt;powerful&lt;/em&gt; features of FCL. It allows any wallet on Flow to self-announce itself, meaning it will show up automatically in the list of available wallets when a user wants to login to a Flow app, without developers needing to do a &lt;em&gt;single thing&lt;/em&gt;! Isn't that nifty?&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;app.detail.icon&lt;/code&gt; and &lt;code&gt;app.detail.title&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;These are purely cosmetic (an icon for your app, and a title), and these attributes will be used to populate the wallet selection popup generated by FCL. In our case we're using the Twitter logo and the title Twitter3. It looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fut6v64yaqh844w64gz4f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fut6v64yaqh844w64gz4f.png" width="510" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Hooks
&lt;/h3&gt;

&lt;p&gt;React hooks are a way to set some state that can be used throughout the app. If you go to &lt;code&gt;/hooks/useConfig.js&lt;/code&gt; and &lt;code&gt;/hooks/useCurrentUser.js&lt;/code&gt; we'll see two important hooks that also are linked with FCL.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;useConfig.js&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;In this hook, we are setting state to load the current Flow network. We use &lt;code&gt;fcl.config.get&lt;/code&gt; to get a specific setting that we set previously.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;fcl&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@onflow/fcl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setNetwork&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flowNetwork&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fcl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flow.network&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;setNetwork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flowNetwork&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;getConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;code&gt;useCurrentUser.js&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;In this hook, we're creating a &lt;code&gt;user&lt;/code&gt; object and populating it based on the state of &lt;code&gt;fcl.currentUser&lt;/code&gt;. This is a function that can be subscribed to and returns the state of the authenticated (or not) user. This gives us a user object we can query and create conditional logic around throughout the app (e.g. showing a Connect Wallet button if not logged in for example).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;fcl&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@onflow/fcl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useCurrentUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;loggedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fcl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what the &lt;code&gt;fcl.currentUser&lt;/code&gt; object contains. &lt;code&gt;loggedIn&lt;/code&gt; and &lt;code&gt;addr&lt;/code&gt; are usually the most important values:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;fcl.currentUser object&lt;/code&gt;
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key&lt;/th&gt;
&lt;th&gt;Value Type&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;addr&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Address&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The public address of the current user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Allows wallets to specify a &lt;a href="https://docs.ipfs.io/concepts/content-addressing/" rel="noopener noreferrer"&gt;content identifier&lt;/a&gt; for user metadata.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;expiresAt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;number&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Allows wallets to specify a time-frame for a valid session.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;f_type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;&lt;code&gt;'USER'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A type identifier used internally by FCL.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;f_vsn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;&lt;code&gt;'1.0.0'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;FCL protocol version.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;loggedIn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;If the user is logged in.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;services&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;[ServiceObject]&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A list of trusted services that express ways of interacting with the current user's identity, including means to further discovery, &lt;a href="https://gist.github.com/orodio/a74293f65e83145ec8b968294808cf35#you-know-who-the-user-is" rel="noopener noreferrer"&gt;authentication, authorization&lt;/a&gt;, or other kinds of interactions.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;📖 Read more about the currentUser object and FCL &lt;a href="https://developers.flow.com/tools/fcl-js/reference/api#currentuserobject" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Components &amp;amp; Pages
&lt;/h3&gt;

&lt;p&gt;Now that we covered the basic foundations of FCL, let's look at how these are applied in the actual app by looking at its components and pages.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;pages/index.js&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;This is the main entry point into the app. Here we load the Flow config and use the &lt;code&gt;useCurrentUser&lt;/code&gt; hook to conditionally render the main container if the user is logged in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Navbar&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/Navbar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../flow/config.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Container&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/Container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;useCurrentUser&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../hooks/useCurrentUser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loggedIn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCurrentUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;


      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Twitter 3&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Twitter3 - thoughts onchain'ed"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.ico"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Navbar&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loggedIn&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;code&gt;components/Container.js&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;This is the other "big" one to look through. In this component we render most of the UI and more or less this is where everything comes together: FCL, the transactions, the scripts and our app functionality. This is the MOTHERLOAD!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;fcl&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@onflow/fcl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;GetTweetsByAccount&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../cadence/scripts/GetTweetsByAccount.cdc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CreateNewTweet&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../cadence/transactions/CreateNewTweet.cdc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../styles/Container.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;useConfig&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../hooks/useConfig&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;useCurrentUser&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../hooks/useCurrentUser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BLOCK_EXPLORER_URLS&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../constants&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Tweet&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Tweet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tweetList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTweetList&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tweetText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTweetText&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;lastTransactionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLastTransactionId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;transactionStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTransactionStatus&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;N/A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCurrentUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isEmulator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mainnet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;testnet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isSealed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="c1"&gt;// 4: 'SEALED'&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastTransactionId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Last Transaction ID: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastTransactionId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="nx"&gt;fcl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastTransactionId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setTransactionStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// Query for new chain string again if status is sealed&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isSealed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;getTweets&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;lastTransactionId&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getTweets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fcl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;cadence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GetTweetsByAccount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;setTweetList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createTweet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;tweetText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please add a new greeting string.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transactionId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fcl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;cadence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CreateNewTweet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tweetText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nf"&gt;setLastTransactionId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transactionId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;openExplorerLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transactionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BLOCK_EXPLORER_URLS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;/transaction/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;transactionId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_blank&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;createTweet&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="na"&gt;for&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"tweet"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Create a new Tweet&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;textarea&lt;/span&gt; 
          &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"tweetContents"&lt;/span&gt;               
          &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"I feel..."&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;tweetText&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTweetText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"tweetContents"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;textarea&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;small&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Share your thoughts with the world.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;small&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Tweet"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;hr&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Your Tweets
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;getTweets&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;refresh&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;svg&lt;/span&gt; &lt;span class="na"&gt;xmlns&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/svg"&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"16"&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"16"&lt;/span&gt; &lt;span class="na"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"currentColor"&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"bi bi-arrow-clockwise"&lt;/span&gt; &lt;span class="na"&gt;viewBox&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"0 0 16 16"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;path&lt;/span&gt; &lt;span class="na"&gt;fill-rule&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"evenodd"&lt;/span&gt; &lt;span class="na"&gt;d&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z"&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;path&lt;/span&gt; &lt;span class="na"&gt;d&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z"&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;tweetList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;
          &lt;span class="nx"&gt;tweetList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;tweet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Tweet&lt;/span&gt; &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;addr&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;tweet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;tweet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Your tweets will show up here!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="si"&gt;}&lt;/span&gt; 

    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Structure
&lt;/h4&gt;

&lt;p&gt;At a high level, there are 3 interacting parts to this code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Imports&lt;/strong&gt;: We load transactions and scripts as variables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;States&lt;/strong&gt;: We set states to keep track of data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Actions&lt;/strong&gt;: We define functions like &lt;code&gt;getTweets&lt;/code&gt; that run the imported code on-chain, then populate the states.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Imports
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;GetTweetsByAccount&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../cadence/scripts/GetTweetsByAccount.cdc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CreateNewTweet&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../cadence/transactions/CreateNewTweet.cdc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are able to import Cadence (.cdc) files thanks to the loader defined in the webpack settings defined in &lt;code&gt;/next.config.js&lt;/code&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  States
&lt;/h5&gt;

&lt;p&gt;We create several states:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tweetList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTweetList&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tweetText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTweetText&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;lastTransactionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLastTransactionId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;transactionStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTransactionStatus&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;N/A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tweetList&lt;/code&gt; is used to keep track of the array of tweets on chain.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tweetText&lt;/code&gt; is used to keep track of the tweet text that we are creating and will then publish&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lastTransactionId&lt;/code&gt; is used to keep track of the transaction ID so that we can link out to the chain explorers like Flowscan or Flow-View-Source. We don't really need this when using the emulator because transactions are instant and we get feedback in the console.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;transactionStatus&lt;/code&gt; is what contains the state of the transaction. Remember our section around possible transaction states above? No? Well here it is again: &lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;UNKNOWN&lt;/td&gt;
&lt;td&gt;The transaction status is not known.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;PENDING&lt;/td&gt;
&lt;td&gt;The transaction has been received by a collector but not yet finalized in a block.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;FINALIZED&lt;/td&gt;
&lt;td&gt;The consensus nodes have finalized the block that the transaction is included in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;EXECUTED&lt;/td&gt;
&lt;td&gt;The execution nodes have produced a result for the transaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;SEALED&lt;/td&gt;
&lt;td&gt;The verification nodes have verified the transaction (the block in which the transaction is) and the seal is included in the latest block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;EXPIRED&lt;/td&gt;
&lt;td&gt;The transaction was submitted past its expiration block height.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://developers.flow.com/nodes/access-api#transaction-status" rel="noopener noreferrer"&gt;Source&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Actions
&lt;/h4&gt;

&lt;h4&gt;
  
  
  Running a script via FCL
&lt;/h4&gt;

&lt;p&gt;How do we get the list of tweets from an account? It's super simple. We just use &lt;code&gt;fcl.query&lt;/code&gt; and pass in the Cadence code we want to run, and the arguments. Here's the annotated source:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getTweets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// read addr from user object&lt;/span&gt;
    &lt;span class="nx"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// run fcl.query which runs a script, &lt;/span&gt;
      &lt;span class="c1"&gt;// using the addr above as argument&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fcl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;cadence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GetTweetsByAccount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// set the state as the resulting array, after sorting.&lt;/span&gt;
    &lt;span class="nf"&gt;setTweetList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Running a transaction via FCL
&lt;/h4&gt;

&lt;p&gt;Similarly to the script, running a transaction via FCL is also incredibly straightforward. Rather than &lt;code&gt;fcl.query&lt;/code&gt;, we use &lt;code&gt;fcl.mutate&lt;/code&gt;. We the pass in the Cadence transaction code imported previously and the arguments, like we do in the script. FCL will take care of triggering an authorization popup when publishing a tweet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const createTweet = async (event) =&amp;gt; {
    event.preventDefault()

    if (!tweetText.length) {
      throw new Error('Please add a new greeting string.')
    }

    const transactionId = await fcl.mutate({
      cadence: CreateNewTweet,
      args: (arg, t) =&amp;gt; [arg(tweetText, t.String)]
    })

    setLastTransactionId(transactionId)
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The authorization popup looks like this: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F87zfzao1a02am13a0jax.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F87zfzao1a02am13a0jax.png" width="668" height="1305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: this layout is what the Dev Wallet shows, other wallets on Flow will show something similar, but it won't be exactly the same. The point is, there's an authorization step, and to &lt;strong&gt;mutate&lt;/strong&gt; the chain you need to be authenticated as an account and sign the transaction. So any time you run a transaction, a popup will show up, asking the user to authorize the transaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying to Testnet
&lt;/h2&gt;

&lt;p&gt;Last thing to try is to deploy our wonderful app to testnet. This will give us a chance to see it in action on a &lt;em&gt;real&lt;/em&gt; live chain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a testnet account
&lt;/h3&gt;

&lt;p&gt;First things first, to deploy to testnet, given that it's a real live chain, we need a testnet account. To create one, all we need to do is run the following Flow CLI command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flow accounts create
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what the process looks like:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Name your Account
&lt;/h4&gt;

&lt;p&gt;Name your new account &lt;code&gt;hero&lt;/code&gt; and hit Enter. Follow the rest of the instructions on screen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Enter an account name: hero
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 You can pick any name, we are trying to keep the instructions in line with your experience. If you would decide to name your account differently, please use that name everywhere we refer to &lt;code&gt;hero&lt;/code&gt; account and address.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  2. Set your network to Flow Testnet
&lt;/h4&gt;

&lt;p&gt;Scroll down once to select Flow Testnet, then hit Enter&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use the arrow keys to navigate: ↓ ↑ → ← 
? Choose a network: 
    Local Emulator
  ▸ Flow Testnet
    Flow Mainnet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Save Account Info
&lt;/h4&gt;

&lt;p&gt;You'll then get presented with a confirmation step. Type y and hit Enter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✔ Flow Testnet

❗ This command will perform the following:
 - Generate a new ECDSA P-256 public and private key pair.
 - Save the private key to hero.private.json and add it to .gitignore.
 - Create a new account on Flow Testnet paired with the public key.
 - Save the newly-created account to flow.json.


? Do you want to continue? [y/N] y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. Fund your Testnet Account
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Please complete the following steps in a web browser:
 1. Complete the captcha challenge.
 2. Click the 'Create Account' button.
 3. Return to this window.

✔ Press &amp;lt;ENTER&amp;gt; to open in your browser...: █

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you press Enter, your browser will be automatically directed to the &lt;a href="https://testnet-faucet.onflow.org/" rel="noopener noreferrer"&gt;Flow Testnet Faucet&lt;/a&gt; with your account information &lt;strong&gt;pre-populated&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;The only actions that is required are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Please complete the following steps in a web browser:
 1. Complete the captcha challenge.
 2. Click the 'Create Account' button.
 3. Return to this window.

You can also navigate to the link manually: https://testnet-faucet.onflow.org/?key=&amp;lt;key_that_is_pre_populated&amp;gt;

Waiting for your account to be created, please finish all the steps in the browser...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fncefmpns1nl5zbjlibvz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fncefmpns1nl5zbjlibvz.gif" alt="Funding your testnet account from Flow faucet" width="600" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  5. You're all set!
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🎉 New account created with address 0xebeb17c521a0d375 and name hero.

Here’s a summary of all the actions that were taken:
 - Added the new account to flow.json.
 - Saved the private key to hero.private.json.
 - Added hero.private.json to .gitignore.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After you finish all the steps, you will notice that 2 new files are now present in the directory:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;flow.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hero.private.json&lt;/code&gt; &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Flow CLI automatically created a second file called &lt;code&gt;hero.private.json&lt;/code&gt;. This file contains our private key from our newly created testnet account. This file is automatically added to the &lt;code&gt;.gitignore&lt;/code&gt; so you don't accidentally leak any credentials! &lt;/p&gt;

&lt;p&gt;If you inspect the files, you should see the address and private key for your freshly minted account 👍!&lt;/p&gt;

&lt;h4&gt;
  
  
  flow.json
&lt;/h4&gt;

&lt;p&gt;You'll also notice the flow.json changed automatically, and now lists "hero" as an account, linking to the json.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"accounts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"emulator-account"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"fromFile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./emulator.private.json"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"hero"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"fromFile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hero.private.json"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to now create an account alias for the contract so FCL will know which account to substitute the imports with when on testnet on our transactions and scripts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  "contracts": {
    "Twitter": {
      "source": "./cadence/contracts/Twitter.cdc",
      "aliases": {
        "emulator": "0xf8d6e0586b0a20c7",
&lt;span class="gi"&gt;+       "testnet": "0x3c1f94baa070dd43"
&lt;/span&gt;      }
    }
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we also need to add a deployment specification for testnet in the flow.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"testnet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"hero"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Twitter"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our new and improved flow.json looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;{
  "contracts": {
    "Twitter": {
      "source": "./cadence/contracts/Twitter.cdc",
      "aliases": {
        "emulator": "0xf8d6e0586b0a20c7",
&lt;span class="gi"&gt;+       "testnet": "0x3c1f94baa070dd43"
&lt;/span&gt;      }
    }
  },
  "networks": {
    "emulator": "127.0.0.1:3569",
    "mainnet": "access.mainnet.nodes.onflow.org:9000",
    "testnet": "access.devnet.nodes.onflow.org:9000"
  },
  "accounts": {
    "emulator-account": {
      "fromFile": "./emulator.private.json"
    },
&lt;span class="gi"&gt;+   "hero": {
+     "fromFile": "hero.private.json"
+   }
&lt;/span&gt;  },
  "deployments": {
    "emulator": {
      "emulator-account": [
        "Twitter"
      ]
    },
&lt;span class="gi"&gt;+   "testnet": {
+     "hero": [
+       "Twitter"
+     ]
+   }
&lt;/span&gt;  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Deploying
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;🚨 Check your transaction and scripts before starting this section and makes ure you change the imports from &lt;code&gt;import Twitter from 0xf8d6e0586b0a20c7&lt;/code&gt; to &lt;code&gt;import Twitter from 0xTwitter&lt;/code&gt;. The latter is specific to FCL and will allow seamlessly switching between the emulator and testnet/mainnet &lt;em&gt;in our app&lt;/em&gt;. If you ever want to use the CLI again directly, you'll need to switch back.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Alright, let's get to deploying! &lt;/p&gt;

&lt;p&gt;Let's run the same command we ran in the emulator, but specifying testnet as our network. The Flow CLI will read the configuration file (flow.json) we updated and know which contract to deploy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flow project deploy --network=testnet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deploying 1 contracts for accounts: hero

Twitter deploying...⠴
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It might take 30 seconds or so. Then you should see:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdbl25qud2dn5m2d23ing.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdbl25qud2dn5m2d23ing.png" width="601" height="148"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎉 Yay!&lt;/p&gt;

&lt;h4&gt;
  
  
  Running app on testnet
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;🚨 Check your transaction and scripts before starting this section and makes ure you change the imports from &lt;code&gt;import Twitter from 0xf8d6e0586b0a20c7&lt;/code&gt; to &lt;code&gt;import Twitter from 0xTwitter&lt;/code&gt;. The latter is specific to FCL and will allow seamlessly switching between the emulator and testnet/mainnet &lt;em&gt;in our app&lt;/em&gt;. If you ever want to use the CLI again directly, you'll need to switch back.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now let's use the built-in &lt;code&gt;npm run dev:testnet&lt;/code&gt;, which will run the app and set the &lt;code&gt;NEXT_PUBLIC_FLOW_NETWORK&lt;/code&gt; to &lt;code&gt;testnet&lt;/code&gt;. Our app should update automagically!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run dev:testnet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;✅ Remember, the npm commands are just conveniences, you can always look through the package.json to see what the commands do. You'll realize they are very thin wrappers around standard and simple Flow CLI commands + NextJS ones.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You should see the same login page as before, and if you click "Connect Wallet" you should now see:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmibfvpxvi2w9wpu4befs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmibfvpxvi2w9wpu4befs.png" width="530" height="545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are actual, real, live, awesome, supercharged Flow wallets!&lt;/p&gt;

&lt;p&gt;Let's pick Blocto. All you need is an email. Pretty sweet right? Wallets on Flow are super user-friendly. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk51zdchbrpx001tvq9he.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk51zdchbrpx001tvq9he.png" width="419" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👉 You'll also notice the &lt;code&gt;DEV&lt;/code&gt; next to Blocto. This is because we are running on testnet, so the wallet is &lt;em&gt;also&lt;/em&gt; on testnet. Just put in your email (or a temp one) and click Sign in / Register.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd6jmjkna0u4m2mzftfgt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd6jmjkna0u4m2mzftfgt.png" width="426" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check your email and put in the code and click Login!&lt;/p&gt;

&lt;p&gt;We're live, on testnet!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feilcpbathz2fh1hab6bb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feilcpbathz2fh1hab6bb.png" width="723" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's try writing a tweet. Then click Tweet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhsoklb6m790kkl6u9zrm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhsoklb6m790kkl6u9zrm.png" width="710" height="849"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A popup similar to the dev wallet will show up, asking you to approve the transaction. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdjm177b6bf4oauva1gy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdjm177b6bf4oauva1gy.png" width="389" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also toggle the "Script" section and look at the code, similar to how we saw it in the Dev Wallet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ufa26h2uo027chgs7le.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ufa26h2uo027chgs7le.png" width="389" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you click approve, you see nothing really happens, but if you check the console, you'll see a transaction ID:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpoks4avsttwr66yvwgm3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpoks4avsttwr66yvwgm3.png" width="691" height="60"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can use that to visit a blockchain explorer like &lt;a href="//flowscan.org"&gt;Flowscan&lt;/a&gt; which is more user-friendly for non-devs or &lt;a href="https://flow-view-source.com" rel="noopener noreferrer"&gt;Flow View Source&lt;/a&gt; which is more "in the weeds". &lt;/p&gt;

&lt;p&gt;Here's Flowscan:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8198896ki00pwpfk2t5p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8198896ki00pwpfk2t5p.png" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's Flow View Source:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmwqt4pwv9tzt1oxnbcv3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmwqt4pwv9tzt1oxnbcv3.png" width="800" height="750"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If everything worked correctly, you should now have a sweet, amazing, awesome tweet on Testnet!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftvoa1prcvvqjjqlqut0s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftvoa1prcvvqjjqlqut0s.png" width="682" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Homework
&lt;/h2&gt;

&lt;p&gt;Ok, now you have all the pieces. Now it's your turn to make this app better!&lt;/p&gt;

&lt;h3&gt;
  
  
  Better transaction feedback
&lt;/h3&gt;

&lt;p&gt;For example, you see we have a transaction ID, and a transaction state. Try to create a simple transaction feedback component (or in the Container directly) to give people some feedback around what's happening with their transaction. Sometimes transactions can take 10-30 seconds, so it's important to give feedback.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extending the contract
&lt;/h3&gt;

&lt;p&gt;Currently, the only metadata we have is the actual contents of the tweet. Wouldn't it be cool if tweets had additional stuff like: date, number of likes, etc? Some additional metadata will require a pretty significant overhaul of the contract, incuding adding brand new transactions and scripts...are you up for it? :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback and suggestions
&lt;/h2&gt;

&lt;p&gt;Have suggestions? Feedback? Leave an issue on &lt;a href="https://github.com/muttoni/web3-twitter" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to follow me on (real) Twitter at &lt;a href="//twitter.com/muttonia"&gt;@muttonia&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also find me on the &lt;a href="//discord.gg/flow"&gt;Flow Discord&lt;/a&gt; if you have any questions.&lt;/p&gt;

&lt;p&gt;👋 and happy building!&lt;/p&gt;

</description>
      <category>gratitude</category>
      <category>devto</category>
    </item>
  </channel>
</rss>
