<?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: Max Daunarovich</title>
    <description>The latest articles on DEV Community by Max Daunarovich (@maxstalker).</description>
    <link>https://dev.to/maxstalker</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%2F319125%2F72f44041-baac-463a-828d-6db58f34b472.png</url>
      <title>DEV Community: Max Daunarovich</title>
      <link>https://dev.to/maxstalker</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/maxstalker"/>
    <language>en</language>
    <item>
      <title>Chapter 1: Boring SVG Manipulation</title>
      <dc:creator>Max Daunarovich</dc:creator>
      <pubDate>Thu, 16 May 2024 23:58:51 +0000</pubDate>
      <link>https://dev.to/maxstalker/chapter-1-boring-svg-manipulation-4kod</link>
      <guid>https://dev.to/maxstalker/chapter-1-boring-svg-manipulation-4kod</guid>
      <description>&lt;h2&gt;
  
  
  Exposition
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The exposition is &lt;strong&gt;a set of scenes in a story that are meant to introduce the audience to the characters, world, and tone of the story&lt;/strong&gt;. It is relatively short, and no major changes occur during these opening scenes.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It was a nice calm evening, right after successfully lunched project. The feeling of accomplishment started to wither away and my mind started to wonder how to occupy itself. I heard a &lt;em&gt;bip&lt;/em&gt; and new email messages popped up in my inbox, notifying me that I just won 3rd place in Apparel Challenge on &lt;a href="http://www.kittl.com/"&gt;www.kittl.com&lt;/a&gt;. I jumped to check the result, then some of applicants who was close or got exact number of votes, then to the Pinterest and then back to Kittl. &lt;/p&gt;

&lt;p&gt;I played around with leftover ideas for the past challenge, but haven’t posted anything. Then I got curios how Kittl is making money, so I looked around what is their business proposition, how they build a community, checked multiple videos they posted on &lt;a href="https://www.youtube.com/@Kittldesign/videos"&gt;Youtube&lt;/a&gt; (lots of quality content there, highly recommend to check it out if you are interested), then researched what’s happening in POD (print on demand) domain, watched a bunch more videos from influencers, creators and debunkers to broaden the understanding of supply and demand…&lt;/p&gt;

&lt;p&gt;At some point I got back to Kittle and stumbled into &lt;a href="https://www.kittl.com/career"&gt;Careers&lt;/a&gt; page. There was an open position for &lt;strong&gt;Senior Frontend Engineer (Rendering)&lt;/strong&gt; role with some more useful information about the team and their business. But on top of that there was this requirement that got most of my attention:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Domain Knowledge&lt;/strong&gt;: Vector graphics and SVG manipulation, with experience in rendering and displaying SVGs. Proficiency in Canvas 2D is a plus.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I skimmed the rest of the description, putting mental checkmarks against skills I had under my belt and got back to &lt;code&gt;Domain Knowledge&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What would be the perfect demo to leave positive impression during interview if I would wanted to get this role? Now, this sound like something than can feed my curiosity and exploration itch for quite a while!&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;If you wonder what this is all about and whether you should continue reading this, I’ll tell you. &lt;/p&gt;

&lt;p&gt;This is an article about how you can compose expertise in different vaguely related fields into something new. It’s about self-doubt and perseverance. How one should start small, make even smallest steps, but still walking forward. How complex tasks can be chunked into smaller, more digestible pieces and then reassembled back. How everything is achievable if you put your fear and doubt on hold and carry on till the goal you set is reached.&lt;/p&gt;

&lt;p&gt;Still with me? Good! Let’s go!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stars Align
&lt;/h2&gt;

&lt;p&gt;Nowadays I am a Lead Frontend Developer at &lt;a href="https://www.findlabs.io/"&gt;FindLabs&lt;/a&gt;, but I was trading my time for about 10 years as UI/UX designer designing interfaces for a wide range of different applications and domains. I had plenty hands on experience using vector based tools - CorelDraw, Illustrator, Photoshop (still my favorite one) and Figma - to design and prepare graphics for production (both print and on-screen).&lt;/p&gt;

&lt;p&gt;As a matter of fact, I also explored SVG internals, capabilities and limitations and had bunch of experiments with SVG manipulation, when I was trying to switch my career from design into development field. &lt;a href="https://dribbble.com/MaxStalker"&gt;My Dribbble profile&lt;/a&gt; still have some of them, alongside Canvas and CSS sandboxes. &lt;/p&gt;

&lt;p&gt;I was in awe that SVG have native support for filters (blurs, shadows, complex color compositions, etc.), animation and even interactivity (albeit limited)!&lt;/p&gt;

&lt;p&gt;And canvas felt almost natural and invoked heavy nostalgia from the first time I touched keyboard and wrote primitive program to draw a house out of lines utilizing Basic. Later on I had a chance to broaden my expertise, when I was doing my hobby game project with &lt;a href="https://pixijs.com/"&gt;Pixi&lt;/a&gt; and small bits and pieces on FindLabs pages.&lt;/p&gt;

&lt;p&gt;So, yeah. I wasn’t going blindly into the battlefield 😅&lt;/p&gt;

&lt;h2&gt;
  
  
  What to build?
&lt;/h2&gt;

&lt;p&gt;Kittle provides you with a set of tools to create impressive vector and bitmap based designs using only browser. Which makes it readily available and accessible for everyone with a computer and a mouse. No need to install “heavy” and expensive software. You can start creating right after you register!&lt;/p&gt;

&lt;p&gt;One of the coolest features I’ve seen in Kittl -  which is missing in, for example, Figma - is text styles and warping based on a curve. Like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F18zbm86mcl7i22e095vq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F18zbm86mcl7i22e095vq.png" alt="Align text to curve" width="600" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is powerful and common effect, which allows you to create dynamic designs. I’d say it’s a “staple” one.&lt;/p&gt;

&lt;p&gt;In order to implement something similar you will need to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how SVG constructs vector image&lt;/li&gt;
&lt;li&gt;how coordinate system works in SVG&lt;/li&gt;
&lt;li&gt;how text can be represented in SVG format&lt;/li&gt;
&lt;li&gt;what are Bezier curves and how they are defined in SVG format&lt;/li&gt;
&lt;li&gt;how we can control individual points&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How &lt;strong&gt;WE&lt;/strong&gt; gonna do it?
&lt;/h2&gt;

&lt;p&gt;Kittl feature is quite complex, but we will start small. Let’s try to modify the corners of the rectangular shape based on the slope of the straight line. We will assume that leftmost point of rectangle perfectly aligns with left side of rectangle and the same is true for the right side.&lt;/p&gt;

&lt;p&gt;For any point on the edge of rectangle, we will take &lt;code&gt;x&lt;/code&gt; coordinate of the point, project it on the guide line to calculate the &lt;code&gt;y&lt;/code&gt; difference of that point, relative to it’s edge. This will give us the difference we need to apply to original point.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wzmc0f20471yfd9szgb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wzmc0f20471yfd9szgb.png" alt="Basic Idea" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's start
&lt;/h2&gt;

&lt;p&gt;Instead of going “whole mile” with using something like React template, we will create a blank HTML file and populate it with minimum content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt;
          &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"X-UA-Compatible"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"ie=edge"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;SVG Alteration Study&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we will open Figma, create rectangle, convert it to outlines (this is important, since we want to adjust position of individual points), slightly offset the points up and to the side (I will explain why in a bit), add another line below it (we will use it as guide) and export it. Then open file with your text editor (I have Notepad here, it’s more than enough). This is what I got here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"640"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"480"&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 640 480"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/svg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"M146.034 288.994L150.967 140.994L498.945 139.006L491.052 287.005L146.034 288.994Z"&lt;/span&gt; &lt;span class="na"&gt;stroke=&lt;/span&gt;&lt;span class="s"&gt;"#0F66EA"&lt;/span&gt; &lt;span class="na"&gt;stroke-width=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"M145 366L499 326"&lt;/span&gt; &lt;span class="na"&gt;stroke=&lt;/span&gt;&lt;span class="s"&gt;"#00B347"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Plug that into the body tag and open the page in browser. Plain boring pair of rectangle and a line should appear:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faq253hay92n112zq3zt6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faq253hay92n112zq3zt6.png" alt="Boring rectangle" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But boring is good! It will allow us to manually adjust the values and see how it affects the output. &lt;/p&gt;

&lt;p&gt;Let’s examine our SVG in detail. We can see that viewbox of our canvas is 640px wide and 480px. That will be our working area. Anything that would go outside of bounds would be cropped. You can think about it as a &lt;code&gt;camera&lt;/code&gt;. Also notice, even though we have &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; properties on &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; tag - those represent browser dimensions of SVG container, not the working area size. We can make it smaller or bigger if needed, while keeping the same logic and inner elements.&lt;/p&gt;

&lt;p&gt;Then we have two paths. First one is most likely define our “rectangular”, since it’s &lt;code&gt;d&lt;/code&gt; value (which is responsible for path definition) have more data in it. Second one is our guide line. Let’s add &lt;code&gt;id&lt;/code&gt; property to both of them, so we could reference them later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"640"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"480"&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 640 480"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/svg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"target"&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"M146.034 288.994L150.967 140.994L498.945 139.006L491.052 287.005L146.034 288.994Z"&lt;/span&gt; &lt;span class="na"&gt;stroke=&lt;/span&gt;&lt;span class="s"&gt;"#0F66EA"&lt;/span&gt; &lt;span class="na"&gt;stroke-width=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"guide"&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"M145 366L499 326"&lt;/span&gt; &lt;span class="na"&gt;stroke=&lt;/span&gt;&lt;span class="s"&gt;"#00B347"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Back to the &lt;code&gt;d&lt;/code&gt; property. Take a look at guide’s path - &lt;code&gt;M145 366L499 326&lt;/code&gt; . That’s a bit cryptic isn’t it? But inside of it there is a set of instructions how to plot this line. Let’s modify it to look like a tabular data, using characters like &lt;code&gt;M&lt;/code&gt; and &lt;code&gt;L&lt;/code&gt; as a marker to start a new line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;M 145 366
L 499 326
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ha, now this is a bit easier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;capital &lt;code&gt;M&lt;/code&gt; instruction will move the “tip” of your pen to a specific location (X, Y) relative to (0, 0) point and will wait for next instruction.&lt;/li&gt;
&lt;li&gt;capital &lt;code&gt;L&lt;/code&gt; will draw a line from current “tip” position to (X, Y) coordinate (relative to zero point)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Meaning those two lines of instructions will move the pen to &lt;strong&gt;(145, 366)&lt;/strong&gt; and then draw a line to &lt;strong&gt;(499, 326).&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that &lt;code&gt;L&lt;/code&gt; instruction will keep the tip at &lt;strong&gt;(499, 326).&lt;/strong&gt;  If we would write another &lt;code&gt;L&lt;/code&gt; instruction, for example, &lt;code&gt;L 520, 350&lt;/code&gt; it will connect points at &lt;strong&gt;(499, 326)&lt;/strong&gt; and &lt;strong&gt;(520, 350)&lt;/strong&gt;. &lt;br&gt;
Even though it doesn’t affect how we approach the solution, it’s important to understand the process in details.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now to our &lt;code&gt;target&lt;/code&gt; path. We will do the same - split instructions on individual lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;M 146.034 288.994
L 150.967 140.994
L 498.945 139.006
L 491.052 287.005
L 146.034 288.994
Z
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s round decimal parts on points to closest integer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;M 146 289
L 150 140
L 498 139
L 491 287
L 146 289
Z
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Capital &lt;code&gt;Z&lt;/code&gt; instructions signifies that shape is closed and can be &lt;code&gt;filled&lt;/code&gt; with color. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can also define multiple overlapping paths, dividing the definition with Z instructions. We will see the example later on, when we would try to warp the text.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s translate it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;M&lt;/strong&gt;ove cursor to (146, 289)&lt;/li&gt;
&lt;li&gt;Draw a &lt;strong&gt;L&lt;/strong&gt;ine (146, 289) → (150, 140)&lt;/li&gt;
&lt;li&gt;Draw a &lt;strong&gt;L&lt;/strong&gt;ine (150, 140) → (498, 139)&lt;/li&gt;
&lt;li&gt;Draw a &lt;strong&gt;L&lt;/strong&gt;ine (489, 139) → (491, 287)&lt;/li&gt;
&lt;li&gt;Draw a &lt;strong&gt;L&lt;/strong&gt;ine (491, 287) → (146, 289)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Z&lt;/strong&gt;e end&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we understand how shapes and paths are created, so we can edit them! We can try to create our own parser (which I did 🙈) , but let’s use some existing solution instead. I’ve found &lt;a href="https://www.npmjs.com/package/parse-svg-path"&gt;parse-svg-path&lt;/a&gt; library, which will do the job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add complexity
&lt;/h2&gt;

&lt;p&gt;Let’s initialize our project with &lt;strong&gt;pnpm&lt;/strong&gt; and &lt;strong&gt;Vite&lt;/strong&gt;, so we can utilize 3rd party libraries in the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm init
pnpm add vite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then install &lt;code&gt;prettier&lt;/code&gt; (to keep the code nice and tidy) and &lt;code&gt;parse-svg-path&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add prettier parse-svg-path
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add dev command to scripts in &lt;code&gt;package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;  "scripts": {
    "dev": "vite"
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make &lt;code&gt;index.html&lt;/code&gt; and plug the code from above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt;
          &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"X-UA-Compatible"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"ie=edge"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;SVG Alteration Study&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"640"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"480"&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 640 480"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/svg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"target"&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"M146.034 288.994L150.967 140.994L498.945 139.006L491.052 287.005L146.034 288.994Z"&lt;/span&gt; &lt;span class="na"&gt;stroke=&lt;/span&gt;&lt;span class="s"&gt;"#0F66EA"&lt;/span&gt; &lt;span class="na"&gt;stroke-width=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"guide"&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"M145 366L499 326"&lt;/span&gt; &lt;span class="na"&gt;stroke=&lt;/span&gt;&lt;span class="s"&gt;"#00B347"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"main.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;main.js&lt;/code&gt; and &lt;code&gt;utils&lt;/code&gt; files and put some simple code to make sure our Vite setup is working properly:&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="c1"&gt;// this goes into utils.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;hello&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="s2"&gt;Hello, world!&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="c1"&gt;// ------------------------------------------------------&lt;/span&gt;
&lt;span class="c1"&gt;// and this is our main.js&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;hello&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;./utils&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run &lt;code&gt;pnpm run dev&lt;/code&gt; and you should see the page with our rectangle and &lt;code&gt;hello world&lt;/code&gt; in the console. Well done! 👍&lt;/p&gt;

&lt;h3&gt;
  
  
  Geometry Time ⌚
&lt;/h3&gt;

&lt;p&gt;In order to calculate the offset we need to apply to the point, we can use basic geometry a devise a ratio using points coordinates:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fued4xgepljribkycpdnt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fued4xgepljribkycpdnt.png" alt="Offset calculation" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the left hand side we have our Y offset and on the right we have ratio in the range from 0 to 1 multiplied by maximum offset. Let’s capture this in form of utility function we can use later.&lt;/p&gt;

&lt;p&gt;First let’s check what &lt;code&gt;parse-svg-path&lt;/code&gt; library will provide us. This way we won’t need to make extra conversions later on and make our utility work with formatted data right away:&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="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;m1 2 3 4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; [['m',1,2],['l',3,4]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Right, so it will be array of arrays. Got it! &lt;/p&gt;

&lt;p&gt;Our utility function will accept a tuple of tuples for guide points as first param and another tuple for point we want to offset.&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;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getOffset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;guidePoints&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;offsetPoint&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;x0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;guidePoints&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;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;point&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;ratio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;x0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;x0&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;maxOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;y1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;y0&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ratio&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;maxOffset&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Back to our &lt;code&gt;main.js&lt;/code&gt;:&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;parse&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;parse-svg-path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Grab nodes&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;guide&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;guide&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="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;target&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Extract path definitions&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;guidePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;guide&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;d&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="nx"&gt;targetPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Parse points&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;guidePoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;guidePath&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;targetPoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetPath&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;guidePoints&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Run, Forest, run!&lt;/span&gt;
&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This will grab the DOM nodes, extract paths from them and try to parse guide points:&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="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;M&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;145&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;366&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="s2"&gt;L&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;499&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;326&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;That’s good! Now, since we know that this path will always have only two points (since we control how it is created) and parsing it will produce known result we can convert it to desired shape - something that &lt;code&gt;getOffset&lt;/code&gt; can consume. We will use &lt;code&gt;.map&lt;/code&gt; method on array and simply slice first value:&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;guidePoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;guidePath&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;point&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will give us clean pair of tuples to use as guide points.&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="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;145&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;366&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;499&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;326&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;Next we will create a mapper for targetPath. We will use &lt;a href="https://javascript.info/currying-partials"&gt;currying&lt;/a&gt; to create a function, which will return us another function, which then be applied to every point in our parsed instruction set via &lt;code&gt;.map&lt;/code&gt; method:&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;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;guidePoints&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="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;point&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;instruction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;point&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;instruction&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Z&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;point&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// calculate offset&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getOffset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;guidePoints&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="c1"&gt;// apply it to Y coordinate&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// plug it back into instruction set&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;instruction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newY&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;And apply it:&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;targetPoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetPath&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;offsetPoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;targetPoints&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="nf"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;guidePoints&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we will output the result into console we will see that Y coordinate of the point actually changed, compared to reference (targetPoints). Though right now it’s in array form and to display it we need to convert it back to path definition. Let’s implement &lt;code&gt;zip&lt;/code&gt; function that will do just that:&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;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instructionSet&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;instructionSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;instruction&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="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;instruction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&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="dl"&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;Import it in &lt;code&gt;main.js&lt;/code&gt; and apply to &lt;code&gt;offsetPoints&lt;/code&gt;:&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;parse&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;parse-svg-path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;zip&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;./utils&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;offsetPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offsetPoints&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;offsetPath&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will produce nice and clean output:&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="nx"&gt;M&lt;/span&gt; &lt;span class="mf"&gt;146.034&lt;/span&gt; &lt;span class="mf"&gt;288.87716384180794&lt;/span&gt;
&lt;span class="nx"&gt;L&lt;/span&gt; &lt;span class="mf"&gt;150.967&lt;/span&gt; &lt;span class="mf"&gt;140.3197627118644&lt;/span&gt;
&lt;span class="nx"&gt;L&lt;/span&gt; &lt;span class="mf"&gt;498.945&lt;/span&gt; &lt;span class="mf"&gt;99.01221468926553&lt;/span&gt;
&lt;span class="nx"&gt;L&lt;/span&gt; &lt;span class="mf"&gt;491.052&lt;/span&gt; &lt;span class="mf"&gt;247.9030790960452&lt;/span&gt;
&lt;span class="nx"&gt;L&lt;/span&gt; &lt;span class="mf"&gt;146.034&lt;/span&gt; &lt;span class="mf"&gt;288.87716384180794&lt;/span&gt;
&lt;span class="nx"&gt;Z&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s plug it back into our SVG canvas. &lt;/p&gt;

&lt;p&gt;Create another path on the canvas, add &lt;code&gt;offsetShape&lt;/code&gt; id so it can be referenced and adjust the style of &lt;code&gt;target&lt;/code&gt; path to be displayed with dashed stroke line:&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;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;"640"&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;"480"&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 640 480"&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;"none"&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="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;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"target"&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;"M146.034 288.994L150.967 140.994L498.945 139.006L491.052 287.005L146.034 288.994Z"&lt;/span&gt; &lt;span class="na"&gt;stroke&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"#CCC"&lt;/span&gt; &lt;span class="na"&gt;stroke-width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;stroke-dasharray&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"4 6"&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;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"guide"&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;"M145 366L499 326"&lt;/span&gt; &lt;span class="na"&gt;stroke&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"orange"&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;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"offsetShape"&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;""&lt;/span&gt; &lt;span class="na"&gt;stroke&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"green"&lt;/span&gt; &lt;span class="na"&gt;stroke-width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"2"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the code in &lt;code&gt;main.js&lt;/code&gt; :&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="c1"&gt;// Apply offset&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;offsetPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offsetPoints&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;offsetShape&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;offsetShape&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;offsetShape&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;offsetPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;..and voilà 👇&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7y8nw39z0s2rwfltgq5u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7y8nw39z0s2rwfltgq5u.png" alt="Skewed!" width="637" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can play around with second coordinate of the guide path to check how it affects the target shape. For example, let’s slope it down instead of up. The beauty of our setup is that we only need to change the d parameter of the guide path and refresh the page (actually Vite will do refreshing part, if you still have dev server running):&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;path&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;"guide"&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;"M145 366L499 420"&lt;/span&gt; &lt;span class="na"&gt;stroke&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"orange"&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7g3n0l2bx14e37cvtaf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7g3n0l2bx14e37cvtaf.png" alt="Skewed again" width="634" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s a win! We can apply this to any shape now, right?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjqvjop9xd6bfyim5r6g1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjqvjop9xd6bfyim5r6g1.png" alt="Padme suspects something" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  P.S.
&lt;/h2&gt;

&lt;p&gt;Second chapter will be more fun, I promise. Stay tuned! 😁&lt;br&gt;
In the mean time, I’ve compiled the code from above into sandbox, so you can &lt;a href="https://codesandbox.io/p/sandbox/svg-manipulation-w5x2gr"&gt;fork it here&lt;/a&gt; 👈&lt;/p&gt;

</description>
      <category>svg</category>
      <category>javascript</category>
      <category>math</category>
      <category>funfunfun</category>
    </item>
    <item>
      <title>Darling, I converted our perfectly fine SPA application into SSR: Part 2</title>
      <dc:creator>Max Daunarovich</dc:creator>
      <pubDate>Tue, 14 May 2024 09:59:54 +0000</pubDate>
      <link>https://dev.to/findlabs/darling-i-converted-our-perfectly-fine-spa-application-into-ssr-part-2-185n</link>
      <guid>https://dev.to/findlabs/darling-i-converted-our-perfectly-fine-spa-application-into-ssr-part-2-185n</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;If you're just tuning in, the &lt;a href="https://dev.to/findlabs/flowdiver-the-road-to-ssr-part-1-448k"&gt;first chapter&lt;/a&gt; detailed our approach to creating the SPA (Single Page Application) version of &lt;a href="https://www.flowdiver.io/"&gt;Flowdiver&lt;/a&gt;. We explained the reasoning behind our decisions and the challenges we encountered.👍&lt;/p&gt;

&lt;p&gt;In this chapter, we'll discuss our experiences in migrating the SPA to a Next.js framework, employing an SSR (Server-Side Rendering) strategy to tackle some of the ongoing "problems."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lab
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Preparation
&lt;/h3&gt;

&lt;p&gt;To ensure that our decision was the right one, we took some time to evaluate other existing solutions on the market.&lt;/p&gt;

&lt;p&gt;Next.js stood out due to its large community, the abundance of examples, and the availability of templates. However, the "recent" shift from a pages router to an app router, along with the introduction of client and server components, and the overall feeling that Next.js might be too cumbersome for our needs, sent us on a quest for new horizons.&lt;/p&gt;

&lt;h3&gt;
  
  
  Qwik
&lt;/h3&gt;

&lt;p&gt;We just wrapped up our &lt;a href="https://www.findlabs.io/"&gt;FindLabs corporate website&lt;/a&gt; using Qwik and thought we could utilize our newly acquired experience.&lt;/p&gt;

&lt;h4&gt;
  
  
  Pros
&lt;/h4&gt;

&lt;p&gt;Qwik was incredibly fast and straightforward to set up for SEO and achieving good web metrics. The clear separation between client and server-side code, utilizing &lt;code&gt;useVisibleTask$()&lt;/code&gt; was a breeze to manage and didn't require complex mental gymnastics to understand the migration process.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cons
&lt;/h4&gt;

&lt;p&gt;The SPA version heavily utilizes &lt;a href="https://styled-components.com/"&gt;Styled Components&lt;/a&gt;, and although it's feasible to use the &lt;code&gt;styled-vanilla-extract&lt;/code&gt; library and migrate the code with minimal changes, some parts would still need refactoring since CSS is pre-built during compilation. We've previously used the &lt;code&gt;useStylesScoped$&lt;/code&gt; function while building a corporate website, but it often felt more like a hack than a solid solution.&lt;/p&gt;

&lt;p&gt;Another significant challenge was the &lt;a href="https://www.patterns.dev/react/render-props-pattern/"&gt;render props&lt;/a&gt; pattern. We heavily rely on this for our table component to ensure a high level of customization and abstraction. However, Qwik's architecture is fundamentally different—the framework aims to fragment the code into the smallest possible chunks and load them in parallel. This means it attempts to &lt;a href="https://qwik.dev/tutorial/props/closures/"&gt;serialize your render functions&lt;/a&gt;, which becomes a mess real fast.&lt;/p&gt;

&lt;p&gt;Additionally, the contexts that Flowdiver heavily depends on would be unworkable and would require a complete redesign into a new composition. While these changes are manageable, we wanted to minimize disruption as much as possible.&lt;/p&gt;

&lt;p&gt;Considering all these pros and cons, we decided to put this on the bench for a better use case 🙏.&lt;/p&gt;

&lt;h3&gt;
  
  
  Waku
&lt;/h3&gt;

&lt;p&gt;While researching server-side components, we discovered &lt;strong&gt;&lt;a href="https://waku.gg/"&gt;Waku&lt;/a&gt;&lt;/strong&gt;—a minimal React framework that facilitates the use of SSR (Server-Side Rendering) and SSG (Static Site Generation) approaches effortlessly 👍.&lt;/p&gt;

&lt;h4&gt;
  
  
  Pros
&lt;/h4&gt;

&lt;p&gt;Waku struck the perfect balance we were looking for—a compact footprint on both client and server sides, along with a clear division of domains.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://waku.gg/"&gt;front page&lt;/a&gt; did an excellent job of clearly and efficiently explaining the concepts of client-/server-side components: data fetching, SEO, routing—all the puzzle pieces began to fall into place.&lt;/p&gt;

&lt;p&gt;We bootstrapped an app and attempted a minimal setup migration. The community and the author on Discord were incredibly responsive, offering valuable tips and explanations on various concepts and strategies.&lt;/p&gt;

&lt;p&gt;Sounds like a dream, right? Well, yeah...&lt;/p&gt;

&lt;h4&gt;
  
  
  Cons
&lt;/h4&gt;

&lt;p&gt;The unstyled concept was functioning flawlessly, but we had to abandon &lt;code&gt;styled-components&lt;/code&gt; almost immediately. The documentation covered CSS modules well, but lacked information on styled components and similar approaches. At that point, we realized that sticking to a well-tried solution might backfire... 🙈&lt;/p&gt;

&lt;p&gt;Similar to &lt;code&gt;Qwik&lt;/code&gt;, the use of contexts in Waku also appeared to be challenging and required significant refactoring to manage props drilling effectively.&lt;/p&gt;

&lt;p&gt;Moreover, as we were experimenting with it, new features were continuously being released, making the framework feel somewhat unstable and experimental as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s Next?
&lt;/h3&gt;

&lt;p&gt;In the end, we found ourselves back where we started, but with newfound knowledge and confidence in our choice.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Pros&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Next.js stands out as the most seasoned of all React-based full-stack frameworks. With dozens of examples and templates available, and hundreds of resolved issues on GitHub backed by multiple contributors, there's reassurance that it won’t just disappear over the weekend because the original author decided to move on from his project.&lt;/p&gt;

&lt;p&gt;It’s also a match made in heaven for Vercel deployment. True to its promises, some features (notably &lt;a href="https://nextjs.org/docs/app/api-reference/next-config-js/partial-prerendering"&gt;PPR&lt;/a&gt;) are exclusively viable on Vercel due to the tight integration and finely tuned setup.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Cons&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Server-side components still didn't make much sense with us at that time 😅&lt;/p&gt;

&lt;p&gt;However, we decided it was time to shed our apprehensions and start tinkering!&lt;/p&gt;

&lt;h2&gt;
  
  
  Take 1 - Heads-on!
&lt;/h2&gt;

&lt;p&gt;We opted for the &lt;code&gt;app router&lt;/code&gt; as it appeared more modern and future-proof. Moreover, it seemed like a logical next step from &lt;a href="https://reactrouter.com/en/main"&gt;react-router&lt;/a&gt;. It also supports &lt;code&gt;server components&lt;/code&gt;, which were crucial for our application. Plus, the &lt;a href="https://nextjs.org/docs/app/building-your-application/routing/parallel-routes"&gt;layout fragments&lt;/a&gt; really seemed promising!&lt;/p&gt;

&lt;p&gt;With our mindset focused on minimal changes and limited time commitment, we set up the basics that would allow us to work with styled-components and render them on a blank page. Once this foundation was laid, we began to &lt;code&gt;migrate&lt;/code&gt; (or more accurately, copy/paste 😅) our components into the Next.js-based repository.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;One component, &lt;br&gt;
Two components, done! &lt;br&gt;
Errors during compilation, &lt;br&gt;
None!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Well, not exactly. We were soon overwhelmed with errors like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;You&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;re importing a component that needs createContext. It only works in a Client
Component but none of its parents are marked with "use client", so they&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;re&lt;/span&gt; &lt;span class="nx"&gt;Server&lt;/span&gt;
&lt;span class="nx"&gt;Components&lt;/span&gt; &lt;span class="nx"&gt;by&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="nx"&gt;Learn&lt;/span&gt; &lt;span class="nx"&gt;more&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//nextjs.org/docs/getting-started/react-essentials&lt;/span&gt;
  &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;But we came prepared, haha! We just needed to tag some files with &lt;code&gt;use client&lt;/code&gt;. So this one, that one... and that one too!&lt;/p&gt;

&lt;p&gt;In the end, we marked almost EVERYTHING with &lt;code&gt;use client&lt;/code&gt; and inadvertently exposed our Hasura token to the public domain. Not exactly what we had planned, but hey, at least it was functioning. A living and “breathing” system. Yes! 👍&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Take 2 - We Require More Minerals&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The next step was to migrate the rest of the pages. So, we thought, why not transfer about a hundred files at once? What could possibly go wrong? Fortunately, with our root layout file flagged as &lt;code&gt;use client&lt;/code&gt;, everything below it was also tagged as "dirty," and thus the compiler remained silent, untroubled by our actions.&lt;/p&gt;

&lt;p&gt;However, trouble started brewing as soon as we began refactoring pages into server-side components...&lt;/p&gt;

&lt;p&gt;Here’s the snag: &lt;code&gt;client components&lt;/code&gt; can’t import &lt;code&gt;server components&lt;/code&gt;. Yet, we desperately needed that &lt;code&gt;ThemeProvider&lt;/code&gt; from &lt;code&gt;styled-components&lt;/code&gt; to function correctly. Moreover, various other context providers needed to be positioned at the top, so they were accessible for data reading across the board.&lt;/p&gt;

&lt;p&gt;We plunged into the refactoring, attempting to determine what should remain a &lt;code&gt;server component&lt;/code&gt; and what needed to be client-side. Yet, a relentless cascade of - &lt;strong&gt;&lt;em&gt;It only works in a Client Component&lt;/em&gt;&lt;/strong&gt; - made it seem like we were running in circles, getting nowhere fast.&lt;/p&gt;

&lt;p&gt;It was time to pull back, reassess, and develop a new "pipeline" for how we would transition our SPA into the promised land of SSR.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Take 3 - Slow, but Steady&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We stripped everything down to the bare bones and began piecing the pages back together, labeling only the absolutely essential elements as client components. Fortunately, most of these necessities were related to &lt;code&gt;styled-components&lt;/code&gt; and nestled within the &lt;code&gt;styles.tsx&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;Hooks, particularly &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useSearchParams&lt;/code&gt;, were reliable indicators that a file belonged on the client side of the network boundary. However, some could seamlessly receive &lt;code&gt;searchParams&lt;/code&gt; props directly from &lt;code&gt;page.tsx&lt;/code&gt; without switching allegiances.&lt;/p&gt;

&lt;p&gt;We tackled the migration one route at a time, and it all seemed to be going smoothly, until we encountered the more complex pages—like those for accounts or transactions:&lt;/p&gt;

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

&lt;p&gt;These pages featured some static elements—like status and transfers at the top—and more dynamic components controlled by tabs. We considered collecting all the data and distributing it to child components via context, but that approach would only be effective in this specific scenario. The account page, in particular, demanded more diverse data, which would necessitate pulling from the server or refreshing the page with new search parameters.&lt;/p&gt;

&lt;p&gt;This led us to the decision to utilize &lt;a href="https://nextjs.org/docs/app/building-your-application/routing/parallel-routes"&gt;parallel routes&lt;/a&gt; for implementing the tabs. This strategy allowed us to establish clear distinctions in data fetching for each tab without the complication of tight coupling. As a result, the render tree remained neat and tidy, while all the logic was appropriately segregated within its own domains:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8kx310nvfegc1aqrqf5y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8kx310nvfegc1aqrqf5y.png" alt="Image description" width="279" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7u5xbjilh0pzwel6ilra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7u5xbjilh0pzwel6ilra.png" alt="Image description" width="201" height="246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point &lt;code&gt;layout.tsx&lt;/code&gt; in the sub-route &lt;code&gt;/tx/[id]&lt;/code&gt; operates as a component, alongside &lt;code&gt;page.tsx&lt;/code&gt; and all the parallel routes. We used &lt;code&gt;Suspense&lt;/code&gt; to effectively display loading states, ensuring that user experience remains smooth and uninterrupted during data fetching. Importantly, we carefully manage security by not exposing our token when fetching data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExbDZndTlod2tzcmR3Y2ZzdGh2NjV5OGI4Zm53dmhsNGZhb2d5cno1aSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/yJFeycRK2DB4c/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExbDZndTlod2tzcmR3Y2ZzdGh2NjV5OGI4Zm53dmhsNGZhb2d5cno1aSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/yJFeycRK2DB4c/giphy.gif" alt="Noice" width="450" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Houston, We Have a Problem
&lt;/h2&gt;

&lt;p&gt;While most of the components and pages function as intended, some fall short...&lt;/p&gt;

&lt;p&gt;Take our custom table component, for instance. In the SPA setup, displaying the loading state was straightforward—we simply retrieved it from the context. However, in the SSR framework, components like the table header and pagination controls need to be visible before the data is fetched. This necessitated some serious refactoring and clever component rearrangement.&lt;/p&gt;

&lt;p&gt;Before, our context provider enveloped the table; now, this needs to be shifted into the &lt;code&gt;children&lt;/code&gt; block because data fetching occurs server-side, across the network boundary. We refactored the code, injecting additional props into the table (since it could no longer access these from the context) and ended up with the following configuration:&lt;/p&gt;

&lt;p&gt;While most of the components and pages works as intended, some don’t…&lt;/p&gt;

&lt;p&gt;For example, our bespoke table component. In SPA implementation it was easy to show loading state - we can simply pull it from context. But in SSR our table  - at least header and pagination controls - should be visible before data is fetched. That was asking for a refactoring and some component juggling.&lt;/p&gt;

&lt;p&gt;Previously, we had context provider wrapping up table, now it should be part of the &lt;code&gt;children&lt;/code&gt; block, cause data fetching is on server side of network boundary. We refactored that code, passed extra props to the table (cause now it couldn’t read them from context) and end up with following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftyxk2b2nicb5zc0174ys.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftyxk2b2nicb5zc0174ys.png" alt="Image description" width="452" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AccountTransactionsProvider&lt;/code&gt; is a server component that fetches the data and then passes it into &lt;code&gt;TableDataProvider&lt;/code&gt; via props. And &lt;code&gt;TableDataProvider&lt;/code&gt; is a client component that can properly work with contexts:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo8gjvv9hn5ijk8vufd47.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo8gjvv9hn5ijk8vufd47.png" alt="Image description" width="517" height="131"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That was an &lt;code&gt;Aha!&lt;/code&gt; moment in understanding how to compose server and client components. You can’t &lt;code&gt;import&lt;/code&gt; server components from client boundary, BUT, you can render the result of their execution in your client components. You just need to pass them as &lt;code&gt;children&lt;/code&gt; or render props!&lt;/p&gt;

&lt;p&gt;So the following composition is perfectly fine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RootServerComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* &amp;lt;--------- SERVER */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ClientComponent&lt;/span&gt; &lt;span class="na"&gt;renderProp&lt;/span&gt;&lt;span class="p"&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="nc"&gt;SDFComponent&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;gt;&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* &amp;lt;--------- CLIENT */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* the following code will be passed as "children" */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SmallServerComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* &amp;lt;--------- SERVER */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InnerClientComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* &amp;lt;--------- CLIENT */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ServerCounterComponent&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* &amp;lt;--------- SERVER */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;InnerClientComponent&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;SmallServerComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... and then we can control where to put SDFComponent in layout */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ClientComponent&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;RootServerComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you prefer not to manage this composition at the root level and aim for modularity, you can achieve this by enhancing your &lt;code&gt;ClientComponent&lt;/code&gt; to accept additional properties—for example, a &lt;code&gt;renderProp&lt;/code&gt;. You can then trust that it will include the necessary representation, allowing you to construct your layout in any preferred manner.&lt;/p&gt;

&lt;p&gt;Personally, I consider the &lt;code&gt;Render Props&lt;/code&gt; pattern to be one of React's most powerful features.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Final Hurdle
&lt;/h2&gt;

&lt;p&gt;The very last “challenge” involved transitioning from the &lt;code&gt;useSearchParams&lt;/code&gt; hook provided by &lt;code&gt;react-router&lt;/code&gt; to its counterpart in &lt;code&gt;next.js&lt;/code&gt;. The twist with Next.js is that while it lets you read the search parameters, it doesn’t offer a direct setter. This requires a more hands-on approach involving a trio of hooks: &lt;code&gt;usePathname&lt;/code&gt;, &lt;code&gt;useRouter&lt;/code&gt;, and &lt;code&gt;useSearchParams&lt;/code&gt;. To manage this, you have to construct your own setter. The process would typically look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSearchParams&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;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouter&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;pathname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;usePathname&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// later in code&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&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;field&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fieldValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fieldValue&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="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;scroll&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We moved this into a convenient hook, so we could reuse the code and update multiple parameters simultaneously—a necessity for managing the filters in our table. &lt;/p&gt;

&lt;h2&gt;
  
  
  Cherries on top 🍒🍰
&lt;/h2&gt;

&lt;p&gt;Leveraging Next.js, a server-side solution, made setting OpenGraph metadata, titles, and descriptions for our pages simply a breeze. This final requirement was almost effortlessly fulfilled. However, we encountered a hiccup with &lt;code&gt;@vercel/og&lt;/code&gt;, which refused to render fonts properly, even the &lt;code&gt;bold&lt;/code&gt; variant of the default one.&lt;/p&gt;

&lt;p&gt;After some troubleshooting, we discovered that Noto Sans, included in the package, &lt;a href="https://github.com/vercel/satori/issues/263#issuecomment-1500705357"&gt;only supports a 400 weight&lt;/a&gt;. Attempts to load custom fonts from the file system did not pan out as expected—the documentation and examples lacked clear guidance on implementation. Furthermore, deployment introduced peculiar bugs, even though the local solutions worked just fine.&lt;/p&gt;

&lt;p&gt;Despite these challenges, experimenting with Satori (the library that lets you create SVG/PNG images by defining them with HTML) proved to be quite enjoyable. We would definitely consider using this package in future projects.&lt;/p&gt;

&lt;p&gt;Additionally, caching was readily available right out of the box, allowing us to lessen the load on our servers and enhance the overall user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Postmortem
&lt;/h2&gt;

&lt;p&gt;Aside from the initial confusion surrounding server components, the majority of the migration process unfolded smoothly.&lt;/p&gt;

&lt;p&gt;The groundwork established during the SPA implementation proved to be robust and resilient, carrying us through the migration with only minimal adjustments needed.&lt;/p&gt;

&lt;p&gt;Most of our headaches stemmed from &lt;code&gt;styled-components&lt;/code&gt;. Despite the merits of this CSS-in-JS library, it doesn’t mesh as seamlessly with server components. Traditional CSS methodologies, such as BEM (&lt;a href="https://getbem.com/"&gt;Block, Element, Modifier&lt;/a&gt;), CSS modules, or even utility-first frameworks like Tailwind, would have alleviated many of our difficulties. This lesson is a key takeaway that we plan to carry forward into our future projects.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>casestudy</category>
      <category>typescript</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>This is how we've utilized our expertise and built solid data-driven application</title>
      <dc:creator>Max Daunarovich</dc:creator>
      <pubDate>Fri, 03 May 2024 15:34:55 +0000</pubDate>
      <link>https://dev.to/findlabs/flowdiver-the-road-to-ssr-part-1-448k</link>
      <guid>https://dev.to/findlabs/flowdiver-the-road-to-ssr-part-1-448k</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;One of the key projects &lt;a href="https://www.findlabs.io/"&gt;FindLabs&lt;/a&gt; has created and currently supports is &lt;a href="https://www.flowdiver.io/"&gt;FlowDiver&lt;/a&gt; - the Flow Blockchain block explorer. It allows you to inspect different information about the blockchain, without directly interfacing with it (which can require a specific setup and knowledge). For example, you will be able to explore which transactions were included in a recent block, what arguments and code were used for said transactions and what events were emitted as a side effect of changes to network’s state.&lt;/p&gt;

&lt;p&gt;There was a single solution on a market back then - &lt;strong&gt;FlowScan&lt;/strong&gt; - which was providing the same kind of information, but there were no public API projects could tap into and private one had it’s own issues - inconsistent data, complex data fetching or inability to filter specific results out, etc.&lt;/p&gt;

&lt;p&gt;We’ve seen the potential and interest in the community and started the work from the data layer. When we got the confirmation and understanding the gargantuan scale of the task we bootstrapped front-end app and continued from there.&lt;/p&gt;

&lt;p&gt;This post is about our journey - what decisions we’ve made and where they lead us. Grab a popcorn and prepare for a ride! :)&lt;/p&gt;

&lt;h1&gt;
  
  
  How we tailored it
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Pick your poison
&lt;/h2&gt;

&lt;p&gt;Given our team's collective proficiency within the React ecosystem, we decided to leverage this expertise for our project. Initially, we contemplated utilizing Next.js; however, due to the limited practical experience with this technology among key engineers and the pressing timeline to develop the first prototype, we opted for a Single Page Application(SPA) approach. For bundling, we selected &lt;a href="https://vitejs.dev/"&gt;Vite&lt;/a&gt;, primarily due to its super fast build times, simplicity of configuration, and potential for a nearly seamless transition to server-side rendering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Styled Components
&lt;/h2&gt;

&lt;p&gt;Next key elements are &lt;code&gt;styled-components&lt;/code&gt; and accompanying it &lt;code&gt;styled-system&lt;/code&gt; libraries. These gave us a clear separation of CSS rules at the component level and provided a nice way to implement our building blocks. &lt;/p&gt;

&lt;p&gt;Yes, it increased the initial bundle size, but that chunk would be reusable and would only be loaded once. Additionally, lazy loading the routes allowed us to cleanly split the app into separate blocks, further minimizing the loading time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Atomic System
&lt;/h2&gt;

&lt;p&gt;We were loosely following &lt;a href="https://atomicdesign.bradfrost.com/table-of-contents/"&gt;Atomic Design&lt;/a&gt; principle to slice our interface into reusable parts. The smallest possible elements would be living under &lt;code&gt;components/atoms&lt;/code&gt;, bigger “brothers” and “sisters” would form &lt;code&gt;molecules&lt;/code&gt; which would be composed into &lt;code&gt;organisms&lt;/code&gt;.  This methodology provided a solid foundation and established component composition as the core principle of our design approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Router
&lt;/h2&gt;

&lt;p&gt;React Router v6 was picked as a stable routing solution to support lazy loaded routes, domain code splitting and it was potentially an easier way to port the app to Next.js. Following Atomic Design, we created a &lt;code&gt;pages&lt;/code&gt; folder and gathered files for respective routes there. In retrospect, this was a great decision, which made transition to server-side rendering a breeze. &lt;/p&gt;

&lt;h2&gt;
  
  
  State
&lt;/h2&gt;

&lt;p&gt;Application architecture is rather simple and can be seen as a lose composition of separate modules. Data fetched on a single route is never reused on another route, which makes it easy to describe using React’s &lt;code&gt;useState&lt;/code&gt; and urql’s &lt;code&gt;useQuery&lt;/code&gt; . Occasional calls to chain were sewn together with backend data using &lt;code&gt;useEffect&lt;/code&gt; resolvers. Overall, the system doesn’t require complex state management and data juggling, which made it easier to split tasks between team members and work in parallel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;A good portion of the application consists of tabular representation of data. Data in said tables can be sorted, paginated and filtered. During the design stage we were able to identify repetitive patterns across these component and plan implementation accordingly. &lt;/p&gt;

&lt;p&gt;Disregarding props-drilling technique in favor of a more reliable and elegant solution we looked for inspiration elsewhere. Another project of ours &lt;a href="https://find.xyz/"&gt;.find&lt;/a&gt; was using &lt;a href="https://typesense.org/"&gt;Typesense&lt;/a&gt;/&lt;a href="https://www.algolia.com/"&gt;Algolia&lt;/a&gt; components, which looked a bit like black-box/magic, but at the same time provided a clean approach to build complex and highly customizable solutions.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;Table&lt;/code&gt; component lives within the confines of our data provider and can be expanded with pagination, sorting and filtering solutions. All of the aforementioned parts are decoupled from each other and could be customized for current needs. Some tables are using on-chain data and some use locally stored data. Filtering/sorting logic is purely client-side, while others pull filtered/sorted data directly from the backend and require customized variables for GraphQL queries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hasura, urql and Graphql
&lt;/h2&gt;

&lt;p&gt;Our backend sports a huge Postgress database, which is exposed via Hasura service in the form of a GraphQL endpoint. This endpoint provides a schema which paired with &lt;a href="https://the-guild.dev/graphql/codegen"&gt;graphql-codegen&lt;/a&gt; generator to get accurate representation on the client side with all the necessary types and variables for the hooks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Typescript
&lt;/h2&gt;

&lt;p&gt;While initially we fancied the idea of dropping Typescript to keep momentum and maximum velocity, in the end we are happy we didn’t go that route and decided to do it “right” from the start.&lt;/p&gt;

&lt;p&gt;TypeScript offers several benefits to a React project, particularly when collaborating with multiple team members. It introduces static typing, which helps catch errors during compile-time rather than at runtime. This not only enhances the quality of the code but also cuts down on the time needed for debugging. The clear typing system also makes the code more readable and acts as its own documentation, making it easier for team members to understand one another's work. Additionally, TypeScript provides robust tooling that includes autocompletion, type checking, and advanced refactoring capabilities, all of which significantly boost developer efficiency. Moreover, the use of generated types from codegen has allowed for the expansion of generic types, ensuring accurate typing of table elements. It's akin to watching puzzle pieces fit together perfectly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;Choosing &lt;a href="https://vercel.com/"&gt;Vercel&lt;/a&gt; was a natural decision as it has become the default method for launching apps that are accessible to a wide audience. The simplicity of configuring environment variables, domains, and other settings facilitated this choice. We have implemented feature branch deployment to guarantee that the code is operational and prepared for peer review.&lt;/p&gt;

&lt;h1&gt;
  
  
  What went “wrong”
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Exposed token
&lt;/h2&gt;

&lt;p&gt;We were initially okay with using an exposed token because there were ways to restrict token rights—either by limiting calls to only those from Flowdiver or by rate limiting the data and frequency of requests. However, this was not an ideal solution as we aimed for a scenario where the token would never be exposed to the client.&lt;/p&gt;

&lt;h2&gt;
  
  
  No SEO whatsoever
&lt;/h2&gt;

&lt;p&gt;The technology we chose did not offer an easy way for pages to be indexed by search engines. The control over page titles was subpar—looking at you, Helmet—and definitely needed improvement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Over-engineering
&lt;/h2&gt;

&lt;p&gt;In our quest to perfectly compose complex blocks, we ventured a bit too far into premature optimization. It wasn’t disastrous, but it did mean that some aspects were overcomplicated when they could have been simpler and easier to maintain. We learned our lesson and refactored this overly complex code when we transitioned to a Next.js solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hooks limitations
&lt;/h2&gt;

&lt;p&gt;While the &lt;code&gt;useQuery&lt;/code&gt; hooks from urql provided straightforward and clean access to backend data, things got tricky when we needed to combine data from multiple sources. Hooks have to be called conditionally, which led to more complex logic involving one or more &lt;code&gt;useEffect&lt;/code&gt; hooks. Although urql allows you to call a query directly and convert the result to a promise, hooks were more convenient, so we endured the complexity and later refactored in Next.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  Atomic, shmatomic…
&lt;/h2&gt;

&lt;p&gt;We did our best to adhere to the Atomic design approach when creating components. However, the system sometimes didn’t clearly indicate where components should be placed. In some cases, it was obvious that an &lt;strong&gt;&lt;code&gt;atom&lt;/code&gt;&lt;/strong&gt; could go anywhere, but in other scenarios, it made more sense to position it near a &lt;strong&gt;&lt;code&gt;molecule&lt;/code&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;code&gt;organism&lt;/code&gt;&lt;/strong&gt;, especially if it was seldom reused.&lt;/p&gt;

&lt;p&gt;This approach didn’t break the app but certainly led to an uneasy feeling that the next person to maintain it might face some challenges and a somewhat rough path.&lt;/p&gt;

&lt;h1&gt;
  
  
  What Next?
&lt;/h1&gt;

&lt;p&gt;As we continued to roll out new features, we began to explore what it would take to migrate everything to Next.js. This move could address some of the fundamental issues we faced with our current setup and provide a clearer path for the app's growth.&lt;/p&gt;

&lt;p&gt;Find out how we did it and the challenges we faced in the next chapter! 😉&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>react</category>
      <category>frontend</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Build on Flow: JS Testing - 4. Storage Inspection</title>
      <dc:creator>Max Daunarovich</dc:creator>
      <pubDate>Fri, 26 May 2023 06:21:53 +0000</pubDate>
      <link>https://dev.to/onflow/build-on-flow-js-testing-4-storage-inspection-5e62</link>
      <guid>https://dev.to/onflow/build-on-flow-js-testing-4-storage-inspection-5e62</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://dev.to/maxstalker/build-on-flow-js-testing-3-execute-scripts-and-send-transactions-5hac"&gt;previous episode&lt;/a&gt; of our epic journey, we've discovered how we can interact with Flow Emulator by sending transactions and executing scripts. Today we will continue exploring available functions that help us build quick and easy to read tests for our Cadence contracts.&lt;/p&gt;

&lt;p&gt;Reading simple values from contracts and accounts is a pretty easy task, even if you write all the Cadence code manually. But ensuring that account has proper paths setup or specific item in its collection could be tedious.&lt;/p&gt;

&lt;p&gt;The Framework provides several methods to inspect account storage fast and painlessly.&lt;/p&gt;

&lt;p&gt;Let's start by creating another test suit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @onflow/flow-js-testing make storage-inspection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Inspect Available Paths
&lt;/h2&gt;

&lt;p&gt;To gather all available paths on accounts we will call &lt;code&gt;getPaths&lt;/code&gt; function, which will return an object containing three Sets: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;publicPaths&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;privatePaths&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;&lt;code&gt;storagePaths&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can inspect them as you would do with any other Set.&lt;/p&gt;

&lt;p&gt;Let's confirm that &lt;code&gt;Alice&lt;/code&gt; has all the necessary bits to operate FLOW token (all new accounts do, but this will simplify the process).&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get paths&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Alice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAccountAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&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;publicPaths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;privatePaths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;storagePaths&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPaths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Alice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Newly created account shall have 2 public and 1 storage slot occupied for FLOW Vault&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;publicPaths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;publicPaths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flowTokenBalance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;publicPaths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flowTokenReceiver&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Newly created account doesn't have any private paths&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;privatePaths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// And it should have single storage path for FLOW token vault&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storagePaths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storagePaths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flowTokenVault&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&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;h2&gt;
  
  
  Get Type Restrictions on Path
&lt;/h2&gt;

&lt;p&gt;A common case is to ensure that account has specific capability in its account and ensure specific type restrictions on it to confirm that transactions would work correctly. We can get an extended version of paths with extra information about them via &lt;code&gt;getPathsWithType&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read path types&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;publicPaths&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPathsWithType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&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="nx"&gt;refTokenBalance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;publicPaths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flowTokenBalance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;refTokenBalance&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;refTokenBalance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;restrictionsList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A.ee82856bf20e2aa6.FungibleToken.Balance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;refTokenBalance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;restrictionsList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;refTokenBalance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;haveRestrictions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FungibleToken.Balance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&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;You can comment out those &lt;code&gt;expect&lt;/code&gt; statements and use &lt;code&gt;console.log(refTokenBalance)&lt;/code&gt; to see all available options you can use to assert it's correctness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read Storage Values
&lt;/h2&gt;

&lt;p&gt;Now let's store a value in Alice's storage and try to read it via &lt;code&gt;getStorageValue&lt;/code&gt;. We need to pass account name (i.e. &lt;code&gt;"Alice"&lt;/code&gt;) or address we resolved with &lt;code&gt;getAccountAddress&lt;/code&gt; and storage path&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read storage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Alice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAccountAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;shallPass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;sendTransaction&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
          transaction{
            prepare(signer: AuthAccount){
              signer.save(42, to: /storage/answer)
            }
          }
        `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;signers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Alice&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;storagePaths&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPaths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Alice&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;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getStorageValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;answer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;42&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storagePaths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;answer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// We can also try to read non-existing value, which shall be resolved to null&lt;/span&gt;
  &lt;span class="c1"&gt;// Notice that we pass string here ;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;empty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getStorageValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&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="s2"&gt;empty&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Storage Stats
&lt;/h2&gt;

&lt;p&gt;Another useful method you can emply during account inspection is &lt;code&gt;getStorageStats&lt;/code&gt; - you might need one if you think users might hold huge collections and check how much of the storage it will occupy:&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Read storage stats&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;used&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getStorageStats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;used&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="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&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;h2&gt;
  
  
  Jest Helpers
&lt;/h2&gt;

&lt;p&gt;Last, but not the least, there are a couple Jest helpers to simplify the inspection process and shorten your tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;shallHavePath(account, pathName)&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This function will allow to quickly confirm that path exists on account. Note, that second argument contains a full path, including domain&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get paths&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Alice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAccountAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;shallHavePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/public/flowTokenBalance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;shallHavePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/public/flowTokenReceiver&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;shallHaveStorageValue(account, {props})&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Using this function, we can quickly check storage value—both complex and simple ones. Let's start with simple:&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read storage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Alice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAccountAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;shallPass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;sendTransaction&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
          transaction{
            prepare(signer: AuthAccount){
              signer.save(42, to: /storage/answer)
            }
          }
        `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;signers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Alice&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="c1"&gt;// This time we only need to path path in storage domain&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;shallHaveStorageValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;pathName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;answer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;42&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if we know that value in storage is complex - let's say some NFT or Vault, then we can provide a key to how we can access it and check our expectations:&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compare complex storage value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Alice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAccountAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// We will read "balance" field of the value stored in "/storage/flowTokenVault" slot&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;shallHaveStorageValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;pathName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flowTokenVault&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;balance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.00100000&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is it for today! 😎&lt;br&gt;
Let us know if you think we've missed some valuable examples 😉&lt;/p&gt;

&lt;p&gt;Good luck and have fun! 👋&lt;/p&gt;

</description>
      <category>testing</category>
      <category>javascript</category>
      <category>flow</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Build on Flow: JS Testing - 3. Execute Scripts and Send Transactions</title>
      <dc:creator>Max Daunarovich</dc:creator>
      <pubDate>Fri, 26 May 2023 06:21:32 +0000</pubDate>
      <link>https://dev.to/onflow/build-on-flow-js-testing-3-execute-scripts-and-send-transactions-5hac</link>
      <guid>https://dev.to/onflow/build-on-flow-js-testing-3-execute-scripts-and-send-transactions-5hac</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Now deploying contracts is all fun and games, but it becomes boring pretty fast, unless you can interact with them :)&lt;/p&gt;

&lt;p&gt;There are two ways how you can interact with contracts and accounts on Flow - you can &lt;code&gt;read&lt;/code&gt; data (via &lt;code&gt;scripts&lt;/code&gt;) and you can &lt;code&gt;write&lt;/code&gt; data (via transactions).&lt;/p&gt;

&lt;p&gt;The biggest difference is — you can't mutate the state of the chain when executing scripts. Even if you called the contract's method, which implementation modifies the state, it won't be preserved when a script returns.&lt;/p&gt;

&lt;p&gt;Let's start with non-intrusive interactions - scripts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Let's assume we are using the same setup from our last part, and we already have our &lt;code&gt;cadence&lt;/code&gt; folder. Later we will plant some scripts into &lt;code&gt;scripts&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;Create a new test suit file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @onflow/flow-js-testing make interaction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Calculator
&lt;/h2&gt;

&lt;p&gt;Since Cadence is able to do basic math operations, let's try to sum two numbers. Import &lt;code&gt;executeScript&lt;/code&gt; and add new test inside &lt;code&gt;describe&lt;/code&gt; block:&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;calculator&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executeScript&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
        pub fun main(a: Int, b: Int): Int{
          return a + b
        }
      `&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10&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="s2"&gt;32&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="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;42&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Notice that we are passing numbers as strings here and the final result returned from the script will also be a string. You can add necessary conversions at your leisure, but this is how network and libraries process numbers on Flow&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;executeScript&lt;/code&gt; will return you a tuple (an array with 2 values) &lt;code&gt;[result, error]&lt;/code&gt;, which you can&lt;br&gt;
use in your assertions.&lt;/p&gt;
&lt;h2&gt;
  
  
  Account Management
&lt;/h2&gt;

&lt;p&gt;The Framework provides you a clean and easy way to operate accounts - &lt;code&gt;getAccountAddress&lt;/code&gt; function.&lt;br&gt;
This function will return an address, which you can pass into any kind of interaction and framework will do the rest for you. For example, you can use it as a transaction signer or one of the&lt;br&gt;
arguments in a function:&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="nx"&gt;Alice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAccountAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&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;blockquote&gt;
&lt;p&gt;What is cool about this method is that this specific account is available anywhere inside your tests. So you can create a helper function, get Alice's account address one more time, and it will&lt;br&gt;
be resolved to exactly the same value! ✨&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Read Balance
&lt;/h2&gt;

&lt;p&gt;Calculator is fun and games, but let's do something more practical. For example, we can read the FLOW balance of any account. It is pretty easy if you know you way around Cadence:&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read balance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Alice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAccountAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&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;balance&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executeScript&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
        pub fun main(address: Address): UFix64 {
          let account = getAccount(address)
          return account.balance
        }
      `&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;Alice&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.00100000&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;All newly created accounts start with &lt;code&gt;0.001&lt;/code&gt; amount of Flow, so we can assert this value and use it as baseline for future computations&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Contract Access
&lt;/h2&gt;

&lt;p&gt;How about reading something from imported contract? Easy enough! Let's redeploy our &lt;code&gt;Message&lt;/code&gt; contract and try to read &lt;code&gt;message&lt;/code&gt; field from it:&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;shallResolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;deployContractByName&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Message&lt;/span&gt;&lt;span class="dl"&gt;"&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;message&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;contractValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executeScript&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
      import Message from 0x1

      pub fun main():String{
        return Message.message
      }
    `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;contractValue&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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;blockquote&gt;
&lt;p&gt;We can import contracts from any address - framework will resolve them and assign proper ones, before sending the script to the emulator.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Short Notation
&lt;/h2&gt;

&lt;p&gt;Let's shorten that script notation, by moving Cadence code into &lt;code&gt;read-message.cdc&lt;/code&gt; file and place it into &lt;code&gt;scripts&lt;/code&gt; folder. &lt;code&gt;executeScript&lt;/code&gt; have a shorthand notion, where the first argument is a name of the file containing the script.&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read message - short&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;shallResolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;deployContractByName&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Message&lt;/span&gt;&lt;span class="dl"&gt;"&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;message&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;contractValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executeScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read-message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;contractValue&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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;Arguments can be passed as second argument. Let's add &lt;code&gt;read-balance.cdc&lt;/code&gt; file with code from above and rewrite our balance reading script:&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;balance - short&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Alice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAccountAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&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;balance&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executeScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read-balance&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="nx"&gt;Alice&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.00100000&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Noice!&lt;/p&gt;

&lt;h2&gt;
  
  
  Cadence Ninja Mutants 🐢
&lt;/h2&gt;

&lt;p&gt;Let's bring some mutations to the mix! We will make two accounts, mint some tokens for one of them and transfer them to another account. This should be fun!&lt;/p&gt;

&lt;p&gt;In order to mint FLOW, we will utilize &lt;code&gt;mintFlow&lt;/code&gt; function, which expects the address and amount as arguments. Import &lt;code&gt;mintFlow&lt;/code&gt; and &lt;code&gt;sendTransaction&lt;/code&gt; at the top of the 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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FLOW transfer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Alice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAccountAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&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="nx"&gt;Bob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAccountAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bob&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;mintFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;42&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;aliceBalance&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executeScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read-balance&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="nx"&gt;Alice&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aliceBalance&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;42.00100000&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similar to how we've used &lt;code&gt;shallPass&lt;/code&gt; to deploy contract, we can utilize it, when sending transactions.&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FLOW transfer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Alice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAccountAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&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="nx"&gt;Bob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAccountAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bob&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;mintFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;42&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;aliceBalance&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executeScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read-balance&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="nx"&gt;Alice&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aliceBalance&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;42.00100000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;shallPass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;sendTransaction&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
        import FungibleToken from 0x1

        transaction(receiverAddress: Address, amount: UFix64){
          prepare(sender: AuthAccount){
            let receiver = getAccount(receiverAddress)

            // Withdraw necessary amount into separate vault
            let senderVault &amp;lt;- sender
                .borrow&amp;lt;&amp;amp;{FungibleToken.Provider}&amp;gt;(from: /storage/flowTokenVault)!
                .withdraw(amount: amount)

            // Send to receiver
            getAccount(receiverAddress)
                .getCapability(/public/flowTokenReceiver)!
                .borrow&amp;lt;&amp;amp;{FungibleToken.Receiver}&amp;gt;()!
                .deposit(from: &amp;lt;- senderVault)
          }
        }
      `&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;Bob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;signers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Alice&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="c1"&gt;// Let's read updated balances and compare to expected values&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;newAliceBalance&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executeScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read-balance&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="nx"&gt;Alice&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;bobBalance&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executeScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read-balance&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="nx"&gt;Bob&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newAliceBalance&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;41.00100000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bobBalance&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.00100000&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Send via Short Notation
&lt;/h2&gt;

&lt;p&gt;Similar to how we've done it with scripts, &lt;code&gt;sendTransaction&lt;/code&gt; function also supports short notation:&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="nf"&gt;sendTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// file name in "transactions folder"&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;signers&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// {optional) list of signers, even if that's single one&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// (optional) list of arguments&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's move all the Cadence code from example above into &lt;code&gt;send-flow.cdc&lt;/code&gt; file under &lt;code&gt;cadence/transactions&lt;/code&gt; folder and rewrite our test:&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FLOW transfer - short&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Alice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAccountAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice&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="nx"&gt;Bob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAccountAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bob&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;mintFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;42&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;aliceBalance&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executeScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read-balance&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="nx"&gt;Alice&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aliceBalance&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;42.00100000&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="nx"&gt;signers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Alice&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;recipient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Bob&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;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&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="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;shallPass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sendTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;send-flow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="c1"&gt;// Let's read updated balances and compare to expected values&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;newAliceBalance&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executeScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read-balance&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="nx"&gt;Alice&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;bobBalance&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executeScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read-balance&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="nx"&gt;Bob&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newAliceBalance&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;41.00100000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bobBalance&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.00100000&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Multisig" is supported out of the box, simply specify the expected number of signers in your transaction code and pass the corresponding number of addresses via &lt;code&gt;signers&lt;/code&gt; parameter 😉&lt;/p&gt;

&lt;p&gt;That's all, folks! &lt;a href="https://dev.to/maxstalker/build-on-flow-js-testing-4-storage-inspection-5e62"&gt;Next time&lt;/a&gt;, we will take a look at how we can inspect account storage and ensure resources were correctly minted or transferred. Until next time! 👋&lt;/p&gt;

</description>
      <category>testing</category>
      <category>javascript</category>
      <category>flow</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Build on Flow: JS Testing - 2. Setup Emulator and Deploy Contracts</title>
      <dc:creator>Max Daunarovich</dc:creator>
      <pubDate>Fri, 26 May 2023 06:21:08 +0000</pubDate>
      <link>https://dev.to/onflow/build-on-flow-js-testing-2-setup-emulator-and-deploy-contracts-38l6</link>
      <guid>https://dev.to/onflow/build-on-flow-js-testing-2-setup-emulator-and-deploy-contracts-38l6</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/onflow/build-on-flow-js-testing-1-introduction-2g16"&gt;Last Time&lt;/a&gt; we've covered how you can get started with testing in your project. That article covers use of &lt;code&gt;init&lt;/code&gt; and &lt;code&gt;make&lt;/code&gt; commands in JS Testing Framework and how to use them to scaffold your testing enviroment.&lt;/p&gt;

&lt;p&gt;We will assume you've gone through that process and have ready setup.&lt;/p&gt;

&lt;p&gt;This time we will cover how you can deploy your newly developed contract to emulator to be able to run scripts and transactions against it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;You will need to install Flow CLI in order to be able to spin up Flow Emulator. Follow &lt;a href="https://developers.flow.com/tools/flow-cli/install"&gt;instructions&lt;/a&gt; for your OS on Developer Portal.&lt;/p&gt;

&lt;p&gt;If you haven't prepared your environment - follow instructions from &lt;a href="https://dev.to/onflow/build-on-flow-js-testing-1-introduction-2g16"&gt;previous article&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Cadence Folder
&lt;/h2&gt;

&lt;p&gt;Most of the methods will allow you to use Cadence code straight from the &lt;code&gt;.cdc&lt;/code&gt; files. The only requirement is to use specific folder structure in designated folder.&lt;/p&gt;

&lt;p&gt;Let's create &lt;code&gt;cadence&lt;/code&gt; folder in the root of your project. Then create 3 new folders inside of it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;contracts&lt;/code&gt; - will hold all the contracts you would want to deploy&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;transactions&lt;/code&gt; - for any transactions code&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scripts&lt;/code&gt; - same for scripts&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Please note that folders should be called exactly in the same manner or they won't work. We have planned the task, which would allow you to use custom names, but it's not implemented yet&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In order for framework to know what location you want to use you will need to call &lt;code&gt;init&lt;/code&gt; method:&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="nx"&gt;path&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;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;emulator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;init&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;@onflow/flow-js-testing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;interactions - sendTransaction&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Instantiate emulator and path to Cadence files&lt;/span&gt;
  &lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;basePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../cadence&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;basePath&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;emulator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Stop emulator, so it could be restarted&lt;/span&gt;
  &lt;span class="nf"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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="nx"&gt;emulator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stop&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;h2&gt;
  
  
  Setup Emulator
&lt;/h2&gt;

&lt;p&gt;In order to test any network interactions, we need instance of emulator running. Frameworks handle the process with &lt;code&gt;emulator&lt;/code&gt; instance, which exposes two methods - &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;stop&lt;/code&gt;. Those will handle running &lt;code&gt;flow emulator&lt;/code&gt; process with necessary flags and extra steps after emulator will be stopped.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can reference code above to see how we use it in &lt;code&gt;beforeEach&lt;/code&gt;/&lt;code&gt;afterEach&lt;/code&gt; blocks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How to Deploy a contract?
&lt;/h2&gt;

&lt;p&gt;Framework have two handy functions, which will help you deploy contracts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;deployContract&lt;/code&gt; - allows you to pass contract code as a string (handy, when you are just playing around)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;deployContractByName&lt;/code&gt;- will allow you to deploy contract defined via file in your &lt;code&gt;cadence&lt;/code&gt; folder (which you pass, when calling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are quite similar in function, but &lt;code&gt;deployContractByName&lt;/code&gt; provides you an easy way of deploying contracts located in your &lt;code&gt;cadence/contracts&lt;/code&gt; folder. Let's create a file &lt;code&gt;HelloWorld.cdc&lt;/code&gt; inside ouf our &lt;code&gt;contracts&lt;/code&gt; folder and paste the following in:&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;contract&lt;/span&gt; &lt;span class="kt"&gt;HelloWorld&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;greetings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;

    &lt;span class="nf"&gt;init&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;greetings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello, from Cadence"&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;Our little contract only have single field, which we can read in the future. Let me show you how we can test it.&lt;/p&gt;

&lt;p&gt;Create new test suit with &lt;code&gt;make&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @onflow/flow-js-testing make first
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will run &lt;code&gt;make&lt;/code&gt; tool provided by testing framework and create a &lt;code&gt;first.js&lt;/code&gt; file, which will have a basic setup for you. Since deploying contract on Flow is just sending specifically designed transaction, we will use &lt;code&gt;shallPass&lt;/code&gt; method to ensure everything works:&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="nx"&gt;path&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;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;init&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;emulator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;shallPass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;deployContractByName&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;@onflow/flow-js-testing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Increase timeout if your tests failing due to timeout&lt;/span&gt;
&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deploy&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;basePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../cadence&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="nx"&gt;logging&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;basePath&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;emulator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;logging&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Stop emulator, so it could be restarted&lt;/span&gt;
  &lt;span class="nf"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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="nx"&gt;emulator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// We will put next block here&lt;/span&gt;
  &lt;span class="c1"&gt;// ========&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our first test will be super simple. We will wrap &lt;code&gt;deployContractByName&lt;/code&gt; with &lt;code&gt;shallPass&lt;/code&gt; and await the result of that computation:&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deploy Hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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;await&lt;/span&gt; &lt;span class="nf"&gt;shallPass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;deployContractByName&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well done! 👍 But scenarios like that is never the case. Contracts are usually much more complicated and accept multiple arguments to init it's field. Let's create another contract &lt;code&gt;Message.cdc&lt;/code&gt; in our &lt;code&gt;contracts&lt;/code&gt; folder and populate it with following Cadence code:&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;contract&lt;/span&gt; &lt;span class="kt"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;let&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="nf"&gt;init&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="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to pass arguments, when we deploy contract. We can do this by specifying &lt;code&gt;args&lt;/code&gt; field on the object we pass into &lt;code&gt;deployContractByName&lt;/code&gt;. It should be an array of values in the same order we defined them on &lt;code&gt;init&lt;/code&gt; method of our contract.&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deploy Message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cadence is great!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;shallPass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;deployContractByName&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Message&lt;/span&gt;&lt;span class="dl"&gt;"&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;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;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note that framework will handle all the type conversions for you! 😎&lt;/p&gt;

&lt;p&gt;You can try to add another argument to ensure that test will fail, ensuring you are doing&lt;br&gt;
everything correctly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another function we have at our disposal is &lt;code&gt;deployContract&lt;/code&gt;. It has pretty much the same API, except it expects &lt;code&gt;code&lt;/code&gt; value for your Cadence instead of a file name. Let's make a simple test to&lt;br&gt;
illustrate how you can use it.&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deploy Custom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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;await&lt;/span&gt; &lt;span class="nf"&gt;shallPass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;deployContract&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
          pub contract Custom{
            pub let message: String

            init(){
              self.message = "This is custom contract! Neat, ha? :)"
            }
          }
        `&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;You can pass arguments in the same fashion we did above for &lt;code&gt;deployContractByName&lt;/code&gt; by specifying &lt;code&gt;args&lt;/code&gt; field.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Originally the purpose of this function was to process and consume arguments from&lt;br&gt;
&lt;code&gt;deployContractByName&lt;/code&gt; and wasn't exported. After some consideration we've exported it to enable&lt;br&gt;
people who just learning Cadence to experiment quikly&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can find detailed explanation of both functions on [Flow Developer Portal - Contract Management (&lt;a href="https://developers.flow.com/tooling/flow-js-testing/contracts"&gt;https://developers.flow.com/tooling/flow-js-testing/contracts&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Too slow!
&lt;/h2&gt;

&lt;p&gt;Sometimes scenario that you are trying to test takes more time than default Jest timeout - 5 seconds. You can control this by increasing the timeout to next reasonable value:&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="c1"&gt;// Place this after import lines&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;path&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;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;deployContractByName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;emulator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;executeScript&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;init&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;@onflow/flow-js-testing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// the rest of the test setup below 👇&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Some CI environments might be slower than you local machine, so if you see randomly failing tests - try to increase this value.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's all, folks! &lt;a href="https://dev.to/maxstalker/build-on-flow-js-testing-3-execute-scripts-and-send-transactions-5hac"&gt;Next time&lt;/a&gt; we will take a look how we can execute scripts, sign and send&lt;br&gt;
transactions.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>testing</category>
      <category>flow</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Build on Flow: JS Testing - 1. Introduction</title>
      <dc:creator>Max Daunarovich</dc:creator>
      <pubDate>Wed, 08 Mar 2023 19:12:16 +0000</pubDate>
      <link>https://dev.to/onflow/build-on-flow-js-testing-1-introduction-2g16</link>
      <guid>https://dev.to/onflow/build-on-flow-js-testing-1-introduction-2g16</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;One of the most important parts of software development is Testing. It helps ensure that the product meets the requirements and is fit for the purpose. Testing allows to detect bugs and errors in the software, which in turn makes it more reliable and efficient.&lt;/p&gt;

&lt;p&gt;It's especially important for any blockchain project, considering the immutable nature of blockchains. Errors that could easily be fixed in Web2 application usually are irreversable, when changes are introducted to the ledger.&lt;/p&gt;

&lt;p&gt;Flow Network is using &lt;a href="https://developers.flow.com/cadence/language"&gt;&lt;strong&gt;Cadence&lt;/strong&gt;&lt;/a&gt; - a new Domain Specific Language designed to make writing smart contracts easier and more accessible. Cadence is a statically typed, high-level smart contract language that simplifies development by allowing developers to write complex logic that can be deployed and executed on the the Flow Network.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Options
&lt;/h2&gt;

&lt;p&gt;There are several paths you can go to test your Cadence code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create testbed based on &lt;a href="https://github.com/onflow/flow-go-sdk"&gt;Flow Go SDK&lt;/a&gt; and inspired by &lt;a href="https://github.com/dapperlabs/nba-smart-contracts/tree/master/lib/go/test"&gt;TopShot&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Use amazing &lt;a href="https://github.com/bjartek/overflow"&gt;Overflow&lt;/a&gt; by one of the most prolific community members &lt;a href="https://github.com/bjartek"&gt;Bjarte S. Karlsen&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;a href="https://developers.flow.com/cadence/testing-framework"&gt;Cadence Testing Framework&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;a href="https://github.com/onflow/flow-js-testing"&gt;Flow JS Testing Framework&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this series we will explore the last option.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Flow JS Testing?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/onflow/flow-js-testing"&gt;Flow JS Testing&lt;/a&gt; is a library of utility methods, which in conjuction with &lt;a href="https://developers.flow.com/tools/flow-cli"&gt;Flow CLI&lt;/a&gt; provides developers the ability to write tests for Cadence using Javascript and testing solutions like &lt;a href="https://jestjs.io"&gt;Jest&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It have all the necessary capabilities to get blockchain interaction out of the way and allow you to focus on writing "human-readable" tests. Here are some of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;start/stop Flow Blockchain emulator&lt;/li&gt;
&lt;li&gt;create and manage accounts&lt;/li&gt;
&lt;li&gt;deploy contracts&lt;/li&gt;
&lt;li&gt;execute scripts and send transactions signed by one or multiple parties&lt;/li&gt;
&lt;li&gt;helpful Jest assertions for passing/failing interactions&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;🖐 Please note, framework is not restricting you to only use Jest, even though all examples and tutorials utilizing it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's give it a try and create a simple test, which will execute the script on Emulator and return a value, which we can then compare to expected result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;You will need to install Flow CLI in order to be able to spin up Flow Emulator. Follow &lt;a href="https://developers.flow.com/tools/flow-cli/install"&gt;instructions&lt;/a&gt; for your OS on Developer Portal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Setting up all the necessary configs and environment is quite taxating 😩. That is exactly the reason, why we made handy &lt;code&gt;init&lt;/code&gt; function for you! Open the terminal in the root of your project, copy/paste following block and press Enter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir test&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="nb"&gt;cd test&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
npx @onflow/flow-js-testing init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will run all the necessary steps, create babel and jest configration as well as install dependecies neededd to run the tests.&lt;/p&gt;

&lt;p&gt;Now let's create our first test file! You can copy/paste on of the examples from links we've provided below or simply run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @onflow/flow-js-testing make simple
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;simple&lt;/code&gt; is the name of the file and test suite - series of tests enclosed in &lt;code&gt;describe&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;Open the file in your prefered editor.&lt;br&gt;
Import &lt;code&gt;executeScript&lt;/code&gt; from &lt;code&gt;@onflow/flow-js-testing&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;emulator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;init&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;@onflow/flow-js-testing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;executeScript&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;@onflow/flow-js-testing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the only &lt;code&gt;test&lt;/code&gt; block defined there:&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="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;basic assertion&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executeScript&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
      pub fun main():Int{
        return 42
      }
    `&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;42&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;executeScript&lt;/code&gt; method will return a tupple &lt;code&gt;[result, error, logs]&lt;/code&gt;. This time we only care about result value so we can drop &lt;code&gt;error&lt;/code&gt; and &lt;code&gt;logs&lt;/code&gt; values - one of the following articles will cover those in details.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;☝ Even though we are returning &lt;code&gt;Int&lt;/code&gt; value it is still a string! You will need to handle conversions yourself. At least for now 😅&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now run your test with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations! You succesfully tested and confirmed your setup is working properly 🎉&lt;/p&gt;

&lt;p&gt;Next time we will create basic smart-contract and interact with it. Stay tuned! 👋&lt;/p&gt;

&lt;h2&gt;
  
  
  Link and Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developers.flow.com/"&gt;&lt;strong&gt;Flow Developer Portal&lt;/strong&gt;&lt;/a&gt; - Detailed information about Flow blockchain, tutorials, tools and everything you need&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developers.flow.com/tools/flow-js-testing/api"&gt;&lt;strong&gt;Flow JS Testing - API Reference&lt;/strong&gt;&lt;/a&gt; - JS Testing API Reference&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/onflow/flow-js-testing/tree/master/examples"&gt;&lt;strong&gt;Flow JS Testing - Examples&lt;/strong&gt;&lt;/a&gt; - Multiple examples for common patterns and interactions&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/onflow/kitty-items/tree/master/cadence/tests"&gt;&lt;strong&gt;KittyItems Example&lt;/strong&gt;&lt;/a&gt; - Real-life example of JS Testing Framework application for Cadence testing&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>testing</category>
      <category>javascript</category>
      <category>flow</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Build on Flow | Learn FCL - 16. How to Send FLOW Tokens to Another Account</title>
      <dc:creator>Max Daunarovich</dc:creator>
      <pubDate>Mon, 29 Aug 2022 09:20:00 +0000</pubDate>
      <link>https://dev.to/onflow/build-on-flow-learn-fcl-16-how-to-send-flow-tokens-to-another-account-3lph</link>
      <guid>https://dev.to/onflow/build-on-flow-learn-fcl-16-how-to-send-flow-tokens-to-another-account-3lph</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Fungible tokens are often used as a means of payment - for products or services. In this article we will guide you how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;get current balance of FLOW on a specific account&lt;/li&gt;
&lt;li&gt;compose FLOW transfer transaction&lt;/li&gt;
&lt;li&gt;sign and send it using Blocto or Lilico wallet&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Theory
&lt;/h3&gt;

&lt;p&gt;FLOW token is a contract, which implements &lt;a href="https://github.com/onflow/flow-ft"&gt;Fungible Token Standard&lt;/a&gt; interface. If you take a look in the code, you will see that on the higher level totalSupply is defined on implementing contract, but it doesn’t know how much tokens holds each individual account. Each account that would want to own tokens would need to have an instance of the &lt;a href="https://github.com/onflow/flow-ft/blob/master/contracts/FungibleToken.cdc#L149"&gt;Vault&lt;/a&gt; resource stored in their account storage. The &lt;code&gt;Vault&lt;/code&gt; resource has methods that the owner and other users can call. Those methods are limited by&lt;code&gt;Provider&lt;/code&gt;, &lt;code&gt;Receiver&lt;/code&gt;, and &lt;code&gt;Balance&lt;/code&gt; resource interfaces. These interfaces declare pre-conditions and post-conditions that restrict the execution of the functions in the Vault. &lt;/p&gt;

&lt;p&gt;They are separate because it gives the user the ability to share a reference to their Vault that only exposes the fields functions in one or more of the interfaces.&lt;/p&gt;

&lt;p&gt;It also gives users the ability to make custom resources that implement these interfaces to do various things with the tokens. For example, a faucet can be implemented by conforming&lt;br&gt;
to the Provider interface.&lt;/p&gt;

&lt;p&gt;By using resources and interfaces, users of Fungible Token contracts can send and receive tokens peer-to-peer, without having to interact with a central ledger smart contract. To send tokens to another user, a user would simply withdraw the tokens from their Vault, then call the deposit function on another user's Vault to complete the transfer.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1 - Installation
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;"@onflow/fcl": "1.0.0"&lt;/code&gt; as your dependency&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2 - FCL Config
&lt;/h3&gt;

&lt;p&gt;Let’s create &lt;code&gt;testnet-config.js&lt;/code&gt; file, so we can reuse it in later projects. It will also make our &lt;code&gt;index.js&lt;/code&gt; file cleaner and allow for an easy swap to mainnet version. The content of the file will be pretty much the same as we covered in previous article:&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="c1"&gt;// Configure FCL&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;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="s2"&gt;@onflow/fcl&lt;/span&gt;&lt;span class="dl"&gt;"&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="c1"&gt;// Use Testnet Access Node&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="c1"&gt;// We will also specify the network as some of the FCL parts need it to properly do it's work&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;testnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// This will be the title of our DApp&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="s2"&gt;Meow DApp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// This is just a kitten photo, we will use for the icon&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="s2"&gt;https://placekitten.com/g/200/200&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// Next two will define where Wallet Discovery is located&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://fcl-discovery.onflow.org/testnet/authn&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="s2"&gt;discovery.authn.endpoint&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="s2"&gt;https://fcl-discovery.onflow.org/api/testnet/authn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="c1"&gt;// We will also set aliases for the contracts we will use in this example&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0xFLOW&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="s2"&gt;0x7e60df042a9c0868&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="s2"&gt;0xFT&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="s2"&gt;0x9a0766d93b6608b7&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;p&gt;If you take a look at the end of the config you can see that we’ve defined two aliases for the contracts we will import in our Cadence code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;0xFLOW&lt;/code&gt; for &lt;code&gt;FlowToken&lt;/code&gt; contract&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0xFT&lt;/code&gt; for &lt;code&gt;FungibleToken&lt;/code&gt; contract&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4 - Imports
&lt;/h3&gt;

&lt;p&gt;Back to our &lt;code&gt;index.js&lt;/code&gt; file, where we will add all the necessary imports:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reauthenticate&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;@onflow/fcl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./testnet-config&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;h3&gt;
  
  
  Step 3 - Implement &lt;code&gt;getFlowBalance&lt;/code&gt; function
&lt;/h3&gt;

&lt;p&gt;Next, let’s create a function, which will check current balance of the account, defined by it’s address.&lt;/p&gt;

&lt;p&gt;It will accept single argument &lt;code&gt;address&lt;/code&gt;, which will be passed to Cadence script and return &lt;code&gt;UFix64&lt;/code&gt; value, represented as string.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡If you just arrived here and don’t quite know what is happening - don’t be afraid! We’ve got you covered! You can check earlier articles in this series:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to Execute Scripts&lt;/li&gt;
&lt;li&gt;How to Send Transactions&lt;/li&gt;
&lt;/ul&gt;


&lt;/blockquote&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;getFlowBalance&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;address&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cadence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    import FlowToken from 0xFLOW
    import FungibleToken from 0xFT

    pub fun main(address: Address): UFix64 {
      let account = getAccount(address)

      let vaultRef = account.getCapability(/public/flowTokenBalance)
        .borrow&amp;lt;&amp;amp;FlowToken.Vault{FungibleToken.Balance}&amp;gt;()
        ?? panic("Could not borrow Balance reference to the Vault")

      return vaultRef.balance
    }
  `&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;args&lt;/span&gt; &lt;span class="o"&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;address&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;cadence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&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;balance&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;blockquote&gt;
&lt;p&gt;🧑‍🏫 If you are wondering where we’ve got the code for this transaction - you can check &lt;a href="https://github.com/onflow/flow-ft"&gt;Fungible Token Standart&lt;/a&gt; repository on Github:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/onflow/flow-ft/blob/master/transactions/scripts/get_balance.cdc"&gt;Get Balance Cadence script&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/onflow/flow-ft/blob/master/transactions/transfer_tokens.cdc"&gt;Transfer Tokens Cadence Transaction&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;The “problem” is - you won’t be able to find &lt;code&gt;BalancePublicPath&lt;/code&gt; field set on &lt;code&gt;FlowToken&lt;/code&gt;contract deployed to &lt;a href="https://flow-view-source.com/testnet/account/0x7e60df042a9c0868/contract/FlowToken"&gt;0x9a0766d93b6608b7&lt;/a&gt;. The contract was deployed before this useful partern of storing common path became widely used. That’s why we are hard-coding &lt;code&gt;/public/flowTokenBalance&lt;/code&gt; value which we sourecd from &lt;code&gt;init&lt;/code&gt; method of the contract. We will also use &lt;code&gt;/public/flowTokenReceiver&lt;/code&gt; defined there to get capability of the Recepient’s Vault.&lt;/p&gt;

&lt;blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;While Javacript code is self-explanatory, let’s cover whats is happening in Cadence script. It accepts single argument &lt;code&gt;address&lt;/code&gt; of type &lt;code&gt;Address&lt;/code&gt; and returns &lt;code&gt;UFix64&lt;/code&gt; value:&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="nx"&gt;pub&lt;/span&gt; &lt;span class="nx"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;main&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="nx"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;UFix64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First we take account, we are trying to “investigate” by calling &lt;code&gt;getAccount&lt;/code&gt; function, which will return us &lt;a href="https://docs.onflow.org/cadence/language/accounts/#publicaccount"&gt;PublicAccount struct&lt;/a&gt;.&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;let&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getAccount&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This struct gives us the ability to call &lt;code&gt;getCapability&lt;/code&gt; method to retrieve necessary capability to FLOW Vault. We know that capability should be exposes on &lt;code&gt;/public/flowTokenBalance&lt;/code&gt; public path. And we also know that it’s a limited capability &lt;code&gt;FungibleToken.Balance&lt;/code&gt;, which will only alow us to read the balance of the Vault.&lt;/p&gt;

&lt;p&gt;We can check &lt;code&gt;init&lt;/code&gt; method of &lt;a href="https://flow-view-source.com/testnet/account/0x7e60df042a9c0868/contract/FlowToken"&gt;FlowToken contract&lt;/a&gt; (line #187) to get the correct type we need to borrow:&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;&amp;amp;&lt;/span&gt;&lt;span class="na"&gt;FlowToken&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Vault&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;FungibleToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Balance&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to operate said capability, we need to get a reference to it with &lt;code&gt;.borrow&lt;/code&gt; method. We can set the type are are expecting to borrow using angular brackets - and paste the same type as it was defined in &lt;code&gt;init&lt;/code&gt; method.&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;let&lt;/span&gt; &lt;span class="nx"&gt;vaultRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCapability&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/public/&lt;/span&gt;&lt;span class="nx"&gt;flowTokenBalance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;borrow&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;FlowToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Vault&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;FungibleToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Balance&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="o"&gt;??&lt;/span&gt; &lt;span class="nf"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Could not borrow Balance reference to the Vault&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;p&gt;If the reference can’t be created (for example stored Capability have different type or can’t be casted to this specific type) - transaction will stop the execution with &lt;code&gt;panic&lt;/code&gt; message.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4 - Implement &lt;code&gt;sendFlow&lt;/code&gt; function
&lt;/h3&gt;

&lt;p&gt;Next on the list is a function, which will accept Recepient’s address and amount of FLOW tokens we want to transfer.&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;sendFlow&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;recepient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;amount&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cadence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    import FungibleToken from 0xFT
    import FlowToken from 0xFLOW

    transaction(recepient: Address, amount: UFix64){
      prepare(signer: AuthAccount){
        let sender = signer.borrow&amp;lt;&amp;amp;FlowToken.Vault&amp;gt;(from: /storage/flowTokenVault)
          ?? panic("Could not borrow Provider reference to the Vault")

        let receiverAccount = getAccount(recepient)

        let receiver = receiverAccount.getCapability(/public/flowTokenReceiver)
          .borrow&amp;lt;&amp;amp;FlowToken.Vault{FungibleToken.Receiver}&amp;gt;()
          ?? panic("Could not borrow Receiver reference to the Vault")

                let tempVault &amp;lt;- sender.withdraw(amount: amount)
        receiver.deposit(from: &amp;lt;- tempVault)
      }
    }
  `&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;args&lt;/span&gt; &lt;span class="o"&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;recepient&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="nf"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&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;UFix64&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;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&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;txId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;cadence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;limit&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="s2"&gt;Waiting for transaction to be sealed...&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="nx"&gt;txDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&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;txId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;onceSealed&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;txDetails&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;Cadence code is pretty similar to one we’ve used above to query FLOW balance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we are getting full reference to a Sender’s Vault&lt;/li&gt;
&lt;li&gt;we are geting limited &lt;code&gt;Receiver&lt;/code&gt; reference to Recepient’s Vault&lt;/li&gt;
&lt;li&gt;we are creating temporary Vault via &lt;code&gt;withdraw&lt;/code&gt; method and passing &lt;code&gt;amount&lt;/code&gt; as argument&lt;/li&gt;
&lt;li&gt;we are depositing into Recepient’s Vault via &lt;code&gt;deposit&lt;/code&gt; method and &lt;code&gt;tempVault&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice the syntax of full reference - we don’t specify limiting interface in curly braces and we also specify storage path &lt;code&gt;/storage/flowTokenVault&lt;/code&gt; . Every account is initialized with FLOW Vault on that path, so it’s safe to assume it’s there for every signer:&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;let&lt;/span&gt; &lt;span class="nx"&gt;sender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;borrow&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;FlowToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Vault&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;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;flowTokenVault&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Finally
&lt;/h3&gt;

&lt;p&gt;Let's add an IIFE at the end of the file and populate it with methods we have just defined:&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="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// "reauthenticate" will ensure your session works properly&lt;/span&gt;
  &lt;span class="c1"&gt;// and present you a popup to sign in&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;reauthenticate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// This is an example account we've created to this exibition&lt;/span&gt;
  &lt;span class="c1"&gt;// You can replace it with one of your addresses&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;recepient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x3e68d80ca405bbac&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Check "initial" balance first&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getFlowBalance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recepient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Send some FLOW tokens to Recepient&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recepient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.337&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Ensure that Recepient's balance has been changed&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getFlowBalance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;recepient&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;After a series of popups and confirmation your console should have the proof that balance of Recepient’s Vault have been changed:&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="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1002.67500000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Waiting&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;sealed&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt; 

&lt;span class="nx"&gt;txDetails&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;blockId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;b555b7ca17fac5ad170e3bfc4a85afd3325eb5d4fb56e4be49550dce9413ffad&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
    &lt;span class="nx"&gt;statusString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SEALED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;
    &lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&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="na"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1004.01200000&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;p&gt;&lt;a href="https://i.giphy.com/media/1BPvv1QvbKV156jyul/giphy-downsized-large.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/1BPvv1QvbKV156jyul/giphy-downsized-large.gif" alt="https://media.giphy.com/media/1BPvv1QvbKV156jyul/giphy-downsized-large.gif" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You know what to do next 😉&lt;/p&gt;

&lt;p&gt;Until next time! 👋 &lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full Source Code&lt;/strong&gt; - &lt;a href="https://codesandbox.io/s/dev-to-16-transfer-flow-tokens-pjq98u?file=/src/testnet-config.js:776-794"&gt;https://codesandbox.io/s/dev-to-16-transfer-flow-tokens-pjq98u&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fungible Token Standard&lt;/strong&gt; - &lt;a href="https://github.com/onflow/flow-ft/blob/master/contracts/FungibleToken.cdc#L53"&gt;https://github.com/onflow/flow-ft&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FCL - &lt;code&gt;mutate&lt;/code&gt;&lt;/strong&gt; - &lt;a href="https://docs.onflow.org/fcl/reference/api/#mutate"&gt;https://docs.onflow.org/fcl/reference/api/#mutate&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FCL - &lt;code&gt;query&lt;/code&gt;&lt;/strong&gt; - &lt;a href="https://docs.onflow.org/fcl/reference/api/#query"&gt;https://docs.onflow.org/fcl/reference/api/#query&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cadence - Capabilities&lt;/strong&gt; - &lt;a href="https://docs.onflow.org/cadence/language/capability-based-access-control/#gatsby-focus-wrapper"&gt;https://docs.onflow.org/cadence/language/capability-based-access-control&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cadence - References&lt;/strong&gt; - &lt;a href="https://docs.onflow.org/cadence/language/references/#gatsby-focus-wrapper"&gt;https://docs.onflow.org/cadence/language/references&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other resources you might find useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flow Docs Site&lt;/strong&gt; - &lt;a href="https://docs.onflow.org/"&gt;https://docs.onflow.org/&lt;/a&gt; - More detailed information about Flow blockchain and how to interact with it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flow Portal&lt;/strong&gt; - &lt;a href="https://flow.com/"&gt;https://flow.com/&lt;/a&gt; - your entry point to Flow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FCL JS&lt;/strong&gt; - &lt;a href="https://github.com/onflow/fcl-js"&gt;https://github.com/onflow/fcl-js&lt;/a&gt; - Source code and ability to contribute to the FCL JS library&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cadence&lt;/strong&gt; - &lt;a href="https://docs.onflow.org/cadence/"&gt;https://docs.onflow.org/cadence/&lt;/a&gt; - Introduction to Cadence&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codesandbox&lt;/strong&gt; - &lt;a href="https://codesandbox.io/"&gt;https://codesandbox.io&lt;/a&gt; - An amazing in-browser IDE enabling quick prototyping&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>fcl</category>
      <category>onflow</category>
    </item>
    <item>
      <title>Build on Flow | Learn FCL - 15. How to Add and Revoke Public Keys</title>
      <dc:creator>Max Daunarovich</dc:creator>
      <pubDate>Mon, 22 Aug 2022 18:40:00 +0000</pubDate>
      <link>https://dev.to/onflow/build-on-flow-learn-fcl-15-how-to-add-and-revoke-public-keys-4k8c</link>
      <guid>https://dev.to/onflow/build-on-flow-learn-fcl-15-how-to-add-and-revoke-public-keys-4k8c</guid>
      <description>&lt;h2&gt;
  
  
  Preface
&lt;/h2&gt;

&lt;p&gt;One of the problems you might encounter, when you need to sign with a lot of transactions is inability to sign more than single transaction by account in single block. This happens because &lt;code&gt;Proposer&lt;/code&gt; role is used to provide a &lt;code&gt;nounce&lt;/code&gt;, which will be updated on account key only after transaction is sealed.&lt;/p&gt;

&lt;p&gt;The solution - we need to add more keys 🔑✨!&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;After you go through the code in this article you will know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how to discover public keys on account using Flow View Source&lt;/li&gt;
&lt;li&gt;how to add new &lt;code&gt;PublicKey&lt;/code&gt; with set weight&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wallet Limitations
&lt;/h3&gt;

&lt;p&gt;While &lt;code&gt;Blocto&lt;/code&gt; or &lt;code&gt;Lilico&lt;/code&gt; will not allow you to use key with different index - other than 0 - in some cases it’s still valuable to add public key you can use programmatically to automate some tasks. The key with full weight will give you access to the account storage and ability to manipulate it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Investigation
&lt;/h3&gt;

&lt;p&gt;Before we continue, let’s check our current account on Flow View Source - &lt;a href="https://flow-view-source.com/testnet/account/0x5593df7d286bcdb8/keys"&gt;0x5593df7d286bcdb8&lt;/a&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;😅 Considering how many times Codesandbox has been run, you probably will see multiple keys here, when you read it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffnqql61mgfotjh4nwlsd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffnqql61mgfotjh4nwlsd.png" alt="Image description" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should see at least a single key with &lt;code&gt;weight&lt;/code&gt; equal to 1000 (full weight).&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 - Installation
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;💡You can go and fork your work from previous article as it will be mostly the same :)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Add &lt;code&gt;"@onflow/fcl"&lt;/code&gt;, &lt;code&gt;elliptic&lt;/code&gt; and &lt;code&gt;sha3&lt;/code&gt; packages as your dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 - Create a signer
&lt;/h3&gt;

&lt;p&gt;You can copy/paste the content of &lt;code&gt;signer.js&lt;/code&gt; file from previous article or follow the &lt;a href="https://www.notion.so/Build-on-Flow-Learn-FCL-14-How-to-Mutate-Chain-State-by-Signing-Transactions-with-a-Private-Key-d3129deb4f924007bf6411de0011424b"&gt;instructions&lt;/a&gt; and make a new one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 - Configure FCL
&lt;/h3&gt;

&lt;p&gt;We are not gonna use wallets in this example - consider this as homework assignment 😉 - so our config only needs access node url:&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="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="s2"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4 - Implement &lt;code&gt;addPublicKey&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Let’s make a new function called &lt;code&gt;addPublicKey&lt;/code&gt;, which will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;accept &lt;code&gt;PublicKey&lt;/code&gt; as a string,&lt;/li&gt;
&lt;li&gt;prepare transaction to pass public key and &lt;code&gt;weight&lt;/code&gt; as arguments&lt;/li&gt;
&lt;li&gt;sign and send aforementioned transaction to network&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The process is similar to how we were cooking transactions in previous article:&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;addPublicKey&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;publicKey&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cadence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
  transaction(publicKey: String, weight: UFix64) {
    prepare(signer: AuthAccount) {
      let bytes = publicKey.decodeHex()

      let key = PublicKey(
        publicKey: bytes,
        signatureAlgorithm: SignatureAlgorithm.ECDSA_P256
      )

      var clampledWeight = weight
      // weight should be in range 0 to 1000
      if(clampledWeight &amp;gt; 1000.0){
        clampledWeight = 1000.0
      }

      signer.keys.add(
        publicKey: key,
        hashAlgorithm: HashAlgorithm.SHA3_256,
        weight: clampledWeight
      )
    }
  }
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// List of arguments&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;weight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// zero weight keys are perfectly fine for Proposer role&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&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;publicKey&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="nf"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weight&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;UFix64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// Roles&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;proposer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signer&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;payer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signer&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;authorizations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;signer&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// Execution limit&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;

  &lt;span class="c1"&gt;// "mutate" method will return us transaction id&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;proposer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authorizations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;cadence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Then we subscribe to status updates and return, when it's sealed&lt;/span&gt;
  &lt;span class="k"&gt;return&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;txId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;onceSealed&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;h3&gt;
  
  
  Step 5 - Implement &lt;code&gt;revokePublicKey&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Another function we would like to prepare is &lt;code&gt;revokePublicKey&lt;/code&gt;. It will prepare and submit transaction, which will revoke the key on account:&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;revokePublicKey&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;keyIndex&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cadence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    transaction(keyIndex: Int){
      prepare(signer: AuthAccount){
        signer.keys.revoke(keyIndex:keyIndex)
      }
    }
  `&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;args&lt;/span&gt; &lt;span class="o"&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;keyIndex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&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;Int&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;proposer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signer&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;payer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signer&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;authorizations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;signer&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;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// "mutate" method will return us transaction id&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;cadence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;proposer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authorizations&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Then we subscribe to status updates and return, when it's sealed&lt;/span&gt;
  &lt;span class="k"&gt;return&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;txId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;onceSealed&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;h3&gt;
  
  
  Finally -
&lt;/h3&gt;

&lt;p&gt;Let's add an IIFE at the end of the file and populate it with methods we have just defined:&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="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// PublicKey doesn't need to be unique, so we are gonna use exactly the same one&lt;/span&gt;
  &lt;span class="c1"&gt;// that already exist on account. This way we can control it with the same private key.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;790a6849decbc179e9904f7f601fbd629f1687f371484998ceb8c587303e05ae4f859c7aa91f8493642de1039039d2da9650b4b7d9d44d2486e7a2adabf602bc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Uncomment this block to add public key&lt;/span&gt;
  &lt;span class="cm"&gt;/*
  const txDetails = await addPublicKey(key);
  console.log({ txDetails });
  */&lt;/span&gt;

  &lt;span class="c1"&gt;// Uncomment this block to revoke key&lt;/span&gt;
  &lt;span class="cm"&gt;/*
  const txDetails = await revokePublicKey(2);
  console.log({ txDetails });
  */&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the dust settles, your console should have the output, showcasing that transaction succesfully updated your account:&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="nx"&gt;txDetails&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;blockId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;b9ddfac94c968864ca369ec890e8025c0144375f334bd0e2ddea1965b175fc82&lt;/span&gt;&lt;span class="dl"&gt;"&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="mi"&gt;4&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SEALED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&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;errorMessage&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="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flow.AccountKeyAdded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;transactionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fa2640f428a3317b656196ef7f069a744b2455569e492f8112d37abca31e273d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;transactionIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="nx"&gt;eventIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&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;Checking Flow View Source will show there are now multiple keys that can be used:&lt;/p&gt;

&lt;p&gt;If you uncomment the &lt;code&gt;revokePublicKey&lt;/code&gt; usage block and wait for execution, you will be able to see that key is marked as revoked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xb5ymv5k80l5a1q6l1z.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xb5ymv5k80l5a1q6l1z.jpg" alt="Image description" width="584" height="184"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Please note, that keys are not &lt;code&gt;removed&lt;/code&gt;, but &lt;code&gt;revoked&lt;/code&gt; - you won’t be able to use this key index on this account anymore 🤷‍♂️&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hope you’ve found this article useful. And if you have gone through it with us - you’ve grown stronger! 💪&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AEo7lmLu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://c.tenor.com/TgDOSZ0PpNsAAAAd/zoolander-boss.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AEo7lmLu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://c.tenor.com/TgDOSZ0PpNsAAAAd/zoolander-boss.gif" alt="https://c.tenor.com/TgDOSZ0PpNsAAAAd/zoolander-boss.gif" width="640" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Until next time 👋&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full Source Code -&lt;/strong&gt; &lt;a href="https://codesandbox.io/s/dev-to-15-add-public-key-cvfho2?file=/src/index.js"&gt;https://codesandbox.io/s/dev-to-15-add-public-key-cvfho2&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cadence Docs - Add Key -&lt;/strong&gt; &lt;a href="https://docs.onflow.org/cadence/language/accounts/#add-account-keys"&gt;https://docs.onflow.org/cadence/language/accounts/#add-account-keys&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cadence Docs - Revoke Key -&lt;/strong&gt; &lt;a href="https://docs.onflow.org/cadence/language/accounts/#revoke-account-keys"&gt;https://docs.onflow.org/cadence/language/accounts/#revoke-account-keys&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other resources you might find useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flow Docs Site&lt;/strong&gt; - &lt;a href="https://docs.onflow.org/"&gt;https://docs.onflow.org/&lt;/a&gt; - More detailed information about Flow blockchain and how to interact with it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flow Portal&lt;/strong&gt; - &lt;a href="https://flow.com/"&gt;https://flow.com/&lt;/a&gt; - your entry point to Flow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FCL JS&lt;/strong&gt; - &lt;a href="https://github.com/onflow/fcl-js"&gt;https://github.com/onflow/fcl-js&lt;/a&gt; - Source code and ability to contribute to the FCL JS library&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cadence&lt;/strong&gt; - &lt;a href="https://docs.onflow.org/cadence/"&gt;https://docs.onflow.org/cadence/&lt;/a&gt; - Introduction to Cadence&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codesandbox&lt;/strong&gt; - &lt;a href="https://codesandbox.io/"&gt;https://codesandbox.io&lt;/a&gt; - An amazing in-browser IDE enabling quick prototyping&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>onflow</category>
      <category>fcl</category>
      <category>buildonflow</category>
    </item>
    <item>
      <title>Build on Flow | Learn FCL - 14. How to Mutate Chain State by Signing Transactions with a Private Key</title>
      <dc:creator>Max Daunarovich</dc:creator>
      <pubDate>Mon, 01 Aug 2022 13:21:35 +0000</pubDate>
      <link>https://dev.to/onflow/build-on-flow-learn-fcl-14-how-to-mutate-chain-state-by-signing-transactions-with-a-private-key-5c4p</link>
      <guid>https://dev.to/onflow/build-on-flow-learn-fcl-14-how-to-mutate-chain-state-by-signing-transactions-with-a-private-key-5c4p</guid>
      <description>&lt;h2&gt;
  
  
  Preface
&lt;/h2&gt;

&lt;p&gt;Last time we covered how you can sign transactions with Lilico and Blocto wallets from the comfort of your browser. But it’s quite common that you might need to do the same task on a backend (i.e. server-side), where the browser is not available.&lt;/p&gt;

&lt;p&gt;Fear not, my friend as this is exactly what we will teach you. After working through materials of this article you will know how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fill different roles for your transaction&lt;/li&gt;
&lt;li&gt;get a basic understanding of the &lt;code&gt;multisig&lt;/code&gt; process&lt;/li&gt;
&lt;li&gt;sign a transaction with your private key&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1 - Installation
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;"@onflow/fcl"&lt;/code&gt;, &lt;code&gt;elliptic&lt;/code&gt; and &lt;code&gt;sha3&lt;/code&gt; packages as project dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 - Create a Signer
&lt;/h3&gt;

&lt;p&gt;Let’s create a new file and call it &lt;code&gt;signer.js&lt;/code&gt;. The file can have any name, we are just picking something with a semantic meaning here. Our signer will need to have 3 functions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First one will be called &lt;code&gt;hashMessageHex&lt;/code&gt;- it will be used to hash the transaction message using a &lt;a href="https://en.wikipedia.org/wiki/SHA-3"&gt;SHA3 algorithm&lt;/a&gt;. The reason we are using SHA3 is because we’ve picked it as the &lt;code&gt;Hash Algorithm&lt;/code&gt; during account creation on the &lt;a href="https://testnet-faucet.onflow.org/"&gt;Testnet Faucet&lt;/a&gt; outlined in one of the previous articles. 
The function itself is pretty straightforward. We will take the transaction message, specifically packed and represented as hex string and feed it into the &lt;code&gt;update&lt;/code&gt; method exposed by &lt;code&gt;SHA3&lt;/code&gt; , then return the result from the &lt;code&gt;digest&lt;/code&gt; method:
&lt;/li&gt;
&lt;/ul&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;hashMessageHex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msgHex&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sha&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SHA3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;sha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msgHex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&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="nx"&gt;sha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&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;ul&gt;
&lt;li&gt;The next function will call &lt;code&gt;signWithKey&lt;/code&gt; - we will use it to sign our hashed transaction message with a private key. Now this IS a really complicated topic and let’s say you will cut a lot of corners if you simply copy-paste this one and do your crypto research later, mkey? 😅
&lt;strong&gt;tldr&lt;/strong&gt;: we will use a &lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm"&gt;Elliptic Curve Digital Signature Algorithm&lt;/a&gt;&lt;/strong&gt; in order to produce our signature:
&lt;/li&gt;
&lt;/ul&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;signWithKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msgHex&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;curve&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keyFromPrivate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&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="nx"&gt;sig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;hashMessageHex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msgHex&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;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;32&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;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toArrayLike&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;be&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&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;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toArrayLike&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;be&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&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;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The last one will be a &lt;code&gt;signer&lt;/code&gt; function, which will be used as &lt;strong&gt;&lt;a href="https://docs.onflow.org/fcl/reference/api/#authorization-function"&gt;Authorization Function&lt;/a&gt; -&lt;/strong&gt; function which produce the information of the user that is going to sign and a &lt;code&gt;signing function&lt;/code&gt; to use the information to produce a signature.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;signer&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;// We are hard coding these values here, but you can pass those values from outside as well.&lt;/span&gt;
  &lt;span class="c1"&gt;// For example, you can create curried function: &lt;/span&gt;
  &lt;span class="c1"&gt;// const signer = (keyId, accountAdddress, pkey) =&amp;gt; (account) =&amp;gt; {...}&lt;/span&gt;
  &lt;span class="c1"&gt;// and then create multiple signers for different key indices &lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keyId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// always ensure that your keyId is a number not a string&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;accountAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x5593df7d286bcdb8&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="nx"&gt;pkey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;248f1ea7b4a058c39dcc97d91e6a5d0aa7afbc931428561b6efbc7bd0f5e0875&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// authorization function need to return an account&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;...&lt;/span&gt;&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// bunch of defaults in here, we want to overload some of them though&lt;/span&gt;
    &lt;span class="na"&gt;tempId&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;accountAddress&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;keyId&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="c1"&gt;// tempIds are more of an advanced topic, for 99% of the times where you know the address and keyId you will want it to be a unique string per that address and keyId&lt;/span&gt;
    &lt;span class="na"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sansPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accountAddress&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// the address of the signatory, currently it needs to be without a prefix right now&lt;/span&gt;
    &lt;span class="nx"&gt;keyId&lt;/span&gt; &lt;span class="c1"&gt;// this is the keyId for the accounts registered key that will be used to sign, make extra sure this is a number and not a string&lt;/span&gt;

    &lt;span class="c1"&gt;// This is where magic happens! ✨&lt;/span&gt;
    &lt;span class="na"&gt;signingFunction&lt;/span&gt;&lt;span class="p"&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;signable&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;// Singing functions are passed a signable and need to return a composite signature&lt;/span&gt;
      &lt;span class="c1"&gt;// signable.message is a hex string of what needs to be signed.&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;signWithKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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="na"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;withPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accountAddress&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// needs to be the same as the account.addr but this time with a prefix, eventually they will both be with a prefix&lt;/span&gt;
        &lt;span class="nx"&gt;keyId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// needs to be the same as account.keyId, once again make sure its a number and not a string&lt;/span&gt;
        &lt;span class="nx"&gt;signature&lt;/span&gt; &lt;span class="c1"&gt;// this needs to be a hex string of the signature, where signable.message is the hex value that needs to be signed&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;blockquote&gt;
&lt;p&gt;✨Please, note, that &lt;code&gt;signingFunction&lt;/code&gt; is asynchronous, meaning that it can use Promises inside of its body to get a signature out of extension or remote server. Which is super handy, when you want to handle gas fees for your users 😉&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 3 - FCL Setup
&lt;/h3&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="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="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tx&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;@onflow/fcl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;signer&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;./signer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;// Contrary to our wallet signing example, we don't need most of it in our config now&lt;/span&gt;
&lt;span class="c1"&gt;// so we'll get back to simple version&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="s2"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="s2"&gt;0xBasic&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="s2"&gt;0xafabe20e55e9ceb6&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;h3&gt;
  
  
  Step 4 - Implement &lt;code&gt;readCounter&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;We will copy the same function from our previous article, because it will behave absolutely the same:&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;readCounter&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="o"&gt;=&amp;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;cadence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    import Basic from 0xBasic

    pub fun main():UInt{
      return Basic.counter
    }
  `&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;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;cadence&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;counter&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;h3&gt;
  
  
  Step 5 - Implement &lt;code&gt;shiftCounter&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;shiftCounter&lt;/code&gt; function will be almost identical as well. The only difference is that this time we will fill all the roles, using our &lt;code&gt;signer&lt;/code&gt; function. On top of that we will log how much time it took to seal the transaction, using &lt;code&gt;console.time&lt;/code&gt; and &lt;code&gt;console.timeEnd&lt;/code&gt; methods:&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;shiftCounter&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;value&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;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="s2"&gt;%cSigning Transaction&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`color: teal`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Our Cadence code. Notice the use of alias here&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cadence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    import Basic from 0xBasic

    transaction(shift: UInt8){
      prepare(signer: AuthAccount){
        Basic.incrementCounterBy(shift)
      }
    }
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// List of arguments&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&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;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&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;UInt8&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;proposer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signer&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;payer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signer&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;authorizations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;signer&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// "mutate" method will return us transaction id&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;cadence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;proposer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;payer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;authorizations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;999&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="s2"&gt;`Submitted transaction &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;txId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; to the network`&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="s2"&gt;%cWaiting for transaction to be sealed...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`color: teal`&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;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Transaction Sealing Time&lt;/span&gt;&lt;span class="dl"&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;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// We will use transaction id in order to "subscribe" to it's state change and get the details&lt;/span&gt;
  &lt;span class="c1"&gt;// of the transaction&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&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;txId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;onceSealed&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;timeEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;label&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;txDetails&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;h3&gt;
  
  
  Finally
&lt;/h3&gt;

&lt;p&gt;Let's add an IIFE at the end of the file and populate it with methods we have just defined:&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="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;readCounter&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;txDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;shiftCounter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&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;txDetails&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// we will call "readCounter" function second time to ensure &lt;/span&gt;
  &lt;span class="c1"&gt;// that value of counter has changed&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;readCounter&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;After the dust settles your console should have similar output:&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="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;655&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;Signing&lt;/span&gt; &lt;span class="nx"&gt;Transaction&lt;/span&gt;
&lt;span class="nx"&gt;Submitted&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="nx"&gt;d88e98687dd98f7597aca9afaf3daaba788f644f90003c9b144bfa13440fd9ab&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;network&lt;/span&gt; 
&lt;span class="nx"&gt;Waiting&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;sealed&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nx"&gt;Transaction&lt;/span&gt; &lt;span class="nx"&gt;Sealing&lt;/span&gt; &lt;span class="nx"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;14749.60000000149&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;txDetails&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;667&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;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4gqOsFsp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://c.tenor.com/eIV3XiQyw4AAAAAC/you-did-it-willy-wonka-and-the-chocolate-factory.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4gqOsFsp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://c.tenor.com/eIV3XiQyw4AAAAAC/you-did-it-willy-wonka-and-the-chocolate-factory.gif" alt="https://c.tenor.com/eIV3XiQyw4AAAAAC/you-did-it-willy-wonka-and-the-chocolate-factory.gif" width="498" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It wasn’t that hard in the end, right? 😉&lt;/p&gt;

&lt;p&gt;Until next time! 👋 &lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full Source Code -&lt;/strong&gt; &lt;a href="https://codesandbox.io/s/dev-to-14-mutate-with-pkey-d0jsj0?file=/src/index.js"&gt;https://codesandbox.io/s/dev-to-14-mutate-with-pkey-d0jsj0&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Package - SHA3&lt;/strong&gt; - &lt;a href="https://www.npmjs.com/package/sha3"&gt;https://www.npmjs.com/package/sha3&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Package - elliptic&lt;/strong&gt; - &lt;a href="https://www.npmjs.com/package/elliptic"&gt;https://www.npmjs.com/package/elliptic&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FCL - Authorization Function&lt;/strong&gt; - &lt;a href="https://docs.onflow.org/fcl/reference/api/#authorization-function"&gt;https://docs.onflow.org/fcl/reference/api/#authorization-function&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other resources you might find useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flow Docs Site&lt;/strong&gt; - &lt;a href="https://docs.onflow.org/"&gt;https://docs.onflow.org/&lt;/a&gt; - More detailed information about Flow blockchain and how to interact with it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flow Portal&lt;/strong&gt; - &lt;a href="https://flow.com/"&gt;https://flow.com/&lt;/a&gt; - your entry point to Flow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FCL JS&lt;/strong&gt; - &lt;a href="https://github.com/onflow/fcl-js"&gt;https://github.com/onflow/fcl-js&lt;/a&gt; - Source code and ability to contribute to the FCL JS library&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cadence&lt;/strong&gt; - &lt;a href="https://docs.onflow.org/cadence/"&gt;https://docs.onflow.org/cadence/&lt;/a&gt; - Introduction to Cadence&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codesandbox&lt;/strong&gt; - &lt;a href="https://codesandbox.io/"&gt;https://codesandbox.io&lt;/a&gt; - An amazing in-browser IDE enabling quick prototyping&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>onflow</category>
      <category>fcl</category>
    </item>
    <item>
      <title>Build on Flow | Learn FCL - 13. How to Modify the State of the Chain by Signing Transactions with Wallets</title>
      <dc:creator>Max Daunarovich</dc:creator>
      <pubDate>Mon, 25 Jul 2022 16:49:00 +0000</pubDate>
      <link>https://dev.to/onflow/build-on-flow-learn-fcl-13-how-to-modify-the-state-of-the-chain-by-signing-transactions-with-wallets-3ndl</link>
      <guid>https://dev.to/onflow/build-on-flow-learn-fcl-13-how-to-modify-the-state-of-the-chain-by-signing-transactions-with-wallets-3ndl</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;In this post we will learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Signing roles - &lt;code&gt;payer&lt;/code&gt;, &lt;code&gt;proposer&lt;/code&gt; and &lt;code&gt;authorizers&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;What is a signing function and how to create one&lt;/li&gt;
&lt;li&gt;How to sign a transaction with one of your wallets&lt;/li&gt;
&lt;li&gt;How to sign a transaction with your private key&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Preface
&lt;/h2&gt;

&lt;p&gt;Once we have our wallet or private keys, we can start signing transactions. Woohoo! &lt;/p&gt;

&lt;p&gt;For better understanding of how this works, you will need some extra knowledge.&lt;/p&gt;

&lt;p&gt;The signing process on Flow requires 3 different parties to sign the transaction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Proposer&lt;/code&gt; - this is the account, which proposes to include changes done by transaction into the blockchain. Proposer role can be filled by any account on Flow blockchain.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Payer&lt;/code&gt; is the account, who will pay the gas fees for transaction execution. Similar to &lt;code&gt;proposer&lt;/code&gt; , this can be any account, who have enough FLOW tokens to cover the fee and is eager to do it.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Authorizers&lt;/code&gt; - this is a list of accounts, who authorize any changes in their accounts, done by transaction they are signing. These should be accounts, that want to make said changes. If there is only a single account, it should still be a list of one.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡All of those roles can be filled by the same account! You don’t need to have 3 “actors” to sign transaction 😅&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 1 - Installation
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;"@onflow/fcl": "1.0.0"&lt;/code&gt; as your dependency&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 - Setup
&lt;/h3&gt;

&lt;p&gt;Just like the last time we will import necessary methods and setup FCL. This time, though, we will extend our configuration with some new values to enable Wallet Discovery.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;FCL Wallet Discovery&lt;/code&gt; allows you to connect to all known and registered wallets at once! If you are coming from Ethereum, you can think about it as Flow variant of &lt;a href="https://walletconnect.com/"&gt;WalletConnect&lt;/a&gt; sans multichain support 😅&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note that we are using slightly different way to specify config by passing in object instead of calling multiple &lt;code&gt;.put&lt;/code&gt; calls:&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="c1"&gt;// Import methods from FCL&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;query&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="s2"&gt;@onflow/fcl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Configure FCL&lt;/span&gt;
&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="c1"&gt;// Use Testnet Access Node&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="c1"&gt;// We will also specify the network as some of the FCL parts need it to properly do it's work&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;testnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// This will be the title of our DApp&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="s2"&gt;Meow DApp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// This is just a kitten photo, we will use for the icon&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="s2"&gt;https://placekitten.com/g/200/200&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// Next two will define where Wallet Discovery is located&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://fcl-discovery.onflow.org/testnet/authn&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="s2"&gt;discovery.authn.endpoint&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="s2"&gt;https://fcl-discovery.onflow.org/api/testnet/authn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c1"&gt;// We will also set alias for the contract we will use in this example&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0xBasic&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="s2"&gt;0xafabe20e55e9ceb6&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;p&gt;You can read more information about those and other configuration keys on FCL &lt;a href="https://github.com/onflow/fcl-js/blob/master/docs/reference/configure-fcl.mdx#common-configuration-keys"&gt;documentation page&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 - Get Current Chain State
&lt;/h3&gt;

&lt;p&gt;We’ve deployed a &lt;a href="https://flow-view-source.com/testnet/account/0xafabe20e55e9ceb6/contract/Basic"&gt;Basic contract&lt;/a&gt; at &lt;code&gt;0xafabe20e55e9ceb6&lt;/code&gt;. If you click on that link it will lead you to Flow View Source. You can see there is a single public variable &lt;code&gt;counter&lt;/code&gt;, that we can read and a couple of methods to modify it. Let’s use the knowledge from previous articles and read it.&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;readCounter&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="o"&gt;=&amp;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;cadence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    import Basic from 0xBasic

    pub fun main():UInt{
      return Basic.counter
    }
  `&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;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;cadence&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;counter&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;This simple query looks exactly like what we’ve built before, except this time we are using &lt;code&gt;0xBasic&lt;/code&gt; alias for the address. FCL will use the value we set in the config - &lt;code&gt;0xafabe20e55e9ceb6&lt;/code&gt; - and replace it. We are doing it this way, cause we will make calls to the contract from our  transaction as well. So we have this value nice and handy in one place and we don’t need to constantly reference it or memorize it 😉 &lt;/p&gt;

&lt;p&gt;You should see some output in your console, similar to this (number can be different, as there are multiple users, who would want to alter it):&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="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;19&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;h3&gt;
  
  
  Step 4 - Modify Counter
&lt;/h3&gt;

&lt;p&gt;We will use method &lt;code&gt;mutate&lt;/code&gt; provided by FCL package to modify the state of the chain. In its most basic form &lt;code&gt;mutate&lt;/code&gt; is very similar to &lt;code&gt;query&lt;/code&gt;, but it’s using some hidden mechanisms in order to sign the transaction (we will demystify them in later article). &lt;/p&gt;

&lt;p&gt;Let’s define another method &lt;code&gt;shiftCounter&lt;/code&gt;, which we will be using to modify the value of the &lt;code&gt;counter&lt;/code&gt;. If you go back to the &lt;code&gt;Basic&lt;/code&gt; &lt;a href="https://flow-view-source.com/testnet/account/0xafabe20e55e9ceb6/contract/Basic"&gt;contract&lt;/a&gt; you will see that it defines two methods. We will use &lt;code&gt;incrementCounterBy(_ step: UInt8)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We will need to pass &lt;code&gt;UInt8&lt;/code&gt; value as an argument to the transaction - we do it the same way we’ve &lt;a href="https://dev.to/onflow/build-on-flow-learn-fcl-2-pass-arguments-to-scripts-393f"&gt;done previously&lt;/a&gt; using the &lt;code&gt;query&lt;/code&gt; method.&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;shiftCounter&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;value&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;// Our Cadence code. Notice we are using alias here as well&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cadence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    import Basic from 0xBasic

    transaction(shift: UInt8){
      prepare(signer: AuthAccount){
        Basic.incrementCounterBy(shift)
      }
    }
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// List of arguments&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&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="c1"&gt;// We need to pass UInt8 value, but it should be a string, remember? :)&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;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&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;UInt8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// "mutate" method will return us transaction id&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;cadence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;999&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// We will use transaction id in order to "subscribe" to it's state change and get the details&lt;/span&gt;
  &lt;span class="c1"&gt;// of the transaction&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&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;txId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;onceSealed&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;txDetails&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait, but what about those roles we’ve mentioned above. You see, &lt;code&gt;mutate&lt;/code&gt; will populate all of them with the current authenticated user…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q9F2uLYC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://c.tenor.com/d-bHBk4UYs4AAAAC/who.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q9F2uLYC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://c.tenor.com/d-bHBk4UYs4AAAAC/who.gif" alt="https://c.tenor.com/d-bHBk4UYs4AAAAC/who.gif" width="382" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s part of the FCL and Wallet Discovery magic 🎇. If you don’t specify any role in that &lt;code&gt;mutate&lt;/code&gt; method it will ask you to connect to the wallet and then use selected account as current user. Then it will use all the necessary params to fill in the roles in that interaction. Pretty cool, ha? 😎&lt;/p&gt;

&lt;h3&gt;
  
  
  Finally
&lt;/h3&gt;

&lt;p&gt;Let's add an IIFE at the end of the file and populate it with methods we have just defined:&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="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// You can [un]comment this line to toggle Wallet Discovery&lt;/span&gt;
  &lt;span class="nf"&gt;unauthenticate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Let's read value, currently set on contract &lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;readCounter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Let's modify the state now&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;shiftCounter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;13&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;txDetails&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Now we can check that value is actually changed&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;readCounter&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;When the code on the page will execute it will present you a popup, allowing to choose which wallet to use.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ You need to have Lilico installed in order for it to appear in the list. Consult one of &lt;a href="https://dev.to/onflow/build-on-flow-learn-fcl-11-how-to-install-and-create-a-new-testnet-account-with-lillico-18i"&gt;our previous articles&lt;/a&gt; for details how to install and setup &lt;a href="https://lilico.app/"&gt;Lilico&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwc81d4zwpwsfyca9w0k2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwc81d4zwpwsfyca9w0k2.png" alt="Pick Wallet" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you were to choose &lt;code&gt;Lilico&lt;/code&gt;, you will be presented with following flow. First it will ask you to connect wallet to our dapp:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fys5aidi8g0e8su2j2214.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fys5aidi8g0e8su2j2214.png" alt="Connect Lilico" width="408" height="624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then ask for confirmation. You can expand/collapse script pane to check the code of the transaction.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Actually, you should ALWAYS check what you are signing. Even on Testnet. It’s a good habit, that will help you make your interaction with Flow more secure 😉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fckrj5avioam3u4bzw865.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fckrj5avioam3u4bzw865.png" alt="Lilico - Approve" width="420" height="631"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://dev.to/onflow/build-on-flow-learn-fcl-10-how-to-create-a-new-testnet-account-with-blocto-wallet-4lda"&gt;Blocto&lt;/a&gt; will guide your through a similar process:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fovx8la1k5csdgmnc27vq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fovx8la1k5csdgmnc27vq.png" alt="Use Blocto" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And it also has a way to check the transaction code:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fom4yqp9is88r2oesyxku.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fom4yqp9is88r2oesyxku.png" alt="Blocto - Confirm" width="417" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After all said and done you should see the following in your console (numbers might change):&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;234&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="na"&gt;txDetails&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;247&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;p&gt;Expanding &lt;code&gt;txDetails&lt;/code&gt; will give your more information about the transaction:&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="nx"&gt;blockId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ad7605f10f9846dd1c5603723b1d12995a3152b19a1ca24e47a3a2e28cee0641&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="nx"&gt;statusString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SEALED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="nx"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;
&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://i.giphy.com/media/3o7btNa0RUYa5E7iiQ/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/3o7btNa0RUYa5E7iiQ/giphy.gif" alt="https://media.giphy.com/media/3o7btNa0RUYa5E7iiQ/giphy.gif" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Until next time! 👋 &lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full Source Code&lt;/strong&gt; - &lt;a href="https://codesandbox.io/s/dev-to-part-13-modify-chain-state-1oy1l7?file=/index.html"&gt;https://codesandbox.io/s/dev-to-part-13-modify-chain-state-1oy1l7&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FCL - &lt;code&gt;mutate&lt;/code&gt; method -&lt;/strong&gt; &lt;a href="https://docs.onflow.org/fcl/reference/api/#mutate"&gt;https://docs.onflow.org/fcl/reference/api/#mutate&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cadence - Transactions -&lt;/strong&gt; &lt;a href="https://docs.onflow.org/cadence/language/transactions/"&gt;https://docs.onflow.org/cadence/language/transactions/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lilico Wallet&lt;/strong&gt; - &lt;a href="https://lilico.app/"&gt;https://lilico.app/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other resources you might find useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flow Docs Site&lt;/strong&gt; - &lt;a href="https://docs.onflow.org/"&gt;https://docs.onflow.org/&lt;/a&gt; - More detailed information about Flow blockchain and how to interact with it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flow Portal&lt;/strong&gt; - &lt;a href="https://flow.com/"&gt;https://flow.com/&lt;/a&gt; - your entry point to Flow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FCL JS&lt;/strong&gt; - &lt;a href="https://github.com/onflow/fcl-js"&gt;https://github.com/onflow/fcl-js&lt;/a&gt; - Source code and ability to contribute to the FCL JS library&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cadence&lt;/strong&gt; - &lt;a href="https://docs.onflow.org/cadence/"&gt;https://docs.onflow.org/cadence/&lt;/a&gt; - Introduction to Cadence&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codesandbox&lt;/strong&gt; - &lt;a href="https://codesandbox.io/"&gt;https://codesandbox.io&lt;/a&gt; - An amazing in-browser IDE enabling quick prototyping&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>fcl</category>
      <category>onflow</category>
    </item>
    <item>
      <title>Создаем на Flow | Изучаем FCL - 1. Введение</title>
      <dc:creator>Max Daunarovich</dc:creator>
      <pubDate>Wed, 29 Jun 2022 12:48:46 +0000</pubDate>
      <link>https://dev.to/onflow/sozdaiem-na-flow-izuchaiem-fcl-1-vviedieniie-4g8j</link>
      <guid>https://dev.to/onflow/sozdaiem-na-flow-izuchaiem-fcl-1-vviedieniie-4g8j</guid>
      <description>&lt;h2&gt;
  
  
  Краткий обзор
&lt;/h2&gt;

&lt;p&gt;После того, как вы закончите чтение этой статьи вы будете знать:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;что такое FCL и зачем он вам нужен&lt;/li&gt;
&lt;li&gt;как настроить FCL JS для взаимодействия с Тестовой сетью (Тестнет / Testnet) блокчейна Flow&lt;/li&gt;
&lt;li&gt;как запустить исполнение простого скрипта написанного на языке Cadence&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Что такое FCL?
&lt;/h2&gt;

&lt;p&gt;Flow Client Library (FCL) - это стандартизированный набор коммуникационных шаблонов между "кошельками" (wallets), приложениями и пользователями, который используется для выполнения большого разнообразия действий в вашем децентрализованном приложении. Различные языки программирования имеют свои собственные имплементации концепции FCL и стандарта.&lt;/p&gt;

&lt;p&gt;В среде Javascript, это NPM-пакет, который используется для взаимодействия между кошельками, пользователем и блокчейном Flow, как в браузере так и на серверной стороне.&lt;/p&gt;

&lt;h2&gt;
  
  
  Подожди, а что за блокчейн такой, Flow?
&lt;/h2&gt;

&lt;p&gt;Я рад, что вы задали такой вопрос! Flow - это блокчейн, созданный специально для нового поколения приложений, игр и цифровых “предметов” используемых в них.&lt;/p&gt;

&lt;p&gt;Есть много различных характеристик, которые делают Flow уникальной “цепью”. Вот некоторые из них:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cadence&lt;/strong&gt; - это новый легко-изучаемый ресурсо-ориентированный язык программирования, разработанный для децентрализованных приложений (dApps) и цифровых “предметов”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Обновляемые Смарт-Контракты&lt;/strong&gt; - позволяет безопасно и “прозрачно” исправить ошибки и обновить предопределенные части смарт-контракта&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Быстрая и Детерминированная Завершенность (Finality)&lt;/strong&gt; - Flow разработан таким образом, чтобы быть быстрый и отзывчивым - позволяя достигнуть глобальной завершенности в течении нескольких секунд&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Вы можете найти больше информации о блокчейне Flow на сайтах &lt;a href="https://flow.com/"&gt;https://flow.com&lt;/a&gt; и &lt;a href="https://docs.onflow.org/"&gt;https://docs.onflow.org/&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;К сожалению, в данный момент документация доступно только на английском языке 😢 &lt;br&gt;
Но мы работаем в этом направлении и обновим ссылки на русско-язычные ресурсы, как только они станут доступны&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Простой Пример
&lt;/h2&gt;

&lt;p&gt;В последующих статьях мы покажем более сложные и значительные пример, но пока давайте попросим тестовую сеть Flow вернуть нам определенное число (пожалуйста не убегайте, дальше будет гораздо интереснее 😅)&lt;/p&gt;

&lt;p&gt;Воспользуемся платформой Codesandbox (&lt;a href="https://codesandbox.io/"&gt;https://codesandbox.io&lt;/a&gt;), чтобы было проще поделиться с вами готовым решением и позволяя вам “форкнуть” (создать свою копию, чтобы иметь возможность делать в ней изменения) “песочницу” и попробовать свои идеи.&lt;/p&gt;

&lt;h3&gt;
  
  
  Шаг 1 - Установка
&lt;/h3&gt;

&lt;p&gt;Добавьте пакет &lt;code&gt;"@onflow/fcl": "1.0.0"&lt;/code&gt; в качестве одной из ваших “зависимостей”:&lt;/p&gt;

&lt;h3&gt;
  
  
  Шаг 2 - Импорт
&lt;/h3&gt;

&lt;p&gt;Программный пакет FCL JS предоставляет множество методов - для “постройки” взаимодействий, конфигурации FCL, взаимодействии с цепью и т.д. Мы импортируем два их них:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;query&lt;/code&gt; (&lt;a href="https://docs.onflow.org/fcl/reference/api/#query"&gt;https://docs.onflow.org/fcl/reference/api/#query&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;config&lt;/code&gt; (&lt;a href="https://docs.onflow.org/fcl/reference/api/#common-configuration-keys"&gt;https://docs.onflow.org/fcl/reference/api/#common-configuration-keys&lt;/a&gt;)
&lt;/li&gt;
&lt;/ul&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;query&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="s2"&gt;@onflow/fcl&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;h3&gt;
  
  
  Шаг 3 - Настройка FCL
&lt;/h3&gt;

&lt;p&gt;FCL должен знать, куда ему отправлять скрипт для обработки. Нижеследующий код задаст адрес Узла Доступа (Access Node) используя метод &lt;code&gt;config&lt;/code&gt;:&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;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://rest-testnet.onflow.org&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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;api&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Шаг 4 - Исполните скрипт на Тестнете
&lt;/h3&gt;

&lt;p&gt;Для того, чтобы исполнить скрипта на блокчейне Flow, мы можем отправить его при помощи метода &lt;code&gt;query&lt;/code&gt; . Наш пример не использует аргументов (параметров), поэтому внутрь &lt;code&gt;query&lt;/code&gt; мы передадим только код скрипта:&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;cadence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    pub fun main(): Int{
      return 42
    }
  `&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;theAnswer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;cadence&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;theAnswer&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  В итоге - Полный Код
&lt;/h3&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;query&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="s2"&gt;@onflow/fcl&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="nx"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://rest-testnet.onflow.org&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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;api&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Мы воспользуемся конструкцией IIFE чтобы автоматически // запустить наш код &lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&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;cadence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    pub fun main(): Int{
      return 42
    }
  `&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;cadence&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;result&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;После выполнения данного блока кода вы должны увидеть ответ в консоли:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;result: &lt;span class="s2"&gt;"42"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Поздравляем! Вы успешно справились с заданием 👍&lt;/p&gt;

&lt;p&gt;В следующей статье мы покажем, как вы можете передавать параметры для ваших скриптов. Оставайтесь на связи! 👋&lt;/p&gt;

&lt;h2&gt;
  
  
  Материалы
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;(ENG) | Полный пример на Codesandbox&lt;/strong&gt; - &lt;a href="https://codesandbox.io/s/dev-to-fcl-01-introduction-zbhz0v"&gt;https://codesandbox.io/s/dev-to-fcl-01-introduction-zbhz0v&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Ccылки и Исходный Код
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;(ENG) | Документация Flow&lt;/strong&gt;  - &lt;a href="https://docs.onflow.org/"&gt;https://docs.onflow.org/&lt;/a&gt; - более детальная информации о блокчейне Flow и как взаимодействовать с ним&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(ENG) | Flow Portal&lt;/strong&gt; - &lt;a href="https://flow.com/"&gt;https://flow.com/&lt;/a&gt; - your entry point to Flow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(ENG) | FCL JS&lt;/strong&gt; - &lt;a href="https://github.com/onflow/fcl-js"&gt;https://github.com/onflow/fcl-js&lt;/a&gt; - Исходный код и возможность поучаствовать в разработке библиотеки FCL JS library&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(ENG) | Cadence&lt;/strong&gt; - &lt;a href="https://docs.onflow.org/cadence/"&gt;https://docs.onflow.org/cadence/&lt;/a&gt; - Введение в язык программирования Cadence&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codesandbox&lt;/strong&gt; - &lt;a href="https://codesandbox.io/"&gt;https://codesandbox.io&lt;/a&gt; - Замечательная среда разработки и прототипирования прямо в вашем браузере&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>blockchain</category>
      <category>onflow</category>
    </item>
  </channel>
</rss>
