<?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>Forem: kenny</title>
    <description>The latest articles on Forem by kenny (@krgrs).</description>
    <link>https://forem.com/krgrs</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%2F425864%2F869e68b7-991a-4b9b-aadd-8c03f0eef9f0.jpg</url>
      <title>Forem: kenny</title>
      <link>https://forem.com/krgrs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/krgrs"/>
    <language>en</language>
    <item>
      <title>Bitcoin Unleashed - Understanding Bitcoin DeFi Resources</title>
      <dc:creator>kenny</dc:creator>
      <pubDate>Tue, 05 Apr 2022 05:03:49 +0000</pubDate>
      <link>https://forem.com/krgrs/bitcoin-unleashed-understanding-bitcoin-defi-resources-160n</link>
      <guid>https://forem.com/krgrs/bitcoin-unleashed-understanding-bitcoin-defi-resources-160n</guid>
      <description>&lt;h2&gt;
  
  
  Catamaran Swaps
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.catamaranswaps.org/"&gt;Website&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.hiro.so/blog/bitcoin-defi-is-here-a-deep-dive-into-trust-less-swaps"&gt;Article on Catamaran Swaps and Bitcoin DeFi&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/friedger/clarity-catamaranswaps"&gt;Catamaran Swaps Code on GitHub&lt;/a&gt;&lt;br&gt;
&lt;a href="https://explorer.stacks.co/txid/SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.btc-stx-swap-v1?chain=mainnet"&gt;Deployed Catmaran Swaps Clarity Contract&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Zest Protocol
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.zestprotocol.com/"&gt;Zest Protocol Website&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/stacksgov/Stacks-Grants/issues/234"&gt;Open Wishlist Grant&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn Stacks Development
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://start.stacks.org/"&gt;Starting Stacks&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Test-Driven Stacks Development with Clarinet</title>
      <dc:creator>kenny</dc:creator>
      <pubDate>Wed, 30 Mar 2022 18:39:00 +0000</pubDate>
      <link>https://forem.com/stacks/test-driven-stacks-development-with-clarinet-2e4i</link>
      <guid>https://forem.com/stacks/test-driven-stacks-development-with-clarinet-2e4i</guid>
      <description>&lt;p&gt;&lt;strong&gt;Make sure you check out the Refactoring section of this tutorial. The original implementation of this contract and the tests had a couple of gaps. I kept them in and added a refactoring section to help others learn from these fixes and the process. Big thanks to &lt;a href="https://twitter.com/LNow_" rel="noopener noreferrer"&gt;lnow&lt;/a&gt; for helping to point these issues out and rework them.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the most difficult things about smart contract and web3 development can be getting an effective development environment set up.&lt;/p&gt;

&lt;p&gt;Since the blockchain itself is a critical piece of our development infrastructure, we need to do have some way of setting up our own local instance of the blockchain we are building for.&lt;/p&gt;

&lt;p&gt;In the Ethereum world, Hardhat is a commonly used tool for local Ethereum development with Solidity.&lt;/p&gt;

&lt;p&gt;In the Stacks world, we have &lt;a href="https://github.com/hirosystems/clarinet" rel="noopener noreferrer"&gt;Clarinet&lt;/a&gt;, which accomplishes something similar.&lt;/p&gt;

&lt;p&gt;Clarinet allows us to not only get a Clarity smart contract project set up but also to create a local Stacks chain to interact with.&lt;/p&gt;

&lt;p&gt;This makes it trivial to begin building Stacks apps without having to deploy our smart contracts to testnet and interact with them that way.&lt;/p&gt;

&lt;p&gt;This can significantly cut down on our development time.&lt;/p&gt;

&lt;p&gt;Other benefits of using Clarinet include Clarity syntax checking, deploying contracts to testnet and mainnet using the CLI, writing and executing a test suite, checking our code's test coverage, and running our contract cost analysis.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/hirosystems/clarinet" rel="noopener noreferrer"&gt;Clarinet GitHub page&lt;/a&gt; does a great job of laying out all the different features of Clarinet if you are curious to learn more.&lt;/p&gt;

&lt;p&gt;Hiro also recently released a &lt;a href="https://www.youtube.com/playlist?list=PL5Ujm489LoJaAz9kUJm8lYUWdGJ2AnQTb" rel="noopener noreferrer"&gt;series of screencasts&lt;/a&gt; going over the essentials of Clarinet.&lt;/p&gt;

&lt;p&gt;Today, we're going to look at how to use Clarinet to build a Stacks app using TDD, or test-driven development. We'll write our tests, write a Clarity smart contract to get them to pass, check out costs and explore ways to optimize them and improve on what we'll be making here.&lt;/p&gt;

&lt;p&gt;TDD seems annoying and unnecessary until you try it, and then it's magical.&lt;/p&gt;

&lt;p&gt;This goes double for smart contract development, where the code is permanent, public, and often controls peoples' finances and other assets.&lt;/p&gt;

&lt;p&gt;Getting a smart contract right the first time can save a lot of headaches and potential security issues down the road. Putting in the effort upfront to test your code well and &lt;a href="https://stacks.org/smart-contract-audits" rel="noopener noreferrer"&gt;getting a professional audit&lt;/a&gt; are significantly better options than having a security breach and having to migrate your contract after deploying.&lt;/p&gt;

&lt;p&gt;Using TDD allows us to map out how our smart contract should function and get a mental roadmap of how we want it to work, and then write our smart contracts in order to get those tests to pass.&lt;/p&gt;

&lt;p&gt;This helps both for thinking through what we want our code to do and ensuring that the entirety of our Clarity contracts are covered by robust tests.&lt;/p&gt;

&lt;p&gt;In this tutorial, we'll use Clarinet to start a new project, create tests for our smart contracts, write the smart contracts themselves, check the syntax of those contracts, check the cost and explore optimization strategies, and deploy them to testnet, all using Clarinet. &lt;/p&gt;

&lt;p&gt;Let's get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We're Building
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we'll be building a simple app called Cargo. Cargo is a fictional, simple Stacks app designed to help facilitate tracking the progress a shipment makes throughout the supply chain.&lt;/p&gt;

&lt;p&gt;In this particular app, we'll track a package's travel progress using a simple map, then explore ways to improve upon the implementation presented here.&lt;/p&gt;

&lt;p&gt;We'll also go over some next steps for you to improve upon this project on your own in order to increase your learning.&lt;/p&gt;

&lt;p&gt;You can find the completed code for this tutorial &lt;a href="https://github.com/kenrogers/cargo" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Clarinet
&lt;/h2&gt;

&lt;p&gt;If you don't have Clarinet installed, you'll need to do that first. I can't do a better job than the &lt;a href="https://github.com/hirosystems/clarinet#installation" rel="noopener noreferrer"&gt;Clarinet docs&lt;/a&gt; at showing that so I will refer you to them.&lt;/p&gt;

&lt;p&gt;In order to run our local Stacks chain with &lt;code&gt;clarinet integrate&lt;/code&gt;, you'll need to make sure you have Docker installed and running as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up a New Clarinet Project
&lt;/h2&gt;

&lt;p&gt;Alright, let's get this thing going.&lt;/p&gt;

&lt;p&gt;First up, let's set up our project with &lt;code&gt;clarinet new cargo&lt;/code&gt; and then &lt;code&gt;cd&lt;/code&gt; into that directory.&lt;/p&gt;

&lt;p&gt;When you look in that directory you'll see some empty folders, &lt;code&gt;contracts&lt;/code&gt; and &lt;code&gt;tests&lt;/code&gt;, and you'll see a &lt;code&gt;settings&lt;/code&gt; folder with three &lt;code&gt;.toml&lt;/code&gt; files in it.&lt;/p&gt;

&lt;p&gt;These files correspond to the settings for each of the three primary development environments.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Devnet.toml&lt;/code&gt; corresponds to our local chain when we run &lt;code&gt;clarinet integrate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Testnet.toml&lt;/code&gt; and &lt;code&gt;Mainnet.toml&lt;/code&gt; correspond to the settings we want to use when we deploy to the Stacks testnet and mainnet, respectively.&lt;/p&gt;

&lt;p&gt;Let's take a look at the &lt;code&gt;Devnet.toml&lt;/code&gt; file, we'll look at the other two when we deploy at the end of the tutorial.&lt;/p&gt;

&lt;p&gt;Here's what our &lt;code&gt;Devnet.toml&lt;/code&gt; file looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[network]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"devnet"&lt;/span&gt;
&lt;span class="py"&gt;deployment_fee_rate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;

&lt;span class="nn"&gt;[accounts.deployer]&lt;/span&gt;
&lt;span class="py"&gt;mnemonic&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw"&lt;/span&gt;
&lt;span class="py"&gt;balance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100_000_000_000_000&lt;/span&gt;
&lt;span class="c"&gt;# secret_key: 753b7cc01a1a2e86221266a154af739463fce51219d97e4f856cd7200c3bd2a601&lt;/span&gt;
&lt;span class="c"&gt;# stx_address: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM&lt;/span&gt;
&lt;span class="c"&gt;# btc_address: mqVnk6NPRdhntvfm4hh9vvjiRkFDUuSYsH&lt;/span&gt;

&lt;span class="nn"&gt;[accounts.wallet_1]&lt;/span&gt;
&lt;span class="py"&gt;mnemonic&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"sell invite acquire kitten bamboo drastic jelly vivid peace spawn twice guilt pave pen trash pretty park cube fragile unaware remain midnight betray rebuild"&lt;/span&gt;
&lt;span class="py"&gt;balance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100_000_000_000_000&lt;/span&gt;
&lt;span class="c"&gt;# secret_key: 7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801&lt;/span&gt;
&lt;span class="c"&gt;# stx_address: ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5&lt;/span&gt;
&lt;span class="c"&gt;# btc_address: mr1iPkD9N3RJZZxXRk7xF9d36gffa6exNC&lt;/span&gt;

&lt;span class="nn"&gt;[accounts.wallet_2]&lt;/span&gt;
&lt;span class="py"&gt;mnemonic&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hold excess usual excess ring elephant install account glad dry fragile donkey gaze humble truck breeze nation gasp vacuum limb head keep delay hospital"&lt;/span&gt;
&lt;span class="py"&gt;balance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100_000_000_000_000&lt;/span&gt;
&lt;span class="c"&gt;# secret_key: 530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101&lt;/span&gt;
&lt;span class="c"&gt;# stx_address: ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG&lt;/span&gt;
&lt;span class="c"&gt;# btc_address: muYdXKmX9bByAueDe6KFfHd5Ff1gdN9ErG&lt;/span&gt;

&lt;span class="nn"&gt;[accounts.wallet_3]&lt;/span&gt;
&lt;span class="py"&gt;mnemonic&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"cycle puppy glare enroll cost improve round trend wrist mushroom scorpion tower claim oppose clever elephant dinosaur eight problem before frozen dune wagon high"&lt;/span&gt;
&lt;span class="py"&gt;balance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100_000_000_000_000&lt;/span&gt;
&lt;span class="c"&gt;# secret_key: d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901&lt;/span&gt;
&lt;span class="c"&gt;# stx_address: ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC&lt;/span&gt;
&lt;span class="c"&gt;# btc_address: mvZtbibDAAA3WLpY7zXXFqRa3T4XSknBX7&lt;/span&gt;

&lt;span class="nn"&gt;[accounts.wallet_4]&lt;/span&gt;
&lt;span class="py"&gt;mnemonic&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"board list obtain sugar hour worth raven scout denial thunder horse logic fury scorpion fold genuine phrase wealth news aim below celery when cabin"&lt;/span&gt;
&lt;span class="py"&gt;balance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100_000_000_000_000&lt;/span&gt;
&lt;span class="c"&gt;# secret_key: f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701&lt;/span&gt;
&lt;span class="c"&gt;# stx_address: ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND&lt;/span&gt;
&lt;span class="c"&gt;# btc_address: mg1C76bNTutiCDV3t9nWhZs3Dc8LzUufj8&lt;/span&gt;

&lt;span class="nn"&gt;[accounts.wallet_5]&lt;/span&gt;
&lt;span class="py"&gt;mnemonic&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hurry aunt blame peanut heavy update captain human rice crime juice adult scale device promote vast project quiz unit note reform update climb purchase"&lt;/span&gt;
&lt;span class="py"&gt;balance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100_000_000_000_000&lt;/span&gt;
&lt;span class="c"&gt;# secret_key: 3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801&lt;/span&gt;
&lt;span class="c"&gt;# stx_address: ST2REHHS5J3CERCRBEPMGH7921Q6PYKAADT7JP2VB&lt;/span&gt;
&lt;span class="c"&gt;# btc_address: mweN5WVqadScHdA81aATSdcVr4B6dNokqx&lt;/span&gt;

&lt;span class="nn"&gt;[accounts.wallet_6]&lt;/span&gt;
&lt;span class="py"&gt;mnemonic&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"area desk dutch sign gold cricket dawn toward giggle vibrant indoor bench warfare wagon number tiny universe sand talk dilemma pottery bone trap buddy"&lt;/span&gt;
&lt;span class="py"&gt;balance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100_000_000_000_000&lt;/span&gt;
&lt;span class="c"&gt;# secret_key: 7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01&lt;/span&gt;
&lt;span class="c"&gt;# stx_address: ST3AM1A56AK2C1XAFJ4115ZSV26EB49BVQ10MGCS0&lt;/span&gt;
&lt;span class="c"&gt;# btc_address: mzxXgV6e4BZSsz8zVHm3TmqbECt7mbuErt&lt;/span&gt;

&lt;span class="nn"&gt;[accounts.wallet_7]&lt;/span&gt;
&lt;span class="py"&gt;mnemonic&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"prevent gallery kind limb income control noise together echo rival record wedding sense uncover school version force bleak nuclear include danger skirt enact arrow"&lt;/span&gt;
&lt;span class="py"&gt;balance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100_000_000_000_000&lt;/span&gt;
&lt;span class="c"&gt;# secret_key: b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401&lt;/span&gt;
&lt;span class="c"&gt;# stx_address: ST3PF13W7Z0RRM42A8VZRVFQ75SV1K26RXEP8YGKJ&lt;/span&gt;
&lt;span class="c"&gt;# btc_address: n37mwmru2oaVosgfuvzBwgV2ysCQRrLko7&lt;/span&gt;

&lt;span class="nn"&gt;[accounts.wallet_8]&lt;/span&gt;
&lt;span class="py"&gt;mnemonic&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"female adjust gallery certain visit token during great side clown fitness like hurt clip knife warm bench start reunion globe detail dream depend fortune"&lt;/span&gt;
&lt;span class="py"&gt;balance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100_000_000_000_000&lt;/span&gt;
&lt;span class="c"&gt;# secret_key: 6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01&lt;/span&gt;
&lt;span class="c"&gt;# stx_address: ST3NBRSFKX28FQ2ZJ1MAKX58HKHSDGNV5N7R21XCP&lt;/span&gt;
&lt;span class="c"&gt;# btc_address: n2v875jbJ4RjBnTjgbfikDfnwsDV5iUByw&lt;/span&gt;

&lt;span class="nn"&gt;[accounts.wallet_9]&lt;/span&gt;
&lt;span class="py"&gt;mnemonic&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"shadow private easily thought say logic fault paddle word top book during ignore notable orange flight clock image wealth health outside kitten belt reform"&lt;/span&gt;
&lt;span class="py"&gt;balance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100_000_000_000_000&lt;/span&gt;
&lt;span class="c"&gt;# secret_key: de433bdfa14ec43aa1098d5be594c8ffb20a31485ff9de2923b2689471c401b801&lt;/span&gt;
&lt;span class="c"&gt;# stx_address: STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6&lt;/span&gt;
&lt;span class="c"&gt;# btc_address: mjSrB3wS4xab3kYqFktwBzfTdPg367ZJ2d&lt;/span&gt;

&lt;span class="nn"&gt;[devnet]&lt;/span&gt;
&lt;span class="py"&gt;disable_bitcoin_explorer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="c"&gt;# disable_stacks_explorer = true&lt;/span&gt;
&lt;span class="c"&gt;# disable_stacks_api = true&lt;/span&gt;
&lt;span class="c"&gt;# working_dir = "tmp/devnet"&lt;/span&gt;
&lt;span class="c"&gt;# stacks_node_events_observers = ["host.docker.internal:8002"]&lt;/span&gt;
&lt;span class="c"&gt;# miner_mnemonic = "twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw"&lt;/span&gt;
&lt;span class="c"&gt;# miner_derivation_path = "m/44'/5757'/0'/0/0"&lt;/span&gt;
&lt;span class="c"&gt;# orchestrator_port = 20445&lt;/span&gt;
&lt;span class="c"&gt;# bitcoin_node_p2p_port = 18444&lt;/span&gt;
&lt;span class="c"&gt;# bitcoin_node_rpc_port = 18443&lt;/span&gt;
&lt;span class="c"&gt;# bitcoin_node_username = "devnet"&lt;/span&gt;
&lt;span class="c"&gt;# bitcoin_node_password = "devnet"&lt;/span&gt;
&lt;span class="c"&gt;# bitcoin_controller_port = 18442&lt;/span&gt;
&lt;span class="c"&gt;# bitcoin_controller_block_time = 30_000&lt;/span&gt;
&lt;span class="c"&gt;# stacks_node_rpc_port = 20443&lt;/span&gt;
&lt;span class="c"&gt;# stacks_node_p2p_port = 20444&lt;/span&gt;
&lt;span class="c"&gt;# stacks_api_port = 3999&lt;/span&gt;
&lt;span class="c"&gt;# stacks_api_events_port = 3700&lt;/span&gt;
&lt;span class="c"&gt;# bitcoin_explorer_port = 8001&lt;/span&gt;
&lt;span class="c"&gt;# stacks_explorer_port = 8000&lt;/span&gt;
&lt;span class="c"&gt;# postgres_port = 5432&lt;/span&gt;
&lt;span class="c"&gt;# postgres_username = "postgres"&lt;/span&gt;
&lt;span class="c"&gt;# postgres_password = "postgres"&lt;/span&gt;
&lt;span class="c"&gt;# postgres_database = "postgres"&lt;/span&gt;
&lt;span class="c"&gt;# bitcoin_node_image_url = "quay.io/hirosystems/bitcoind:devnet"&lt;/span&gt;
&lt;span class="c"&gt;# stacks_node_image_url = "localhost:5000/stacks-node:devnet"&lt;/span&gt;
&lt;span class="c"&gt;# stacks_api_image_url = "blockstack/stacks-blockchain-api:latest"&lt;/span&gt;
&lt;span class="c"&gt;# stacks_explorer_image_url = "blockstack/explorer:latest"&lt;/span&gt;
&lt;span class="c"&gt;# bitcoin_explorer_image_url = "quay.io/hirosystems/bitcoin-explorer:devnet"&lt;/span&gt;
&lt;span class="c"&gt;# postgres_image_url = "postgres:alpine"&lt;/span&gt;

&lt;span class="c"&gt;# Send some stacking orders&lt;/span&gt;
&lt;span class="nn"&gt;[[devnet.pox_stacking_orders]]&lt;/span&gt;
&lt;span class="py"&gt;start_at_cycle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="py"&gt;duration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;
&lt;span class="py"&gt;wallet&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"wallet_1"&lt;/span&gt;
&lt;span class="py"&gt;slots&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="py"&gt;btc_address&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"mr1iPkD9N3RJZZxXRk7xF9d36gffa6exNC"&lt;/span&gt;

&lt;span class="nn"&gt;[[devnet.pox_stacking_orders]]&lt;/span&gt;
&lt;span class="py"&gt;start_at_cycle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="py"&gt;duration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;
&lt;span class="py"&gt;wallet&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"wallet_2"&lt;/span&gt;
&lt;span class="py"&gt;slots&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="py"&gt;btc_address&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"muYdXKmX9bByAueDe6KFfHd5Ff1gdN9ErG"&lt;/span&gt;

&lt;span class="nn"&gt;[[devnet.pox_stacking_orders]]&lt;/span&gt;
&lt;span class="py"&gt;start_at_cycle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="py"&gt;duration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;
&lt;span class="py"&gt;wallet&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"wallet_3"&lt;/span&gt;
&lt;span class="py"&gt;slots&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="py"&gt;btc_address&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"mvZtbibDAAA3WLpY7zXXFqRa3T4XSknBX7"&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;There's a lot going on here, but it's actually pretty simple. All we are doing is declaring the name of the network, setting the amount of STX we want to pay to deploy a contract on it, and then instantiating a bunch of different principals (Stacks addresses) with some test STX.&lt;/p&gt;

&lt;p&gt;The first one is the deployer address and the rest are just other accounts we can use to test our contracts.&lt;/p&gt;

&lt;p&gt;At the bottom we are setting up a bunch of stuff that will determine how our local chain will actually run.&lt;/p&gt;

&lt;p&gt;Most of these are ports and postgres configurations that you'll never need to touch, but if you ever do, now you know where they are.&lt;/p&gt;

&lt;p&gt;We also have a config item at the very bottom that is setting up one of our wallets to be a stacker, which will automatically set our chain up with a PoX workflow with accounts 1, 2, and 3 stacking their STX tokens and earning BTC, all happening on our local Clarinet chain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Smart Contract
&lt;/h2&gt;

&lt;p&gt;Let's create our Cargo smart contract with &lt;code&gt;clarinet contract new cargo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This will create both the smart contract Clarity contract itself in the &lt;code&gt;contracts&lt;/code&gt; folder as well as the test file in the &lt;code&gt;tests&lt;/code&gt; folder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing Tests
&lt;/h2&gt;

&lt;p&gt;The first thing we are going to do is write a failing test describing what we want our contract to do.&lt;/p&gt;

&lt;p&gt;The generated test file took care of all the boilerplate setup for us, so all we need to do is write our actual tests.&lt;/p&gt;

&lt;p&gt;Here's what you should have in that &lt;code&gt;cargo_test.ts&lt;/code&gt; file right now:&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;Clarinet&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;Chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://deno.land/x/clarinet@v0.14.0/index.ts&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;assertEquals&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://deno.land/std@0.90.0/testing/asserts.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Clarinet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&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;Ensure that &amp;lt;...&amp;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;async&lt;/span&gt; &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;&amp;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;let&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mineBlock&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="cm"&gt;/* 
             * Add transactions with: 
             * Tx.contractCall(...)
            */&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;receipts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&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="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mineBlock&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="cm"&gt;/* 
             * Add transactions with: 
             * Tx.contractCall(...)
            */&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;receipts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&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="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 starter test file is already doing quite a bit for us. Up at the top we are importing the Clarinet Deno testing library.&lt;/p&gt;

&lt;p&gt;I recommend going through &lt;a href="https://deno.land/x/clarinet@v0.14.0/index.ts" rel="noopener noreferrer"&gt;that actual file&lt;/a&gt; to get a handle on the different things this testing library allows us to do.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Clarinet&lt;/code&gt; class is our actual test runner, and we are calling &lt;code&gt;test&lt;/code&gt; to initiate the test process.&lt;/p&gt;

&lt;p&gt;In there we pass in our test name and function. We'll create a new one of these for each test we run. In this function we are passing &lt;code&gt;chain&lt;/code&gt; and &lt;code&gt;accounts&lt;/code&gt; which will handle setting up a mocknet Stacks chain and our set of mock accounts for testing purposes. This corresponds to the same list of accounts from that &lt;code&gt;Devnet.toml&lt;/code&gt; file we saw earlier.&lt;/p&gt;

&lt;p&gt;Then within the function we are mining two blocks and checking for the correct block height after mining. We can add transactions within individual blocks where we see the &lt;code&gt;TX.contractCall(..)&lt;/code&gt; comment.&lt;/p&gt;

&lt;p&gt;But what are the &lt;code&gt;block.receipts&lt;/code&gt;? Whenever we mine a block on the Stacks chain, a receipt is generated for each transaction that was processed in that block that gives us information about the transaction.&lt;/p&gt;

&lt;p&gt;Since we aren't processing any transactions in these blocks yet, we have no receipts.&lt;/p&gt;

&lt;p&gt;If we run &lt;code&gt;clarinet test&lt;/code&gt; right now everything should pass, since we aren't checking for much other than our mocknet for our test suite running and mining successfully.&lt;/p&gt;

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

&lt;p&gt;Before we get started writing our tests, let's think about what we need our smart contract to do and outline a couple of test cases.&lt;/p&gt;

&lt;p&gt;For this simple application, we're really only going to have one main piece of functionality, and that will be updating a package's shipping status.&lt;/p&gt;

&lt;p&gt;But even this one use case brings up a couple of test cases. We'll likely want to make sure only certain addresses can update shipping status.&lt;/p&gt;

&lt;p&gt;Maybe we can keep a simple map of each shipment where we store the shipper as a &lt;code&gt;principal&lt;/code&gt; type along with all the other shipment data in a tuple.&lt;/p&gt;

&lt;p&gt;There is actually a more efficient way to do this, but we'll implement it this way in this tutorial and explore a possible refactor at the end.&lt;/p&gt;

&lt;p&gt;So here are the test cases we might need for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A user should be able to successfully create a new shipment&lt;/li&gt;
&lt;li&gt;The shipper should be able to successfully update their shipment status&lt;/li&gt;
&lt;li&gt;A user should not be able to update another shipper's shipment status&lt;/li&gt;
&lt;li&gt;A user should be able to read the current status of a shipment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I like to phrase my test cases in human-readable form, in a user story-ish format, describing what the functionality is actually doing, rather than defining the specific technical implementation in the test case name.&lt;/p&gt;

&lt;p&gt;I find that this way, it's easier to wrap our heads around what the contract should be doing, then we can change the technical implementation as needed without needing to change the test case itself.&lt;/p&gt;

&lt;p&gt;Remember that the blockchain is public by default, so all of the shipping statuses of all packages will be publicly viewable, hence the last test case is generic and applies to all users.&lt;/p&gt;

&lt;p&gt;If we wanted to make this data private, we would need to change up our approach a bit, something we'll explore further down below when we look at optimizing costs.&lt;/p&gt;

&lt;p&gt;We aren't going to be storing a history of all our shipment updates directly within our map in our smart contract. Why not?&lt;/p&gt;

&lt;p&gt;Again, this is something that requires a shift in thinking from traditional web2 apps. The blockchain itself is, by design, a historical record of all transactions. So we don't need to store this history in our contract directly, Stacks does it for us.&lt;/p&gt;

&lt;p&gt;Clarity has a built-in &lt;code&gt;at-block&lt;/code&gt; function that changes the context of whatever expression is passed to it to that particular block.&lt;/p&gt;

&lt;p&gt;So we can pull our shipment status map data from any previous block by passing in the block number and pulling the relevant map data.&lt;/p&gt;

&lt;p&gt;We won't be implementing this particular piece of functionality in this tutorial, but here's what it could look like if you want to explore it on your own.&lt;/p&gt;

&lt;p&gt;We could store the block height of when the shipment was created and when it arrived and use that to create a range of time when the shipment was in transit.&lt;/p&gt;

&lt;p&gt;In our UI, we could take these block heights and extrapolate out time estimates from those and allow the user to look up what the status was at a certain point in time.&lt;/p&gt;

&lt;p&gt;Alright let's get to writing our tests.&lt;/p&gt;

&lt;p&gt;First up:&lt;/p&gt;

&lt;h3&gt;
  
  
  A user should be able to successfully create a new shipment
&lt;/h3&gt;

&lt;p&gt;Here's the test for this particular user story:&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="nx"&gt;Clarinet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&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;A user should be able to successfully create a new shipment&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="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shipper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wallet_1&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="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;receiver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wallet_2&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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mineBlock&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="c1"&gt;// Call the create-new-shipment function, passing in the starting location as the only parameter&lt;/span&gt;
            &lt;span class="nx"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contractCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cargo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create-new-shipment&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;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ascii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Denver&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
                &lt;span class="nx"&gt;shipper&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;types&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="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;receipts&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;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// Check for the success message&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;expectOk&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;expectAscii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Shipment created successfully&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;First we create the test and give it a name. I like to name them based on the user stories created above.&lt;/p&gt;

&lt;p&gt;Then we are creating the actual test function itself and passing in the chain and accounts. These are generated by Clarinet and allow us to actually interact with our testing mocknet.&lt;/p&gt;

&lt;p&gt;Inside the function we initiate mining a block with the &lt;code&gt;chain.mineBlock&lt;/code&gt; function, and inside that is where we call our contract, thus initiating a transaction, with &lt;code&gt;Tx.contractCall&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We need to pass some parameters to tell the &lt;code&gt;contractCall&lt;/code&gt; function what to actually call.&lt;/p&gt;

&lt;p&gt;First we pass the name of our contract, &lt;code&gt;cargo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then the name of the function we want to call within that contract, &lt;code&gt;create-new-shipment&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then we pass in any parameters the function needs. In this case, we need to pass in a starting location to the function and a receiver address, which has been defined above the block creation.&lt;/p&gt;

&lt;p&gt;Finally we pass in the principal of the transaction sender, again defined up above. In our case we are using the second generated wallet address.&lt;/p&gt;

&lt;p&gt;You can see the structure of the &lt;code&gt;accounts&lt;/code&gt; map by adding a simple &lt;code&gt;console.log(accounts)&lt;/code&gt; statement if you are curious how those are structured.&lt;/p&gt;

&lt;p&gt;Note the &lt;code&gt;types.ascii&lt;/code&gt; and &lt;code&gt;types.principal&lt;/code&gt; functions we are passing our arguments to. That needs to be the same type that our Clarity function accepts in our contract.&lt;/p&gt;

&lt;p&gt;Now if we run &lt;code&gt;clarinet test&lt;/code&gt; this will of course fail because we don't even have that function to call.&lt;/p&gt;

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

&lt;p&gt;In this case it is failing because we have no transaction receipt, because our transaction isn't actually doing anything yet.&lt;/p&gt;

&lt;p&gt;Let's jump over to our contract and write this function.&lt;/p&gt;

&lt;p&gt;One thing to remember when doing TDD is that we only want to add functionality incrementally as we create tests.&lt;/p&gt;

&lt;p&gt;So right now we are only adding enough to this contract to get this test to pass. We'll add additional functionality like auth checking as we write more failing tests.&lt;/p&gt;

&lt;p&gt;Let's define our first public function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;;; cargo
;; a simple decentralized shipment tracker

;; constants

;; data maps and vars
(define-data-var last-shipment-id uint u0)
(define-map shipments uint {location: (string-ascii 25), status: (string-ascii 25), shipper: principal, receiver: principal})

;; private functions
;;

;; public functions
(define-public (create-new-shipment (starting-location (string-ascii 25)) (receiver principal))
    (let
        (
            (new-shipment-id (+ (var-get last-shipment-id) u1))
        )
        ;; #[filter(starting-location, receiver)]
        (map-set shipments new-shipment-id {location: starting-location, status: "In Transit", shipper: tx-sender, receiver: receiver})
        (ok "Shipment created successfully")
    )
)

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

&lt;/div&gt;



&lt;p&gt;The first thing we are doing here is defining a &lt;code&gt;data-var&lt;/code&gt; and a &lt;code&gt;map&lt;/code&gt; in order to keep track of our shipment ids and our shipment data.&lt;/p&gt;

&lt;p&gt;Then we are creating the actual function that will handle creating this new shipment. You can see that the parameters that we are accepting here match up with the parameters we passed in our test.&lt;/p&gt;

&lt;p&gt;We are first setting the value of our new id, and then adding this particular item to our map. After we run the &lt;code&gt;map-set&lt;/code&gt; then we return an &lt;code&gt;ok&lt;/code&gt; response with the expected test.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;clarinet test&lt;/code&gt; again and our test should pass.&lt;/p&gt;

&lt;p&gt;What's this &lt;code&gt;;; #[filter(starting-location, receiver)]&lt;/code&gt; line?&lt;/p&gt;

&lt;p&gt;This is another feature of Clarinet called the check-checker that warns us about any untrusted input in our contract.&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://github.com/hirosystems/clarinet#check-checker" rel="noopener noreferrer"&gt;read more about it here&lt;/a&gt; but in our case we want the user to be able to pass in whatever they want for the &lt;code&gt;starting-location&lt;/code&gt; and &lt;code&gt;receiver&lt;/code&gt; fields, so we are telling the check checker to filter out these particular variables when checking for untrusted input.&lt;/p&gt;

&lt;h3&gt;
  
  
  Syntax Checking
&lt;/h3&gt;

&lt;p&gt;One of the other very helpful features of Clarinet that you may have noticed is syntax checking.&lt;/p&gt;

&lt;p&gt;Throughout the process of developing our smart contract, Clarinet will help us to make sure we are formatting things correctly and have the right syntax.&lt;/p&gt;

&lt;p&gt;This can help greatly in our workflow and make it so we can write better contracts faster.&lt;/p&gt;

&lt;p&gt;There are two ways to check the syntax. You can run &lt;code&gt;clarinet check&lt;/code&gt; in the main Clarinet folder.&lt;/p&gt;

&lt;p&gt;Or if you use VS Code, you can use the &lt;a href="https://marketplace.visualstudio.com/items?itemName=hirosystems.clarity-lsp" rel="noopener noreferrer"&gt;Clarity extension&lt;/a&gt; to automatically run syntax checks when you save your files.&lt;/p&gt;

&lt;p&gt;Now, let's get back to building out our tests. We have the first one passing, and have confirmed that a user can successfully create a new shipment.&lt;/p&gt;

&lt;p&gt;Let's add our next test case.&lt;/p&gt;

&lt;h3&gt;
  
  
  The shipper should be able to successfully update their shipment status
&lt;/h3&gt;

&lt;p&gt;Here's what test for this particular functionality would look like:&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="nx"&gt;Clarinet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&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;A user should be able to update their shipment&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="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shipper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wallet_1&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="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;let&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mineBlock&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="c1"&gt;// Call the update-shipment function, passing in the shipment id and current location&lt;/span&gt;
            &lt;span class="nx"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contractCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cargo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;update-shipment&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;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uint&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="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ascii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Phoenix&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
                &lt;span class="nx"&gt;shipper&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;receipts&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;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// Check for the success message&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;expectOk&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;expectAscii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Shipment updated successfully&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 very similar to the first test, except we are calling an update function and passing in a couple of different parameters to find the correct shipment and to update the location.&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;clarinet test&lt;/code&gt; results in a failing test, so let's write that new function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(define-public (update-shipment (shipment-id uint) (current-location (string-ascii 25)))
    (let
        (
            (previous-shipment (unwrap! (map-get? shipments shipment-id) err-shipment-not-found))
            (new-shipment-info (merge previous-shipment {location: current-location}))
        )
        ;; #[filter(shipment-id)]
        (map-set shipments shipment-id new-shipment-info)
        (ok "Shipment updated successfully")
    )
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are also adding a constant for our error message up top:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;;; constants
(define-constant err-shipment-not-found (err u100))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are first getting the existing shipment, and returning an error if it doesn't exist. We don't want to add a new shipment here.&lt;/p&gt;

&lt;p&gt;Then we are creating a new tuple of the shipment info by merging the existing info with the new location.&lt;/p&gt;

&lt;p&gt;Tuples are immutable once created, so we need to create a new tuple but with only the relevant information updated.&lt;/p&gt;

&lt;p&gt;Then we are taking that information and using it to update the shipments map using the corresponding shipment id that was passed into the function and returning a success message.&lt;/p&gt;

&lt;p&gt;If we run this now, it will fail with our &lt;code&gt;shipment-not-found-error&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's because in our test case, we aren't creating a new shipment before attempting to update it. So we need to add in some code to create a new shipment.&lt;/p&gt;

&lt;p&gt;Let's update this test to first create a new shipment in the first block, then update it in the second 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="nx"&gt;Clarinet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&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;A user should be able to update their shipment&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="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shipper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wallet_1&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="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;receiver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wallet_2&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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mineBlock&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="c1"&gt;// Call the create-new-shipment function, passing in the starting location as the only parameter&lt;/span&gt;
            &lt;span class="nx"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contractCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cargo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create-new-shipment&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;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ascii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Denver&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
                &lt;span class="nx"&gt;shipper&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;receipts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&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="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mineBlock&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="c1"&gt;// Call the update-shipment function, passing in the shipment id and current location&lt;/span&gt;
            &lt;span class="nx"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contractCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cargo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;update-shipment&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;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uint&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="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ascii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Phoenix&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
                &lt;span class="nx"&gt;shipper&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;receipts&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;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// Check for the success message&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;expectOk&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;expectAscii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Shipment updated successfully&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;Now if we run &lt;code&gt;clarinet test&lt;/code&gt; again, our test passes.&lt;/p&gt;

&lt;p&gt;This has however brought up an additional use case we are not currently testing for. You'll notice this workflow as you practice TDD.&lt;/p&gt;

&lt;p&gt;You'll do your best to create the best test cases at the beginning, but they will evolve as you build out your project.&lt;/p&gt;

&lt;p&gt;We should a test to check and make sure that a user cannot update a shipment that doesn't exist. Because of the way map-set works, this would create a new shipment. We don't want that.&lt;/p&gt;

&lt;p&gt;Our code actually does this already, but we should add in a test case to make sure that functionality doesn't break as we refactor.&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="nx"&gt;Clarinet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&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;A user should not be able to update a shipment that does not exist&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="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shipper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wallet_1&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="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;receiver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wallet_2&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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mineBlock&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="c1"&gt;// Call the create-new-shipment function, passing in the starting location as the only parameter&lt;/span&gt;
            &lt;span class="nx"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contractCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cargo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create-new-shipment&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;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ascii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Denver&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
                &lt;span class="nx"&gt;shipper&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;receipts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&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="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mineBlock&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="c1"&gt;// Call the update-shipment function, passing in the shipment id and current location&lt;/span&gt;
            &lt;span class="nx"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contractCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cargo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;update-shipment&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;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uint&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="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ascii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Phoenix&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
                &lt;span class="nx"&gt;shipper&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;receipts&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;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// Check for the correct message defined in our constants&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;expectErr&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;expectUint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&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 very similar to the previous test case except we are passing in the id of a shipment that does not exist and checking that our function returns the correct error response.&lt;/p&gt;

&lt;p&gt;This test will pass, since we built that functionality into our contract, but let's make sure it works by creating a failing test case.&lt;/p&gt;

&lt;p&gt;Change the id of &lt;code&gt;5&lt;/code&gt; to a &lt;code&gt;1&lt;/code&gt; and the test should fail because the contract call succeeds.&lt;/p&gt;

&lt;p&gt;Be sure to change it back before moving on to the next test case.&lt;/p&gt;

&lt;h3&gt;
  
  
  A user should not be able to update another shipper's shipment status
&lt;/h3&gt;

&lt;p&gt;As it stands now, anybody can update any shipment, regardless of whether or not they are the shipper.&lt;/p&gt;

&lt;p&gt;We don't want that. Only the shipper should be able to update the status. In a real-world application, we may want to have a collection of allowed addresses that can update the shipment, rather than only the shipper being able to update it.&lt;/p&gt;

&lt;p&gt;We could do that by passing in a list of allowed addresses when we first create the shipment, and using the &lt;a href="https://docs.stacks.co/write-smart-contracts/language-functions#index-of" rel="noopener noreferrer"&gt;index-of&lt;/a&gt; function to see if the &lt;code&gt;tx-sender&lt;/code&gt; is in that list.&lt;/p&gt;

&lt;p&gt;I leave that as an exercise for the reader. For now, we will compare to a single principal, the &lt;code&gt;shipper&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's the next test case:&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="nx"&gt;Clarinet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&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;A user should not be able to update another shipper's shipment status&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="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shipper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wallet_1&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="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;receiver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wallet_2&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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stranger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wallet_3&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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mineBlock&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="c1"&gt;// Call the create-new-shipment function, passing in the starting location as the only parameter&lt;/span&gt;
            &lt;span class="nx"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contractCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cargo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create-new-shipment&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;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ascii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Denver&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
                &lt;span class="nx"&gt;shipper&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;receipts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&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="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mineBlock&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="c1"&gt;// Call the update-shipment function, passing in the shipment id and current location&lt;/span&gt;
            &lt;span class="c1"&gt;// This should fail since it is being called by a stranger and not the shipper&lt;/span&gt;
            &lt;span class="nx"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contractCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cargo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;update-shipment&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;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uint&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="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ascii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Phoenix&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
                &lt;span class="nx"&gt;stranger&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;receipts&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;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// Check for the correct error message defined in our constants&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;expectErr&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;expectUint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;101&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;Again, very similar to a previous test except we are instead passing in the &lt;code&gt;stranger&lt;/code&gt; as the &lt;code&gt;tx-sender&lt;/code&gt;, which corresponds to a different address on the chain.&lt;/p&gt;

&lt;p&gt;And we are checking for an error of &lt;code&gt;u101&lt;/code&gt; when the transaction attempts to execute.&lt;/p&gt;

&lt;p&gt;Our test should fail now because we are successfully updating the status, rather than erroring out.&lt;/p&gt;

&lt;p&gt;Let's refactor our contract a bit to get this test to pass.&lt;/p&gt;

&lt;p&gt;The two main things we need to add are a new error constant and an &lt;code&gt;asserts!&lt;/code&gt; statement checking to see if the &lt;code&gt;tx-sender&lt;/code&gt; is equal to the &lt;code&gt;shipper&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's what our full contract looks like after making those changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
;; cargo
;; a simple decentralized shipment tracker

;; constants
(define-constant err-shipment-not-found (err u100))
(define-constant err-tx-sender-unauthorized (err u101))

;; data maps and vars
(define-data-var last-shipment-id uint u0)
(define-map shipments uint {location: (string-ascii 25), status: (string-ascii 25), shipper: principal, receiver: principal})

;; private functions
;;

;; public functions
(define-public (create-new-shipment (starting-location (string-ascii 25)) (receiver principal))
    (let
        (
            (new-shipment-id (+ (var-get last-shipment-id) u1))
        )
        ;; #[filter(starting-location, receiver)]
        (map-set shipments new-shipment-id {location: starting-location, status: "In Transit", shipper: tx-sender, receiver: receiver})
        (ok "Shipment created successfully")
    )
)

(define-public (update-shipment (shipment-id uint) (current-location (string-ascii 25)))
    (let
        (
            (previous-shipment (unwrap! (map-get? shipments shipment-id) err-shipment-not-found))
            (shipper (get shipper previous-shipment))
            (new-shipment-info (merge previous-shipment {location: current-location}))
        )
        (asserts! (is-eq tx-sender shipper) err-tx-sender-unauthorized)
        ;; #[filter(shipment-id)]
        (map-set shipments shipment-id new-shipment-info)
        (ok "Shipment updated successfully")
    )
)

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

&lt;/div&gt;



&lt;p&gt;We've added a new error constant along with a check to make sure the sender of this transaction is the shipper of the shipment being edited.&lt;/p&gt;

&lt;p&gt;Note the addition of the &lt;code&gt;shipper&lt;/code&gt; variable in the &lt;code&gt;let&lt;/code&gt; function where we get that information.&lt;/p&gt;

&lt;p&gt;Run this test again and it should pass. Let's add the last test case.&lt;/p&gt;

&lt;h3&gt;
  
  
  A user should be able to read the current status of a shipment
&lt;/h3&gt;

&lt;p&gt;This one is pretty straightforward. We simply want to make sure that we can easily read the shipment status of a shipment with a given id.&lt;/p&gt;

&lt;p&gt;We'll set up a new test to call a &lt;code&gt;read-only&lt;/code&gt; function and then get that function written.&lt;/p&gt;

&lt;p&gt;First, the 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="nx"&gt;Clarinet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&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;A user should be able to read the current status of a shipment&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="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shipper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wallet_1&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="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;receiver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wallet_2&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="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mineBlock&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="c1"&gt;// Call the create-new-shipment function, passing in the starting location as the only parameter&lt;/span&gt;
            &lt;span class="nx"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contractCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cargo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create-new-shipment&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;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ascii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Denver&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
                &lt;span class="nx"&gt;shipper&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="c1"&gt;// Get the shipment information with an ID of 1&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newShipment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callReadOnlyFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cargo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;get-shipment&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;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uint&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="nx"&gt;receiver&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// Now we want to check and see if this returns the shipment tuple we are expecting&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expectedShipment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newShipment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;
        &lt;span class="nx"&gt;expectedShipment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expectOk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expectedShipment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`(ok {location: "Denver", receiver: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, shipper: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;shipper&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, status: "In Transit"})`&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;All we are doing at the bottom is checking that we get an &lt;code&gt;ok&lt;/code&gt; response, and that it has the data we are expecting.&lt;/p&gt;

&lt;p&gt;Right now when we run this it will fail because that function does not exist.&lt;/p&gt;

&lt;p&gt;Let's create it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(define-read-only (get-shipment (shipment-id uint))
    (ok (unwrap! (map-get? shipments shipment-id) err-shipment-not-found))
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a simple &lt;code&gt;read-only&lt;/code&gt; function that will take in a shipment id and attempt to grab the entry in our shipments map with that id.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;unwrap!&lt;/code&gt; function will attempt to grab that value and return the not found error we created if it doesn't exist.&lt;/p&gt;

&lt;p&gt;Now when we run the test again it should pass.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Coverage
&lt;/h2&gt;

&lt;p&gt;One more thing we can do before moving on is check to see how much of our code is covered by tests.&lt;/p&gt;

&lt;p&gt;We can do this in just a few commands. Clarinet uses lcov to produce code coverage reports.&lt;/p&gt;

&lt;p&gt;If you don't have that installed yet, you can do so on Mac with &lt;code&gt;brew install lcov&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you have Windows, lcov is available as a &lt;a href="https://community.chocolatey.org/packages/lcov" rel="noopener noreferrer"&gt;Chocolatey package&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, from inside your Clarinet directory, run &lt;code&gt;clarinet test --coverage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once that finishes, you can generate the file with &lt;code&gt;genhtml coverage.lcov&lt;/code&gt; and open it with &lt;code&gt;open index.html&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;According to this report we have 100% code coverage. Nice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Refactoring
&lt;/h2&gt;

&lt;p&gt;The astute reader may notice a couple of problems with the way the tests have been written so far, and an error with the contract itself.&lt;/p&gt;

&lt;p&gt;Big thanks to &lt;a href="https://twitter.com/LNow_" rel="noopener noreferrer"&gt;lnow&lt;/a&gt; for pointing these issues out and helping work to write more robust tests.&lt;/p&gt;

&lt;p&gt;There's one critical error with the way I've written the tests here. Because they are only checking for return statuses, and not for data actually changing on-chain, we can only verify they work on a surface level.&lt;/p&gt;

&lt;p&gt;For example, this contract would actually cause all our tests to pass, which is obviously not what we want.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;define-public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;create-new-shipment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;starting-location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;string-ascii&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;receiver&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Shipment created successfully"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;define-public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;update-shipment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;shipment-id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;current-location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;string-ascii&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;begin&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;asserts!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;is-eq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shipment-id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u100&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;asserts!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;is-eq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tx-sender&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;'ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u101&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Shipment updated successfully"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;define-read-only&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-shipment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;shipment-id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Denver"&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;'ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG,&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="n"&gt;shipper&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;'ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"In Transit"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we need to make a couple of adjustments to our tests to check for on-chain data.&lt;/p&gt;

&lt;p&gt;We already have the piece we need to do this in our &lt;code&gt;get-shipment&lt;/code&gt; function. So we need to add this and check what it returns as part of our tests to make sure shipments have been updated and added correctly.&lt;/p&gt;

&lt;p&gt;That piece of code we use to check that we can successfully get a shipment from the chain? We need to add that at the bottom of our &lt;code&gt;create-shipment&lt;/code&gt; 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="c1"&gt;// Check that a shipment was created&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newShipment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callReadOnlyFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cargo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;get-shipment&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;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uint&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="nx"&gt;receiver&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// Now we want to check and see if this returns the shipment tuple we are expecting&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expectedShipment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newShipment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;
&lt;span class="nx"&gt;expectedShipment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expectOk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expectedShipment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`(ok {location: "Denver", receiver: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, shipper: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;shipper&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, status: "In Transit"})`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And our &lt;code&gt;update-shipment&lt;/code&gt; 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="c1"&gt;// Check that a shipment was updated&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newShipment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callReadOnlyFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cargo&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;get-shipment&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;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uint&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="nx"&gt;receiver&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Now we want to check and see if this returns the shipment tuple we are expecting&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expectedShipment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newShipment&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="nx"&gt;expectedShipment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expectOk&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;expectedShipment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;`(ok {location: "Phoenix", receiver: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, shipper: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;shipper&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, status: "In Transit"})`&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 have some better tests that are actually checking that the things we want to happen on-chain are happening.&lt;/p&gt;

&lt;p&gt;But we have another issue.&lt;/p&gt;

&lt;p&gt;Right now, we only have tests to check if we can create a single shipment successfully, which means our tests have no way of verifying whether or not our shipment ID incrementer works correctly (spoiler alert: we never added it 🙃).&lt;/p&gt;

&lt;p&gt;So let's first add a failing test to create multiple shipments.&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="nx"&gt;Clarinet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&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;Multiple users should be able to successfully create multiple shipments&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="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstShipper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wallet_1&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="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;firstReceiver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wallet_2&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="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;firstLocation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Denver&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mineBlock&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="c1"&gt;// Call the create-new-shipment function, passing in the starting location as the only parameter&lt;/span&gt;
      &lt;span class="nx"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contractCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cargo&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;create-new-shipment&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;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ascii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;firstLocation&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;firstReceiver&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
        &lt;span class="nx"&gt;firstShipper&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;receipts&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;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Check for the success message&lt;/span&gt;
    &lt;span class="nx"&gt;firstResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expectOk&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;expectAscii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Shipment created successfully&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 that a shipment was created&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstShipment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callReadOnlyFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cargo&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;get-shipment&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;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uint&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="nx"&gt;firstReceiver&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Now we want to check and see if this returns the shipment tuple we are expecting&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstExpectedShipment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firstShipment&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="nx"&gt;firstExpectedShipment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expectOk&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;firstExpectedShipment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;`(ok {location: "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;firstLocation&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;", receiver: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;firstReceiver&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, shipper: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;firstShipper&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, status: "In Transit"})`&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Now let's create another shipment and perform the same checks&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;secondShipper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wallet_3&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="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;secondReceiver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wallet_4&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="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;secondLocation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New York&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mineBlock&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="c1"&gt;// Call the create-new-shipment function, passing in the starting location as the only parameter&lt;/span&gt;
      &lt;span class="nx"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contractCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cargo&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;create-new-shipment&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;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ascii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;secondLocation&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;secondReceiver&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
        &lt;span class="nx"&gt;secondShipper&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;secondResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;receipts&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;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Check for the success message&lt;/span&gt;
    &lt;span class="nx"&gt;secondResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expectOk&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;expectAscii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Shipment created successfully&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 that a shipment was created&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;secondShipment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callReadOnlyFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cargo&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;get-shipment&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;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uint&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="nx"&gt;secondReceiver&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Now we want to check and see if this returns the shipment tuple we are expecting&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;secondExpectedShipment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;secondShipment&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="nx"&gt;secondExpectedShipment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expectOk&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;secondExpectedShipment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;`(ok {location: "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;secondLocation&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;", receiver: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;secondReceiver&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, shipper: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;secondShipper&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, status: "In Transit"})`&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we run &lt;code&gt;clarinet test&lt;/code&gt; again this will fail with an &lt;code&gt;err u100&lt;/code&gt; If we check our contract, that corresponds to the shipment not found error.&lt;/p&gt;

&lt;p&gt;Why is this happening?&lt;/p&gt;

&lt;p&gt;If you look in our &lt;code&gt;create-new-shipment&lt;/code&gt; function, we are getting the &lt;code&gt;last-shipment-id&lt;/code&gt; but we are never updating that value when we update our map, so it will always get set to 1.&lt;/p&gt;

&lt;p&gt;Let's fix that by modifying the function and then re-run our test.&lt;/p&gt;

&lt;p&gt;We only need to add one line to make this work, add this right above the &lt;code&gt;ok&lt;/code&gt; return.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;var-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last-shipment-id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new-shipment-id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And with that, our tests pass.&lt;/p&gt;

&lt;p&gt;Alright, we have all our main tests and functionality written. But the way we store data here could be improved. Let's look at how we might refactor this while using Clarinet's cost optimization functions. &lt;/p&gt;

&lt;h2&gt;
  
  
  Cost Optimization
&lt;/h2&gt;

&lt;p&gt;One thing to keep in mind when writing data to a blockchain via a smart contract is that we want to keep that amount of data to a minimum. Users pay for every byte of data.&lt;/p&gt;

&lt;p&gt;Clarinet has a cost analysis function built into the testing harness, but there are currently &lt;a href="https://github.com/hirosystems/clarinet/issues/133" rel="noopener noreferrer"&gt;some issues&lt;/a&gt; with the way it works.&lt;/p&gt;

&lt;p&gt;Until those get sorted out, we'll need to analyze the costs of our functions manually using the console.&lt;/p&gt;

&lt;p&gt;Another huge shoutout to &lt;a href="https://twitter.com/LNow_" rel="noopener noreferrer"&gt;lnow&lt;/a&gt; for pointing these out to me and helping me work through how to run manual cost analysis.&lt;/p&gt;

&lt;p&gt;I very highly recommend reading through that GitHub issue to understand what the problem is and the discrepancy between running &lt;code&gt;::get_costs&lt;/code&gt; and &lt;code&gt;clarinet test --costs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's run a quick cost analysis by opening up the console with &lt;code&gt;clarinet console&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We'll run a cost analysis on our &lt;code&gt;create-shipment&lt;/code&gt; function and pass in some data.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;::get_costs (contract-call? .cargo create-new-shipment "Denver" 'ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Remember your address will be different, I just used the first one generated when I entered the console.&lt;/p&gt;

&lt;p&gt;We'll get our success output and a rundown of what it cost, it should look something like this. This is telling us how many bytes were consumed by each type of action on the left, and the upper limit of what can be done on the right.&lt;/p&gt;

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

&lt;p&gt;The goal is to get the cost down as much as possible so we can have more transactions per block and cut down on write costs of writing data to the chain.&lt;/p&gt;

&lt;p&gt;Remember when I said above that writing all that data into a map was not the best way to handle this?&lt;/p&gt;

&lt;p&gt;This is why. We want to avoid writing that much data if possible.&lt;/p&gt;

&lt;p&gt;Pay particular attention to the &lt;code&gt;Write length (bytes)&lt;/code&gt; column. &lt;/p&gt;

&lt;p&gt;This is just a sample app, in a real-world shipment tracker we would likely need a lot more data to be stored in that map.&lt;/p&gt;

&lt;p&gt;A better option here would be to hash this data, store it in a traditional database, and use the on-chain hash of the data as the source of truth. That way we can compare the hash of the centralized data to the hash stored on-chain to maintain security and trustlessness without needing to store the data directly on-chain.&lt;/p&gt;

&lt;p&gt;Another benefit of this is that we can keep data private while still verifying it is accurate. If we wanted the data to be public we could implement some sort of publicly viewable dashboard that showed the hash of the current data and that it was the same as what is on chain.&lt;/p&gt;

&lt;p&gt;All of the UI code responsible for fetching the data and comparing the hash could be made open source so it is publicly viewable and verifiable. Users could determine for themselves if the data is to be trusted and act accordingly.&lt;/p&gt;

&lt;p&gt;Remember, transparency is not necessarily the problem we are trying to solve for when building smart contracts. Transparency is easily solved with open source code.&lt;/p&gt;

&lt;p&gt;We are trying to make something transparent &lt;em&gt;and&lt;/em&gt; immutable/incorruptible. But that comes with tradeoffs, like every transaction having a cost.&lt;/p&gt;

&lt;p&gt;We can create applications that are the best of both worlds by writing smart contracts that store a minimal amount of data while still keeping integrity.&lt;/p&gt;

&lt;p&gt;This also makes it significantly easier to update our data structure in the future. It's out of the scope of this tutorial, but you can read more about this approach in &lt;a href="https://book.clarity-lang.org/ch14-02-what-to-store-on-chain.html" rel="noopener noreferrer"&gt;the Clarity Book&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you've read my &lt;a href="https://dev.to/krgrs/built-on-bitcoin-an-introduction-to-full-stack-web3-development-with-stacks-me9"&gt;first tutorial on Stacks development&lt;/a&gt;, you know I'm a fan of going out and practicing things on your own.&lt;/p&gt;

&lt;p&gt;This is an excellent opportunity to do that. I have a few ideas for how you can flex your Stacks muscles in the "Practice on Your Own" section below, with some guidance.&lt;/p&gt;

&lt;p&gt;But first, let's get this deployed to testnet using Clarinet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying
&lt;/h2&gt;

&lt;p&gt;Clarinet makes deploying Clarity contracts very easy. &lt;/p&gt;

&lt;p&gt;In fact, we literally only need one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clarinet publish --testnet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But before this will work we need to edit the &lt;code&gt;Testnet.toml&lt;/code&gt; file in order to add our testnet address mnemonic so Clarinet knows what address to deploy with.&lt;/p&gt;

&lt;p&gt;You can find this in the Hiro wallet by switching to testnet, selecting the address you want to deploy with, hitting the menu with the three dots, and selecting 'View Secret Key'.&lt;/p&gt;

&lt;p&gt;Copy the memonic that shows there and paste it in the right spot in the &lt;code&gt;Testnet.toml&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[network]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"testnet"&lt;/span&gt;
&lt;span class="py"&gt;node_rpc_address&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://stacks-node-api.testnet.stacks.co"&lt;/span&gt;
&lt;span class="py"&gt;deployment_fee_rate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;

&lt;span class="nn"&gt;[accounts.deployer]&lt;/span&gt;
&lt;span class="py"&gt;mnemonic&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;YOUR PRIVATE TESTNET MNEMONIC HERE&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can go to the explorer and copy the tx id that was generated to view your deployed contract. You can &lt;a href="https://explorer.stacks.co/txid/0x5864dabc9122732e16fcebd5ddaa727db8614eaee59499967c18011c1ddbd5b8?chain=testnet" rel="noopener noreferrer"&gt;see mine here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practice On Your Own
&lt;/h2&gt;

&lt;p&gt;There are two major improvements we could make to our project as it stands right now, implementing hashing as discussed above to reduce contract costs and adding a UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementing the Hash Function
&lt;/h3&gt;

&lt;p&gt;Here are the steps you would need to take to make this happen. Implementing this on your own would be great practice.&lt;/p&gt;

&lt;p&gt;First, Modify the testing file to create the data structure in the form of an object and pass it to a function that will sha256 hash it, such as &lt;a href="https://www.npmjs.com/package/js-sha256" rel="noopener noreferrer"&gt;js-sha256&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You'll need to modify all of the test functions in order to correctly pass in this new data to the create and update functions.&lt;/p&gt;

&lt;p&gt;Next you'll need to remove the &lt;code&gt;get-shipment&lt;/code&gt; function and replace it with something that compares the data hash generated via JS with the one stored on chain.&lt;/p&gt;

&lt;p&gt;Finally, you'll need to modify the Clarity functions to instead take in the data hash as a parameter and get the tests to pass.&lt;/p&gt;

&lt;p&gt;In a real app, our tests would be mimicking us saving our data to an off-chain DB and then passing the hash of that saved data to our smart contract.&lt;/p&gt;

&lt;p&gt;For more information on what this might look like, check out the &lt;a href="https://book.clarity-lang.org/ch14-02-what-to-store-on-chain.html" rel="noopener noreferrer"&gt;Best Practices chapter of the Clarity Book&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a UI and DB
&lt;/h3&gt;

&lt;p&gt;We've got some smart contracts that are covered by tests now, but they aren't very useful if nobody can interact with them.&lt;/p&gt;

&lt;p&gt;You've got a fully functioning smart contract with Clarinet, let's try adding a frontend and database to it.&lt;/p&gt;

&lt;p&gt;This is something to try on your own to exercise your Stacks muscles and start learning how to build useful full-stack apps.&lt;/p&gt;

&lt;p&gt;The concept of storing hashes of data instead of the data itself is super important to familiarize yourself with. It's important to remember that decentralized web development is different than traditional web development. We need to think about things differently.&lt;/p&gt;

&lt;p&gt;Storing a hash of our data on the blockchain while storing the data itself in a traditional centralized database still allows us to maintain public, transparent, verifiable data integrity while keeping the benefits of centralized data storage, such as speed, easy upgradeability, and data privacy.&lt;/p&gt;

&lt;p&gt;If we needed to add other data field to our shipment info down the road, this would be a major task if all this data were stored on the blockchain, but it's trivial with traditional data storage.&lt;/p&gt;

&lt;p&gt;So, try this out for a project:&lt;/p&gt;

&lt;p&gt;Utilizing &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt;, &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind CSS&lt;/a&gt;, &lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt;, and &lt;a href="https://docs.micro-stacks.dev/" rel="noopener noreferrer"&gt;Micro-Stacks&lt;/a&gt;, create a frontend for the smart contracts we wrote here.&lt;/p&gt;

&lt;p&gt;This will likely be challenging, but will be an excellent exercise to practice the art of full-stack development with Stacks.&lt;/p&gt;

&lt;p&gt;Be sure to tag me in the &lt;a href="https://discord.gg/5DJaBrf" rel="noopener noreferrer"&gt;Stacks Discord&lt;/a&gt; if you need any help, kennny#0001.&lt;/p&gt;

&lt;p&gt;Good luck!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap Up and Next Steps
&lt;/h2&gt;

&lt;p&gt;In this tutorial we've taken a brief look at how you can use Clarinet to aid in your Stacks development.&lt;/p&gt;

&lt;p&gt;We've looked at testing, syntax checking, cost optimizations, and deployment. &lt;/p&gt;

&lt;p&gt;But as always, this information won't really sink in unless you go out and practice it on your own. I've given you a few ideas to get your gears turning, but feel free to experiment and see how all this works for yourself.&lt;/p&gt;

&lt;p&gt;I'm always available for help if you need anything on &lt;a href="https://discord.gg/5DJaBrf" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; and &lt;a href="https://twitter.com/KenTheRogers" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if you haven't yet, be sure to check out &lt;a href="https://start.stacks.org/" rel="noopener noreferrer"&gt;start.stacks.org&lt;/a&gt; for a complete roadmap to get started in Stacks development.&lt;/p&gt;

</description>
      <category>stacks</category>
      <category>web3</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Understanding Stacks Post Conditions</title>
      <dc:creator>kenny</dc:creator>
      <pubDate>Fri, 11 Mar 2022 05:24:00 +0000</pubDate>
      <link>https://forem.com/stacks/understanding-stacks-post-conditions-e65</link>
      <guid>https://forem.com/stacks/understanding-stacks-post-conditions-e65</guid>
      <description>&lt;h2&gt;
  
  
  What Are Post Conditions?
&lt;/h2&gt;

&lt;p&gt;Post conditions are one of my favorite features of Stacks. They are one of the many unique features of Stacks and Clarity that helps make it easier for developers to build safe applications and for users to be safer users of those applications.&lt;/p&gt;

&lt;p&gt;If you aren't familiar with Stacks or Clarity, you can check out my &lt;a href="https://dev.to/krgrs/built-on-bitcoin-an-introduction-to-full-stack-web3-development-with-stacks-me9"&gt;Intro to Stacks&lt;/a&gt; tutorial, where we walk through the basics of what Stacks is and how to build a full-stack app on it.&lt;/p&gt;

&lt;p&gt;Now, what exactly are post conditions?&lt;/p&gt;

&lt;p&gt;Put simply, post conditions are a set of conditions that must be met before a user's transaction will execute. The primary goal behind post conditions is to limit the amount of damage that can be done to a user's assets due to a bug, intentional or otherwise.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Post Conditions Work
&lt;/h2&gt;

&lt;p&gt;Post conditions allow the developer of an application to append a set of conditions that must be met. If these conditions are not met, the transaction will abort and the user will only be out the transaction fee.&lt;/p&gt;

&lt;p&gt;How might this look in practice?&lt;/p&gt;

&lt;p&gt;Say we are building an NFT marketplace and a user wants to purchase an NFT for 20 STX. As the developers of that application, we can embed post conditions stating that the purchaser's transaction should not transfer more than 20 STX and that they should own one NFT of that specific type.&lt;/p&gt;

&lt;p&gt;If contract execution would result in either of these two things not happening, the entire thing aborts and the purchaser loses nothing but the transaction fee.&lt;/p&gt;

&lt;p&gt;It's crucial to note that post conditions are not something that is defined in a Clarity smart contract. They are meant to be separate from the contract so that the user has some control over what happens when they initiate a transaction outside of the contract itself.&lt;/p&gt;

&lt;p&gt;So they are &lt;a href="https://github.com/stacksgov/sips/blob/main/sips/sip-005/sip-005-blocks-and-transactions.md#transaction-encoding" rel="noopener noreferrer"&gt;sent as part of the transaction&lt;/a&gt; when the user initiates it.&lt;/p&gt;

&lt;p&gt;The post conditions will be shown prior to a user initiating a transaction in their wallet.&lt;/p&gt;

&lt;p&gt;As web3 developers, it is our job to make sure we write code with good post conditions to safeguard our user's assets as much as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Types of Post Conditions
&lt;/h2&gt;

&lt;p&gt;We have three different types of post conditions to cover the three main types of assets on Stacks: NFTs, fungible tokens, and STX tokens.&lt;/p&gt;

&lt;p&gt;All of these post conditions correspond to the transaction sender's account and assets.&lt;/p&gt;

&lt;p&gt;Let's look at a few code examples pulled from the &lt;a href="https://github.com/hirosystems/stacks.js/tree/master/packages/transactions#post-conditions" rel="noopener noreferrer"&gt;Stacks.js docs&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  STX Post Condition
&lt;/h3&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;FungibleConditionCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;makeStandardSTXPostCondition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;makeContractSTXPostCondition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stacks/transactions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// With a standard principal&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postConditionAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SP2ZD731ANQZT6J4K3F5N8A40ZXWXC1XFXHVVQFKE&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;postConditionCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;FungibleConditionCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GreaterEqual&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;postConditionAmount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12345&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;standardSTXPostCondition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;makeStandardSTXPostCondition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;postConditionAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;postConditionCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;postConditionAmount&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// With a contract principal&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contractAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SPBMRFRPPGCDE3F384WCJPK8PQJGZ8K9QKK7F59X&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;contractName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-contract&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;contractSTXPostCondition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;makeContractSTXPostCondition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;contractName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;postConditionCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;postConditionAmount&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we've got the basic setup for a post condition for a STX transfer.&lt;/p&gt;

&lt;p&gt;After we import the necessary packages, we are setting up a condition that says that the user with the specified address will transfer an amount of STX that will be greater than or equal to the specified amount.&lt;/p&gt;

&lt;p&gt;So as the user, if we were to initiate this transaction with the Hiro Wallet, we would be presented with a condition that stated that we will be transferring at least 12,345 STX or the transaction will abort.&lt;/p&gt;

&lt;p&gt;The second section is doing something similar, but in this case it is being applied to the contract, so we're saying that the contract will be transferring at least the specified amount, rather than the user.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fungible Token Post Condition
&lt;/h3&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;FungibleConditionCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;createAssetInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;makeStandardFungiblePostCondition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stacks/transactions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// With a standard principal&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postConditionAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SP2ZD731ANQZT6J4K3F5N8A40ZXWXC1XFXHVVQFKE&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;postConditionCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;FungibleConditionCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GreaterEqual&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;postConditionAmount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12345&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;assetAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SP62M8MEFH32WGSB7XSF9WJZD7TQB48VQB5ANWSJ&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;assetContractName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-asset-contract&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;fungibleAssetInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createAssetInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assetAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;assetContractName&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;standardFungiblePostCondition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;makeStandardFungiblePostCondition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;postConditionAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;postConditionCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;postConditionAmount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;fungibleAssetInfo&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// With a contract principal&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contractAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SPBMRFRPPGCDE3F384WCJPK8PQJGZ8K9QKK7F59X&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;contractName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-contract&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;assetAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SP62M8MEFH32WGSB7XSF9WJZD7TQB48VQB5ANWSJ&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;assetContractName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-asset-contract&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;fungibleAssetInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createAssetInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assetAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;assetContractName&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;contractFungiblePostCondition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;makeContractFungiblePostCondition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;contractName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;postConditionCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;postConditionAmount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;fungibleAssetInfo&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The process here is similar. The main difference is that in addition to supplying the conditions for the transfer itself, since this corresponds to a custom SIP-010 token, we are also specifying the token info by referencing the contract name and address that defines the token.&lt;/p&gt;

&lt;h3&gt;
  
  
  NFT Post Condition
&lt;/h3&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;NonFungibleConditionCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;createAssetInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;makeStandardNonFungiblePostCondition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;makeContractNonFungiblePostCondition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;bufferCVFromString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stacks/transactions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// With a standard principal&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postConditionAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SP2ZD731ANQZT6J4K3F5N8A40ZXWXC1XFXHVVQFKE&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;postConditionCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NonFungibleConditionCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sends&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;assetAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SP62M8MEFH32WGSB7XSF9WJZD7TQB48VQB5ANWSJ&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;assetContractName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-asset-contract&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;assetName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-asset&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;tokenAssetName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;bufferCVFromString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-token-asset&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;nonFungibleAssetInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createAssetInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assetAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;assetContractName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;assetName&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;standardNonFungiblePostCondition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;makeStandardNonFungiblePostCondition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;postConditionAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;postConditionCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;nonFungibleAssetInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;tokenAssetName&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// With a contract principal&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contractAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SPBMRFRPPGCDE3F384WCJPK8PQJGZ8K9QKK7F59X&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;contractName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-contract&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;contractNonFungiblePostCondition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;makeContractNonFungiblePostCondition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;contractName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;postConditionCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;nonFungibleAssetInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;tokenAssetName&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one is a bit different. Rather than specifying the amount that the transfer should be compared to, we are setting the condition that after this transaction executes, the specified address should own the specified NFT.&lt;/p&gt;

&lt;p&gt;We could combine a couple of post conditions for this as well, and in fact this is what we are going to do in just a moment when we look at how to use post conditions in a sample app.&lt;/p&gt;

&lt;p&gt;Let's say we are purchasing an NFT for 50 STX. We can add two post conditions that require that after the transaction executes we will transfer no more than 50 STX from our principal and that our principal will own the specified NFT.&lt;/p&gt;

&lt;p&gt;Note that post conditions don't allow us to specify that we own a NFT with a particular identifier, only that we own one NFT of that particular name and contract.&lt;/p&gt;

&lt;p&gt;We can see the different comparator codes for each type in the &lt;a href="https://github.com/hirosystems/stacks.js/blob/48159007703933326f0e5a1ff6a2c061f2c753e6/packages/transactions/src/constants.ts#L113" rel="noopener noreferrer"&gt;@stacks/transactions source code&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample App
&lt;/h2&gt;

&lt;p&gt;Let's take everything we've learned about post conditions and use them to create a basic sample app using Stacks.js.&lt;/p&gt;

&lt;p&gt;As always, &lt;a href="https://twitter.com/KenTheRogers" rel="noopener noreferrer"&gt;reach out&lt;/a&gt; and let me know your feedback or if you notice any errors or potential improvements.&lt;/p&gt;

&lt;p&gt;Our sample app is a very simple app where we can buy and sell a custom SIP-009 token. This will allow us to look at how to implement the sample post condition scenario outlined above.&lt;/p&gt;

&lt;p&gt;Since we are focusing on the post conditions in this tutorial, I've created a &lt;a href="https://github.com/kenrogers/fabulous-frogs" rel="noopener noreferrer"&gt;sample repo&lt;/a&gt; with a completed frontend and contracts, the only thing missing is the set of post conditions.&lt;/p&gt;

&lt;p&gt;In that same repo, I also have a separate branch with the completed code so you can compare.&lt;/p&gt;

&lt;p&gt;First, download the starter code from GitHub and let's get it fired up.&lt;/p&gt;

&lt;p&gt;You'll need &lt;code&gt;npm&lt;/code&gt; installed on your system to follow along. I'm using Node 17. You can use &lt;a href="https://github.com/nvm-sh/nvm" rel="noopener noreferrer"&gt;nvm&lt;/a&gt; if you need to switch versions.&lt;/p&gt;

&lt;p&gt;Switch into the &lt;code&gt;frontend&lt;/code&gt; directory and run &lt;code&gt;npm install&lt;/code&gt; and then &lt;code&gt;npm run dev&lt;/code&gt;, then switch into the &lt;code&gt;backend&lt;/code&gt; directory and run &lt;code&gt;clarinet integrate&lt;/code&gt; to get everything up and running.&lt;/p&gt;

&lt;p&gt;If you open up the &lt;code&gt;fabulous-frogs.clar&lt;/code&gt; file you can see we have a simple contract setting up a SIP-009 NFT.&lt;/p&gt;

&lt;p&gt;Pay particular attention to the &lt;code&gt;mint&lt;/code&gt; function, as that is the function that we will be utilizing and to which we will be attaching post conditions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;define-public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recipient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;token-id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;var-get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last-token-id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;try!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;stx-transfer?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u50000000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tx-sender&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;as-contract&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tx-sender&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;try!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;nft-mint?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fabulous-frogs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;token-id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;var-set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last-token-id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;token-id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;token-id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a basic mint function that will first increment that &lt;code&gt;token-id&lt;/code&gt; variable. Then, using that value as the context for the rest of the expressions (this is what the &lt;a href="https://docs.stacks.co/references/language-functions#let" rel="noopener noreferrer"&gt;&lt;code&gt;let&lt;/code&gt; function&lt;/a&gt; does) it will execute the other expressions.&lt;/p&gt;

&lt;p&gt;In this case, we are first attempting to transfer 50 STX from the current user, &lt;code&gt;tx-sender&lt;/code&gt; to the contract, &lt;code&gt;(as-contract tx-sender)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If that succeeds, we then attempt to mint a new NFT using the newly calculated &lt;code&gt;token-id&lt;/code&gt;, set a new &lt;code&gt;last-token-id&lt;/code&gt; for the next round of minting, and return.&lt;/p&gt;

&lt;p&gt;Now let's shift our focus to the frontend code and see what we need to do.&lt;/p&gt;

&lt;p&gt;Here's what the initial &lt;code&gt;index.tsx&lt;/code&gt; file looks like:&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;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextPage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StacksMocknet&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stacks/network&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;AppConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;UserSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;showConnect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;openContractCall&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stacks/connect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;NonFungibleConditionCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;FungibleConditionCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;createAssetInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;makeStandardNonFungiblePostCondition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;makeStandardSTXPostCondition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;bufferCVFromString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;standardPrincipalCV&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stacks/transactions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;appConfig&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;AppConfig&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;publish_data&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;userSession&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;UserSession&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;appConfig&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;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&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;userData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUserData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loggedIn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoggedIn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Set up the network and API&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;network&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;StacksMocknet&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;authenticate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;showConnect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;appDetails&lt;/span&gt;&lt;span class="p"&gt;:&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="s1"&gt;Fabulous Frogs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://assets.website-files.com/618b0aafa4afde65f2fe38fe/618b0aafa4afde2ae1fe3a1f_icon-isotipo.svg&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;redirectTo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;onFinish&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reload&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="nx"&gt;userSession&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="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isSignInPending&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;userSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handlePendingSignIn&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;userData&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;setUserData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;userSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isUserSignedIn&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setLoggedIn&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;setUserData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadUserData&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mint&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;assetAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;functionArgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nf"&gt;standardPrincipalCV&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;userSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadUserData&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stxAddress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;testnet&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;assetAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;contractName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fabulous-frogs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;functionArgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;appDetails&lt;/span&gt;&lt;span class="p"&gt;:&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="s1"&gt;Fabulous Frogs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://assets.website-files.com/618b0aafa4afde65f2fe38fe/618b0aafa4afde2ae1fe3a1f_icon-isotipo.svg&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;onFinish&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;openContractCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex min-h-screen flex-col items-center justify-center py-2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Head&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Fabulous&lt;/span&gt; &lt;span class="nx"&gt;Frogs&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/title&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="nx"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;icon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/favicon.ico&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Head&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex w-full flex-1 flex-col items-center justify-center px-20 text-center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-6xl font-bold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Mint&lt;/span&gt; &lt;span class="nx"&gt;Your&lt;/span&gt; &lt;span class="nx"&gt;Fabulous&lt;/span&gt; &lt;span class="nx"&gt;Frog&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mt-4 w-full text-xl md:w-1/2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Fabulous&lt;/span&gt; &lt;span class="nx"&gt;Frogs&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;most&lt;/span&gt; &lt;span class="nx"&gt;fabulous&lt;/span&gt; &lt;span class="nx"&gt;amphibians&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="nx"&gt;side&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt;
          &lt;span class="nx"&gt;Mississippi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;You&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt; &lt;span class="nx"&gt;mint&lt;/span&gt; &lt;span class="nx"&gt;yours&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;only&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="nx"&gt;STX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mt-6 flex max-w-4xl flex-wrap items-center justify-around sm:w-full&lt;/span&gt;&lt;span class="dl"&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;loggedIn&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;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
              &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;mint&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
              &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rounded bg-indigo-500 p-4 text-2xl text-white hover:bg-indigo-700&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nx"&gt;Mint&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
              &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-white-500 mb-6 rounded border-2 border-black py-2 px-4 font-bold hover:bg-gray-300&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nx"&gt;Connect&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;Wallet&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;)}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;We have a basic auth system and a simple mint function. Right now there are no post conditions but everything else is working just fine.&lt;/p&gt;

&lt;p&gt;You'll need to modify the &lt;code&gt;assetAddress&lt;/code&gt; to the address of the NFT contract that Clarinet generates when you run &lt;code&gt;clarinet integrate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also, if you have not already, you need to hook your local Hiro Wallet account to one of the Devnet accounts to get some test STX and interact with the site.&lt;/p&gt;

&lt;p&gt;I show how to do this in my &lt;a href="https://dev.to/krgrs/built-on-bitcoin-an-introduction-to-full-stack-web3-development-with-stacks-me9"&gt;Stacks 101&lt;/a&gt; article under the heading titled "Adding STX to Your Local Account".&lt;/p&gt;

&lt;p&gt;If you try to mint an NFT using this, you'll notice that we have a default post condition of not transferring anything.&lt;/p&gt;

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

&lt;p&gt;So if we try to run this now, it will fail.&lt;/p&gt;

&lt;p&gt;We need to add two conditions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We need to ensure that we are being transferred an instance of the Fabulous Frog NFT&lt;/li&gt;
&lt;li&gt;We need to ensure that we are not transferring more than 50 STX&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's do that now. Remember, if you want to compare you can view the completed code in &lt;a href="https://github.com/kenrogers/fabulous-frogs/tree/completed" rel="noopener noreferrer"&gt;this branch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We can create and add both post conditions with the following code. Add this right below the line where we are declaring the &lt;code&gt;assetAddress&lt;/code&gt; variable.&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;postConditionAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nx"&gt;userSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadUserData&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stxAddress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;testnet&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nftPostConditionCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NonFungibleConditionCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sends&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assetContractName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fabulous-frogs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assetName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fabulous-frogs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokenAssetName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;bufferCVFromString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fabulous-frogs&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;nonFungibleAssetInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createAssetInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;assetAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;assetContractName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;assetName&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;stxConditionCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;FungibleConditionCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LessEqual&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;stxConditionAmount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// denoted in microstacks&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postConditions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;makeStandardNonFungiblePostCondition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;postConditionAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;nftPostConditionCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;nonFungibleAssetInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;tokenAssetName&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;makeStandardSTXPostCondition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;postConditionAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;stxConditionCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;stxConditionAmount&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;What we are doing here is first setting all the variables we will need in order to create the post conditions.&lt;/p&gt;

&lt;p&gt;After we declare the variables, we are creating the actual post conditions and putting them in an array. We use the &lt;code&gt;makeStandardNonFungiblePostCondition&lt;/code&gt; and &lt;code&gt;makeStandardSTXPostCondition&lt;/code&gt; from the &lt;code&gt;@stacks/transactions&lt;/code&gt; package to actually create this.&lt;/p&gt;

&lt;p&gt;Most of this is pretty self-explanatory, we are just defining the type of asset that should be transferred and referencing it's contract and name in the NFT case.&lt;/p&gt;

&lt;p&gt;All we are doing here is taking the identifying information from our NFT and putting into a format that the Stacks blockchain can understand.&lt;/p&gt;

&lt;p&gt;That involves passing the result of a function called &lt;code&gt;createAssetInfo&lt;/code&gt;, a function included in stacks.js into the post conditions. This takes the token name, contract name, and asset contract address and formats it to send with the transaction to the chain itself.&lt;/p&gt;

&lt;p&gt;If you are curious, you can see what each of these pieces of data correspond to on chain by &lt;a href="https://github.com/stacksgov/sips/blob/main/sips/sip-005/sip-005-blocks-and-transactions.md#transaction-post-conditions-1" rel="noopener noreferrer"&gt;reading the SIP&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Why do we need to convert the token name to a buffer by using the &lt;code&gt;bufferCVFromString&lt;/code&gt; function?&lt;/p&gt;

&lt;p&gt;From the document linked above, referring to one of items required to be passed into the post condition body for an NFT condition:&lt;/p&gt;

&lt;p&gt;"A variable-length asset name, which is the Clarity value that names the token instance, serialized according to the Clarity value serialization format."&lt;/p&gt;

&lt;p&gt;Everything we are doing here is to convert our data into a format that can be passed to the chain to evaluate the post conditions that must be met.&lt;/p&gt;

&lt;p&gt;I got the address here from the local Clarinet Devnet chain, so be sure to add yours by setting the &lt;code&gt;assetAddress&lt;/code&gt; variable if you haven't already.&lt;/p&gt;

&lt;p&gt;And in the case of the STX transfer, we are defining how much should be transferred (in microstacks) and the comparator.&lt;/p&gt;

&lt;p&gt;For fungible and STX token conditions, we have 5 possible operators:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Equal&lt;/li&gt;
&lt;li&gt;Greater&lt;/li&gt;
&lt;li&gt;GreaterEqual&lt;/li&gt;
&lt;li&gt;Less&lt;/li&gt;
&lt;li&gt;LessEqual&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And for the NFT conditions we only have two:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sends&lt;/li&gt;
&lt;li&gt;DoesNotSend&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These come from constants in the &lt;code&gt;@stacks/transactions&lt;/code&gt; package called &lt;code&gt;FungibleConditionCode&lt;/code&gt; and &lt;code&gt;NonFungibleConditionCode&lt;/code&gt; respectively.&lt;/p&gt;

&lt;p&gt;The last thing we need to do is actually pass these conditions into our function call by adding them to the &lt;code&gt;options&lt;/code&gt; object:&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;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;assetAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;contractName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fabulous-frogs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;functionArgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// Passing the post conditions here&lt;/span&gt;
    &lt;span class="nx"&gt;postConditions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;appDetails&lt;/span&gt;&lt;span class="p"&gt;:&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="s1"&gt;Fabulous Frogs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://assets.website-files.com/618b0aafa4afde65f2fe38fe/618b0aafa4afde2ae1fe3a1f_icon-isotipo.svg&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;onFinish&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&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="nx"&gt;data&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 now if we try to run this again, it should work as expected.&lt;/p&gt;

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

&lt;p&gt;These two simple examples show how we can construct post conditions for all sorts of scenarios so we can help to safeguard our apps against unexpected behavior.&lt;/p&gt;

&lt;p&gt;If you were to change the NFT condition code from &lt;code&gt;Sends&lt;/code&gt; to &lt;code&gt;DoesNotSend&lt;/code&gt;, and try to Mint again, you'll notice that it fails by aborting due to supplied post conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Post Conditions Are Useful
&lt;/h2&gt;

&lt;p&gt;One of the most common frustrations with web3 and DeFi applications is that it is easy for people to screw up irreversibly. Post conditions allow the developer of a UI or the user (if their wallet allows for it) to declare up front what they expect to happen in clear language.&lt;/p&gt;

&lt;p&gt;If that thing does not happen, they don't have to worry about losing their assets.&lt;/p&gt;

&lt;p&gt;This adds one extra layer of security for users of our application. As an example, let's say that we were very careless in writing our smart contract and we accidentally priced the NFT at 500 STX instead of 50 by adding an extra 0.&lt;/p&gt;

&lt;p&gt;If our UI says that it costs 50 STX, but the contract actually tries to transfer 500, we can add an extra layer of security and help safeguard against that error with our post conditions.&lt;/p&gt;

&lt;p&gt;Post conditions are one of the many unique security features that makes Stacks an ideal chain on which to build robust decentralized software.&lt;/p&gt;

&lt;p&gt;In my opinion, we are only beginning to see the benefits of post conditions, and as the UX for web3 apps gets better and better, I envision post conditions as being an essential security feature that will help both developers and users to be able to better protect their assets and not have to exclusively trust the developer of the smart contract.&lt;/p&gt;

&lt;p&gt;It adds an additional layer of security to help secure users' assets that, as far as I'm aware (correct me if I'm wrong here), does not exist in other chains.&lt;/p&gt;

&lt;p&gt;As always, please feel free to &lt;a href="https://twitter.com/KenTheRogers" rel="noopener noreferrer"&gt;reach out to me directly&lt;/a&gt; or hop in the &lt;a href="https://discord.gg/QH2T4QuEJE" rel="noopener noreferrer"&gt;Stacks Discord&lt;/a&gt; if you have any questions or feedback.&lt;/p&gt;

</description>
      <category>stacks</category>
      <category>bitcoin</category>
      <category>web3</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Stacks Resources</title>
      <dc:creator>kenny</dc:creator>
      <pubDate>Thu, 24 Feb 2022 17:38:58 +0000</pubDate>
      <link>https://forem.com/krgrs/web3con-resources-2nci</link>
      <guid>https://forem.com/krgrs/web3con-resources-2nci</guid>
      <description>&lt;p&gt;Hey there Stacks devs!&lt;/p&gt;

&lt;p&gt;In my journey as Dev Advocate for the Stacks Foundation, I constantly come across various resources for learning the basics and intricacies of Stacks.&lt;/p&gt;

&lt;p&gt;Stacks is relatively new and can be confusing and contentious for people new to the space. This page is designed to be an ever-growing list of resources both for learning about Stacks itself and for building on it.&lt;/p&gt;

&lt;p&gt;Eventually, once a single static blog post becomes infeasible to host all the resources on, I will convert this into a more user-friendly format, but this works for now.&lt;/p&gt;

&lt;p&gt;If you come across anything you think should be added to this list, please &lt;a href="https://twitter.com/KenTheRogers"&gt;reach out to me on Twitter&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Stacks Fundamentals
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.stacks.co/"&gt;Stacks Website&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.stacks.co/learn/learning-resources"&gt;How Stacks Works&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Proof of Transfer
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://hackernoon.com/wtf-is-proof-of-transfer-and-why-should-anyone-care-wd2330p9"&gt;WTF is Proof of Transfer&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.stacks.co/understand-stacks/proof-of-transfer"&gt;Understanding Proof of Transfer&lt;/a&gt;&lt;br&gt;
&lt;a href="https://stacks.org/stacks-blockchain"&gt;What Kind of Blockchain is Stacks?&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Security and Connection to Bitcoin
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://twitter.com/muneeb/status/1492246784592302087"&gt;Muneeb Ali Twitter Space&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Developing on Stacks
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/krgrs/built-on-bitcoin-an-introduction-to-full-stack-web3-development-with-stacks-me9"&gt;Introduction to Full-Stack Web3 Development with Stacks&lt;/a&gt;&lt;br&gt;
&lt;a href="https://stacks.org/clarity-universe"&gt;Clarity Universe&lt;/a&gt;&lt;br&gt;
&lt;a href="https://book.clarity-lang.org/"&gt;Clarity Book &lt;em&gt;in-progress&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Smart Contract Examples
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/friedger/clarity-catamaranswaps/blob/main/catamaran-btc/contracts/btc-stx-swap.clar"&gt;Catamaran Swaps&lt;/a&gt; - Utilizing Bitcoin state in Clarity smart contracts&lt;/p&gt;

&lt;h2&gt;
  
  
  Community
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://twitter.com/KenTheRogers"&gt;My Twitter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/stacks"&gt;Stacks Twitter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/stacksorg"&gt;Stacks Foundation Twitter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://discord.gg/bckcRKKdf9"&gt;Stacks Discord&lt;/a&gt;&lt;br&gt;
&lt;a href="https://stacks.org/"&gt;Stacks Foundation&lt;/a&gt;&lt;/p&gt;

</description>
      <category>stacks</category>
      <category>web3</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Built on Bitcoin: An Introduction to Full-Stack Web3 Development with Stacks</title>
      <dc:creator>kenny</dc:creator>
      <pubDate>Mon, 14 Feb 2022 22:13:00 +0000</pubDate>
      <link>https://forem.com/stacks/built-on-bitcoin-an-introduction-to-full-stack-web3-development-with-stacks-me9</link>
      <guid>https://forem.com/stacks/built-on-bitcoin-an-introduction-to-full-stack-web3-development-with-stacks-me9</guid>
      <description>&lt;p&gt;When most people think of web3 development, the chain that immediately comes to mind is Ethereum. But did you know that it is possible to build completely decentralized web3 dapps on top of Bitcoin as well?&lt;/p&gt;

&lt;p&gt;Enter Stacks, the &lt;a href="https://dev.toST3QFME3CANQFQNR86TYVKQYCFT7QX4PRXM1V9W6H"&gt;biggest web3 project on Bitcoin&lt;/a&gt;. Stacks is a blockchain that allows us to build fully decentralized apps on top of Bitcoin, without modifying Bitcoin itself.&lt;/p&gt;

&lt;p&gt;That's a simple statement, but there is a lot of amazing technology and a lot of interesting and sometimes controversial concepts packed into that simple sentence.&lt;/p&gt;

&lt;p&gt;If you are not familiar with Stacks yet, I highly recommend diving in and &lt;a href="https://www.stacks.co/learn/introduction" rel="noopener noreferrer"&gt;learning about the basics&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At a high level, Stacks allows us to build fully decentralized software that ultimately settles on Bitcoin utilizing a unique consensus mechanism called &lt;a href="https://assets.website-files.com/5fcf9ac604d37418aa70a5ab/60072dbb32d416d6b3806935_5f1596b12bcc0800f3dcadcd_pox.pdf" rel="noopener noreferrer"&gt;Proof of Transfer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Stacks is unique in that it is a Layer 1 chain with its own token that has its own smart contract language, and all Stacks transactions ultimately settle on Bitcoin.&lt;/p&gt;

&lt;p&gt;This allows us to build fully expressive smart contracts and dapps that are secured by Bitcoin, without modifying Bitcoin itself.&lt;/p&gt;

&lt;p&gt;If you are interested in a technical deep dive of how Stacks works and how it is different from other blockchain technologies, I highly recommend Jude Nelson's article, &lt;a href="https://stacks.org/stacks-blockchain" rel="noopener noreferrer"&gt;What Kind of Blockchain is Stacks?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This tutorial will serve as a practical introduction to actually building things on it using Clarity, Next, and Stacks.js.&lt;/p&gt;

&lt;p&gt;The more I learn about Stacks and get involved in the community, the more I find myself fascinated by the ecosystem and the technology.&lt;/p&gt;

&lt;p&gt;I wrote this tutorial for developers interested in getting started building dapps on Stacks.&lt;/p&gt;

&lt;p&gt;It's designed to be an introductory tutorial, taking you from 0 to a complete, although simple, Stacks dapp.&lt;/p&gt;

&lt;p&gt;If you are a seasoned JS developer and interested in building things on Stacks, you should be good. If you have experience writing smart contracts with another language like Solidity, even better.&lt;/p&gt;

&lt;p&gt;I wrote this guide as a way to help get new developers started building on Stacks as fast as possible.&lt;/p&gt;

&lt;p&gt;If anyone notices I have made a mistake or that something can be improved, please do &lt;a href="https://twitter.com/KenTheRogers" rel="noopener noreferrer"&gt;let me know&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;This tutorial is serving as an MVP of sorts for a more extensive full-stack Stacks dev guide I am working on so definitely reach out if you think something could be improved, added, removed, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Stacks?
&lt;/h2&gt;

&lt;p&gt;At a high level, it enables smart contracts on top of Bitcoin.&lt;/p&gt;

&lt;p&gt;One of the main differentiators between Ethereum and Bitcoin is that Ethereum was programmable and had the capability to create smart contracts.&lt;/p&gt;

&lt;p&gt;This is why the DeFi market exploded on the Ethereum blockchain. People could write code in Solidity and deploy that code as a smart contract to live forever on the blockchain.&lt;/p&gt;

&lt;p&gt;Stacks brings this capability to Bitcoin. Stacks is working on bringing full-expressive smart contracts to Bitcoin, without modifying Bitcoin itself. &lt;/p&gt;

&lt;p&gt;Along with related technologies like Lightning and &lt;a href="https://atomic.finance/blog/a-laypersons-guide-to-discreet-log-contracts-atomic-yield-series-part-3/" rel="noopener noreferrer"&gt;DLCs&lt;/a&gt;, Stacks rounds out the dream team that will bring DeFi and smart contracts to the world's most secure blockchain and the soundest money the world has ever seen, Bitcoin.&lt;/p&gt;

&lt;p&gt;This was one of the main advantages Ethereum had over Bitcoin, and now Bitcoin has that capability as well, without (and this is a key point) modifying Bitcoin itself.&lt;/p&gt;

&lt;p&gt;Imagine getting involved in the Ethereum ecosystem when it was first blossoming and the amazing opportunity that would have been. I'm convinced that getting involved and building on Stacks is an equivalent (if not greater) opportunity today.&lt;/p&gt;

&lt;p&gt;As a related benefit, because of Stacks' unique Proof of Transfer consensus mechanism, it is actually able to recycle Bitcoin's energy usage, so rather than adding to the environmental load, it extracts further benefit from the electricity Bitcoin already uses.&lt;/p&gt;

&lt;p&gt;Because of the nature of the recycling of energy, Stacks actually uses less electricity than even PoS chains. In the words of Jude Nelson, "Bitcoin isn't wasted energy, it's simply under-utilized."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stacks Developer Ecosystem
&lt;/h2&gt;

&lt;p&gt;We'll go over the process of building a complete (although basic) application using some of these throughout the tutorial.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clarity
&lt;/h3&gt;

&lt;p&gt;First, Clarity is the language that smart contracts are written in on Stacks. Think of this as the Stacks version of Solidity.&lt;/p&gt;

&lt;p&gt;It has a different feel than languages like Solidity and JavaScript, so it can feel a bit weird at first, but you'll find that it clicks as you use it more and the simplicity is wonderful.&lt;/p&gt;

&lt;p&gt;The cool thing about Clarity is that it has been intentionally designed to write safe smart contracts and make it difficult to write dangerous code and you can see what the code will do before running it.&lt;/p&gt;

&lt;p&gt;The Stacks blockchain itself also has something to aid with writing secure contracts, post-conditions. These are conditions that have to be true when the contract finishes running. If they are not true, the contract function aborts. This can help with things like safeguarding funds in transfers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clarinet
&lt;/h3&gt;

&lt;p&gt;Clarinet is a CLI that allows us to easily write, test, and deploy smart contracts.&lt;/p&gt;

&lt;p&gt;If you're from the Ethereum world, this is similar to things like Hardhat or Truffle.&lt;/p&gt;

&lt;p&gt;Clarinet is a part of our toolset that will allow us to build and test our contracts locally along with deploying them to a testnet and finally to mainnet.&lt;/p&gt;

&lt;p&gt;We'll be using Clarinet in this tutorial but will not be covering testing our code. Testing is a complex topic that deserves its own post. &lt;/p&gt;

&lt;p&gt;If you are interested in integrating testing into this project, &lt;a href="https://twitter.com/nikosbaxevanis" rel="noopener noreferrer"&gt;Nikos Baxevanis&lt;/a&gt; has written an excellent &lt;a href="https://blog.nikosbaxevanis.com/2022/03/05/clarity-property-based-testing-primer/" rel="noopener noreferrer"&gt;introduction to testing with Clarinet&lt;/a&gt; using the app we're building here as a starting point.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stacks.js
&lt;/h3&gt;

&lt;p&gt;Stacks.js is how we can interact with our smart contracts from our frontend applications.&lt;/p&gt;

&lt;p&gt;Again from the Ethereum world, this can be compared to ethers.js or web3.js.&lt;/p&gt;

&lt;p&gt;This will help us with things like authentication, interacting with our storage system, interacting with smart contracts, and other things like stacking that we'll go over.&lt;/p&gt;

&lt;p&gt;We're actually going to be using a few different packages in this tutorial, we'll cover them one at a time as we use them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gaia
&lt;/h3&gt;

&lt;p&gt;Gaia is Stack's storage solution. It's a bit of a hybrid system in that it utilizes traditional cloud storage like Amazon S3.&lt;/p&gt;

&lt;p&gt;Gaia allows us to store application and user data off-chain but still access it securely from our Stacks apps.&lt;/p&gt;

&lt;p&gt;The blockchain should only be used to store critical metadata as it is expensive and slow to store data on the blockchain directly.&lt;/p&gt;

&lt;p&gt;We won't be using Gaia in this particular tutorial, as we won't be storing any data off-chain, but I'm planning on writing a tutorial incorporating storage with Gaia in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Awesome People and Organizations to Follow
&lt;/h2&gt;

&lt;p&gt;Now that we've gone over the developer ecosystem, here's a list of people you should definitely follow on Twitter if you're looking to immerse yourself in the world of Stacks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/KenTheRogers" rel="noopener noreferrer"&gt;kenny&lt;/a&gt; - shameless plug, this is me&lt;br&gt;
&lt;a href="https://twitter.com/Stacks" rel="noopener noreferrer"&gt;Stacks&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/hirosystems" rel="noopener noreferrer"&gt;Hiro&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/stacksorg" rel="noopener noreferrer"&gt;Stacks Foundation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/StacksStartups" rel="noopener noreferrer"&gt;Stacks Accelerator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is just barely scratching the surface, but it will be a great jumping-off point for you to immerse yourself in the community.&lt;/p&gt;
&lt;h2&gt;
  
  
  What We'll Be Building
&lt;/h2&gt;

&lt;p&gt;Throughout this series, we'll be building an app called Sup. Sup is a simple app that will allow visitors to our site to pay a specified amount of STX to post a message.&lt;/p&gt;

&lt;p&gt;So visitors will be able to go to our site and pay a small fee in STX to post a message on our website.&lt;/p&gt;

&lt;p&gt;We'll also display the currently logged-in user's message on the same page.&lt;/p&gt;

&lt;p&gt;This basic app will be a great use case to get familiar with the various parts of the Stacks development ecosystem and the basics of the Clarity language.&lt;/p&gt;

&lt;p&gt;We'll write our smart contracts in Clarity, use Clarinet as our development environment, and connect our frontend to the Stacks chain using stacks.js.&lt;/p&gt;

&lt;p&gt;For the frontend, we'll be using Next and Tailwind.&lt;/p&gt;

&lt;p&gt;Before going through this series, you should be familiar with the basics of building sites and apps with JS and React.&lt;/p&gt;

&lt;p&gt;No existing knowledge of Stacks or Clarity is necessary, we'll be covering the basics here.&lt;/p&gt;

&lt;p&gt;If at any point you get stuck, lost, or otherwise off track, you can compare your code to the &lt;a href="https://github.com/kenrogers/sup" rel="noopener noreferrer"&gt;Sup GitHub repo&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to Use This Tutorial
&lt;/h2&gt;

&lt;p&gt;If you've gone through many tutorials, you are probably familiar with the concept of tutorial hell.&lt;/p&gt;

&lt;p&gt;This is where you get stuck endlessly consuming tutorials but never feel capable enough to actually build anything.&lt;/p&gt;

&lt;p&gt;I'll let you in on a secret, tutorials aren't actually a great way to learn something.&lt;/p&gt;

&lt;p&gt;Why am I writing one then?&lt;/p&gt;

&lt;p&gt;Because they are a great way to be introduced to something and to get a high-level picture of how it works and how to stitch multiple technologies together.&lt;/p&gt;

&lt;p&gt;But to actually learn, you need to struggle through the process of building something on your own.&lt;/p&gt;

&lt;p&gt;So, go through this tutorial and follow along to get familiar with how it all works together.&lt;/p&gt;

&lt;p&gt;Then, and this is critical, go and build something on your own from scratch. Something different.&lt;/p&gt;

&lt;p&gt;Build it and deploy it for the world to see.&lt;/p&gt;

&lt;p&gt;It will be hard and frustrating, but it's the only way to really learn.&lt;/p&gt;

&lt;p&gt;I'm &lt;a href="https://twitter.com/KenTheRogers" rel="noopener noreferrer"&gt;here to help&lt;/a&gt; if you need me, just reach out.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://discord.gg/KKdEfKB3" rel="noopener noreferrer"&gt;Stacks Discord&lt;/a&gt; is another great place to go for help&lt;/p&gt;

&lt;p&gt;Let's do this.&lt;/p&gt;
&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;p&gt;The first thing we need to do is get our dev environment set up with Clarinet and Next.&lt;/p&gt;

&lt;p&gt;First, create a main project folder that will house both our smart contract code and our front-end Next app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir sup &amp;amp;&amp;amp; cd sup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's get the Next app set up with Tailwind by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-next-app -e with-tailwindcss frontend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change into that directory and run &lt;code&gt;npm run dev&lt;/code&gt; to make sure everything is working.&lt;/p&gt;

&lt;p&gt;If everything worked, you should be able to visit &lt;code&gt;localhost:3000&lt;/code&gt; and see the default template:&lt;/p&gt;

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

&lt;p&gt;Leave that terminal window open and open up a new one to get our smart contracts set up with Clarinet.&lt;/p&gt;

&lt;p&gt;Clarinet is super helpful in writing smart contracts because it allows us to deploy them on our own little localized blockchain. We can instantly create accounts and allocate STX to them and can run contracts without having to wait for them to process on a live chain.&lt;/p&gt;

&lt;p&gt;Also, if you use VS Code, you may want to get the &lt;a href="https://marketplace.visualstudio.com/items?itemName=HiroSystems.clarity-lsp" rel="noopener noreferrer"&gt;Clarity extension&lt;/a&gt; set up.&lt;/p&gt;

&lt;p&gt;If you're on Mac you can install Clarinet with Homebrew.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Once we have Clarinet installed, we can instantiate a new project by changing into the main &lt;code&gt;sup&lt;/code&gt; folder and running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clarinet new backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To install Clarinet on other systems, check &lt;a href="https://docs.hiro.so/smart-contracts/clarinet#installing-clarinet" rel="noopener noreferrer"&gt;Hiro's website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Change into that directory and you'll see a few folders: contracts, settings, and tests. You'll also see a &lt;code&gt;Clarinet.toml&lt;/code&gt; file for Clarinet configuration.&lt;/p&gt;

&lt;p&gt;If we look inside the settings folder, we'll see a few config files that correspond to different networks.&lt;/p&gt;

&lt;p&gt;When we use Clarinet to develop, we're working in the &lt;code&gt;Devnet&lt;/code&gt; network, a localized Stacks network that runs in memory only. If you open up that file you'll see that we are setting up some mock accounts to work with.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[network]
name = "devnet"

[accounts.deployer]
mnemonic = "twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw"
balance = 100_000_000_000_000
# secret_key: 753b7cc01a1a2e86221266a154af739463fce51219d97e4f856cd7200c3bd2a601
# stx_address: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
# btc_address: mqVnk6NPRdhntvfm4hh9vvjiRkFDUuSYsH

[accounts.wallet_1]
mnemonic = "sell invite acquire kitten bamboo drastic jelly vivid peace spawn twice guilt pave pen trash pretty park cube fragile unaware remain midnight betray rebuild"
balance = 100_000_000_000_000
# secret_key: 7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801
# stx_address: ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5
# btc_address: mr1iPkD9N3RJZZxXRk7xF9d36gffa6exNC

[accounts.wallet_2]
mnemonic = "hold excess usual excess ring elephant install account glad dry fragile donkey gaze humble truck breeze nation gasp vacuum limb head keep delay hospital"
balance = 100_000_000_000_000
# secret_key: 530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101
# stx_address: ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG
# btc_address: muYdXKmX9bByAueDe6KFfHd5Ff1gdN9ErG
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's start learning some Clarity and write our first contract. We'll continue to use and learn more about Clarinet as we go.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our First Smart Contract with Clarity
&lt;/h2&gt;

&lt;p&gt;Before we get started, ensure that you are inside the &lt;code&gt;sup/backend&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;First up, let's create our contract with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clarinet contract new sup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sup contract is what will handle users being able to post a message to our site.&lt;/p&gt;

&lt;p&gt;After we run this, you'll notice a few things were created.&lt;/p&gt;

&lt;p&gt;First, a &lt;code&gt;sup.clar&lt;/code&gt; file was created in our contracts folder. This is where we'll actually write our contract.&lt;/p&gt;

&lt;p&gt;Second, a &lt;code&gt;sup_test.ts&lt;/code&gt; file was created in the tests folder. This is how we can test our file using the Clarinet testing harness, which is a tool for testing smart contracts in TypeScript.&lt;/p&gt;

&lt;p&gt;As mentioned earlier, we're not going to be testing in this tutorial, but you can check out the generated code yourself and run &lt;code&gt;clarinet test&lt;/code&gt; if you are curious.&lt;/p&gt;

&lt;p&gt;And if you are interested in integrating testing into this project, &lt;a href="https://twitter.com/nikosbaxevanis" rel="noopener noreferrer"&gt;Nikos Baxevanis&lt;/a&gt; has written an excellent &lt;a href="https://blog.nikosbaxevanis.com/2022/03/05/clarity-property-based-testing-primer/" rel="noopener noreferrer"&gt;introduction to testing with Clarinet&lt;/a&gt; using the app we're building here as a starting point.&lt;/p&gt;

&lt;p&gt;Finally, it updated our &lt;code&gt;Clarinet.toml&lt;/code&gt; file to reference the new contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[contracts.sup]
path = "contracts/sup.clar"
depends_on = []
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clarity is designed to be highly readable and was written intentionally to make it easier to write safe smart contracts. It is decidable, meaning you can know with certainty what code will do before you run it.&lt;/p&gt;

&lt;p&gt;It is meant to be predictable and secure by default, making it as simple as possible to write secure smart contracts, which is extremely important, since once they are deployed, they are deployed forever.&lt;/p&gt;

&lt;p&gt;Clarity may seem a bit strange at first, especially if you come from the world of JavaScript or Solidity, but once you start working with it you'll love the conciseness and simplicity.&lt;/p&gt;

&lt;p&gt;The best way to learn is by doing, so let's write this smart contract and we'll go over what each line is doing as we go, covering Clarity concepts and syntax along the way.&lt;/p&gt;

&lt;p&gt;Open up the &lt;code&gt;sup.clar&lt;/code&gt; file that was created and let's get going.&lt;/p&gt;

&lt;p&gt;Clarinet generates some placeholder content for us, which serves as a nice outline for creating our own contract:&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Contract Documenting
&lt;/h3&gt;

&lt;p&gt;First up, we can add a description by prefacing it with &lt;code&gt;;;&lt;/code&gt;, which is Clarity's syntax for code comments. Here is some &lt;a href="https://github.com/stacksgov/sips/pull/32" rel="noopener noreferrer"&gt;helpful information&lt;/a&gt; on how to effectively document your contract.&lt;/p&gt;

&lt;p&gt;We'll write:&lt;/p&gt;

&lt;p&gt;'Smart contract to handle writing a message to the blockchain in exchange for a small fee in STX'&lt;/p&gt;

&lt;p&gt;For the rest of the code, let's think through what we actually need our smart contract to do.&lt;/p&gt;

&lt;p&gt;I always like to write out the functionality of my code before I start coding to help me get started.&lt;/p&gt;

&lt;p&gt;Usually I do that in pseudo-code comments right inside my code files.&lt;/p&gt;

&lt;p&gt;So for Sup, we need the site visitor to be able to post a message to the blockchain. As part of that process, we need them to be able to transfer a certain amount of STX from their wallet into our wallet.&lt;/p&gt;

&lt;p&gt;This brings up a few different pieces of data that need to be created and used, as well as a couple of functions.&lt;/p&gt;

&lt;p&gt;First, we need the user to be able to authenticate themselves and pass their address from the front end to the contract itself.&lt;/p&gt;

&lt;p&gt;We'll handle the front end piece in a bit, but this will be handled by integrating with the Hiro Web Wallet.&lt;/p&gt;

&lt;p&gt;We also need them to be able to type in a message and pass that through to our contract.&lt;/p&gt;

&lt;p&gt;As far as functionality, we need a function that will allow the visitor to post a message.&lt;/p&gt;

&lt;p&gt;We also need a couple of getter functions, which will handle retrieving the values of the variables we are storing, like the message.&lt;/p&gt;

&lt;h3&gt;
  
  
  Defining Variables and Constants
&lt;/h3&gt;

&lt;p&gt;First let's define our address (the one we want people to transfer STX to) as a constant.&lt;/p&gt;

&lt;p&gt;Constants in Clarity are values that will not change throughout our contract, but that we need to reference.&lt;/p&gt;

&lt;p&gt;For now, let's create a constant for our address and for storing an error message.&lt;/p&gt;

&lt;p&gt;If you don't have the &lt;a href="https://www.hiro.so/wallet" rel="noopener noreferrer"&gt;Hiro Web Wallet&lt;/a&gt; installed and set up, go ahead and do that now, we'll be using it in a bit.&lt;/p&gt;

&lt;p&gt;For now, let's use one of the addresses generated by Clarinet on our DevNet chain. We can use the address listed in &lt;code&gt;accounts.deployer&lt;/code&gt; from our &lt;code&gt;Devnet.toml&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(define-constant receiver-address 'ST3QFME3CANQFQNR86TYVKQYCFT7QX4PRXM1V9W6H)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's our first piece of Clarity code. What we're doing here is saying that we want to define a new constant with &lt;code&gt;define-constant&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We want to name that constant &lt;code&gt;receiver-address&lt;/code&gt; and we want it to be a principal with the value of &lt;code&gt;ST3QFME3CANQFQNR86TYVKQYCFT7QX4PRXM1V9W6H&lt;/code&gt;. Principals in Clarity can be thought of as user accounts corresponding to Stacks addresses.&lt;/p&gt;

&lt;p&gt;In this case, you'll want to replace the address with one of the generated addresses from the &lt;code&gt;Devnet.toml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;'&lt;/code&gt; character is how we denote that we are setting a principal.&lt;/p&gt;

&lt;p&gt;Note the parentheses. Everything in Clarity is wrapped in parentheses. It takes some getting used to and can be a bit difficult to keep track of.&lt;/p&gt;

&lt;p&gt;If you use VS Code, you can enable a setting to highlight matching bracket pairs, which can make it easier to keep track of things in Clarity.&lt;/p&gt;

&lt;p&gt;Add the following to your &lt;code&gt;settings.json&lt;/code&gt; file in VS Code to enable this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"editor.bracketPairColorization.enabled": true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to open up the &lt;code&gt;Devnet.toml&lt;/code&gt; file and add that rather than using the address listed here. This is the address my local Clarinet instance generated, and yours will be different.&lt;/p&gt;

&lt;p&gt;Next we need to get our variables set up. The main difference between constants and variables is that variables can change throughout a contract and constants cannot.&lt;/p&gt;

&lt;p&gt;I like to define my constants and variables at the top of my contracts, but you can also define them at the bottom if you prefer.&lt;/p&gt;

&lt;p&gt;For Sup we'll only need two variables, one to store the total amount of sups we have received and one to store a map of each message.&lt;/p&gt;

&lt;p&gt;A map in Clarity can map together two types and pieces of data. In our case we want to map a message to a principal.&lt;/p&gt;

&lt;p&gt;So the way our app will work is that when a visitor posts a message, it will add a new item to our messages map with the visitor's address as the key and the message content as the value.&lt;/p&gt;

&lt;p&gt;We don't need a variable for the sender's address because Clarity has a built-in keyword called &lt;code&gt;tx-sender&lt;/code&gt; that will get that for us.&lt;/p&gt;

&lt;p&gt;Let's define those underneath the &lt;code&gt;;; data maps and vars&lt;/code&gt; comment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(define-data-var total-sups uint u0)
(define-map messages principal (string-utf8 500))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The top line here is saying we want to define a new variable named total-sups, we want it to be an unsigned integer, and we want the default value to be an unsigned integer of 0.&lt;/p&gt;

&lt;p&gt;The bottom line is saying we want to define a new map called &lt;code&gt;messages&lt;/code&gt;. It will contain data pairs consisting of a principal corresponding to a utf8 string with a max of 500 characters.&lt;/p&gt;

&lt;p&gt;And we can retrieve this string by looking up the address.&lt;/p&gt;

&lt;p&gt;What this means is that we are creating a map of values where the key will be a principal and the value will be a string.&lt;/p&gt;

&lt;p&gt;This is how we will keep track of all the messages people write on the site.&lt;/p&gt;

&lt;p&gt;Remember that a blockchain is, in a way, a distributed database. So the data in this map will persist on the blockchain. We'll look at how to read from it later in this tutorial.&lt;/p&gt;

&lt;p&gt;Consult the &lt;a href="https://book.clarity-lang.org/ch02-00-types.html" rel="noopener noreferrer"&gt;Clarity Book&lt;/a&gt; to learn more about the different types available to you in Clarity and how to declare them.&lt;/p&gt;

&lt;p&gt;Side note, notice how these addresses begin with &lt;code&gt;ST&lt;/code&gt;? That means that we are dealing with an address on a testnet. If it were on mainnet, the address would begin with &lt;code&gt;SP&lt;/code&gt; or &lt;code&gt;SM&lt;/code&gt; instead. Just something to be aware of.&lt;/p&gt;

&lt;h3&gt;
  
  
  Defining Functions
&lt;/h3&gt;

&lt;p&gt;Next let's create a simple getter function to retrieve our stored variable.&lt;/p&gt;

&lt;p&gt;We want to be able to call this getter function from our front end, so it needs to be public.&lt;/p&gt;

&lt;p&gt;Underneath the &lt;code&gt;;; public functions&lt;/code&gt; heading we'll create that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(define-read-only (get-sups)
  (var-get total-sups)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are pretty simple, and are essentially saying we want to define a new read-only function (read-only because we aren't modifying any data, just reading it) called &lt;code&gt;get-sups&lt;/code&gt;, that will then retrieve that value with &lt;code&gt;var-get&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We also want to set up a getter function to access the message mapped to the currently logged in user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(define-read-only (get-message (who principal))
    (map-get? messages who)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;map-get?&lt;/code&gt; is how we retrieve a value from a map, and here we are getting the entry whose principal value is equal to whatever we pass in to the function. In this &lt;code&gt;read-only&lt;/code&gt; function, we are passing a variable called &lt;code&gt;who&lt;/code&gt; with a type of &lt;code&gt;principal&lt;/code&gt;. This is how we'll look up the right message in the map we created.&lt;/p&gt;

&lt;p&gt;Read-only functions are able to be accessed both inside and outside our contract.&lt;/p&gt;

&lt;p&gt;If an entry is found, it will return an optional, a &lt;code&gt;some&lt;/code&gt; or a &lt;code&gt;none&lt;/code&gt; value. Again, consult the &lt;a href="https://book.clarity-lang.org/ch02-00-types.html" rel="noopener noreferrer"&gt;Clarity book&lt;/a&gt; for more on what that means.&lt;/p&gt;

&lt;p&gt;Now let's create the function that will actually handle writing the message to the blockchain and transferring the STX.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(define-public (write-sup (message (string-utf8 500)) (price uint))
    (begin
        (try! (stx-transfer? price tx-sender receiver-address))

        (map-set messages tx-sender message )

        (var-set total-sups (+ (var-get total-sups) u1))

        (ok "Sup written successfully")
    )
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alright there is a lot going on here so let's break it down.&lt;/p&gt;

&lt;p&gt;First we are defining a public function called &lt;code&gt;write-sup&lt;/code&gt; that will take two parameters, the message and the price.&lt;/p&gt;

&lt;p&gt;Then we start a &lt;code&gt;begin&lt;/code&gt; block, which groups multiple expressions, and returns the value of the last expression. This simple construct is needed because the body of a function is limited to one expression. You may be familiar with other programming languages that use curly braces { ... } for this same purpose.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;begin&lt;/code&gt; block allows us to wrap multiple function calls in one. To see what I mean, comment out the beginning and end of the &lt;code&gt;begin&lt;/code&gt; block and run &lt;code&gt;clarinet check&lt;/code&gt;. You'll see an error saying that the number of arguments is incorrect.&lt;/p&gt;

&lt;p&gt;The first line of this block is using a &lt;code&gt;try!&lt;/code&gt; function to transfer STX.&lt;/p&gt;

&lt;p&gt;From the &lt;a href="https://book.clarity-lang.org/ch06-02-try.html" rel="noopener noreferrer"&gt;Clarity Book&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;"The &lt;code&gt;try!&lt;/code&gt; function takes an &lt;code&gt;optional&lt;/code&gt; or a response type and will attempt to unwrap it. Unwrapping is the act of extracting the inner value and returning it."&lt;/p&gt;

&lt;p&gt;In this case, we are attempting to evaluate the stx-transfer? function. The function returns a response type. If the call succeeds, it will return &lt;code&gt;(ok true)&lt;/code&gt;. The &lt;code&gt;try!&lt;/code&gt;  function unwraps the inner value and therefore returns true.&lt;/p&gt;

&lt;p&gt;If it fails, it will return the error and exit the &lt;code&gt;write-sup&lt;/code&gt; function. All Clarity functions with a ! at the end can exit the control flow early.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;stx-transfer?&lt;/code&gt; function takes in a few parameters: the price, denoted in microstacks, the principal sending the STX, and the principal receiving the STX.&lt;/p&gt;

&lt;p&gt;Next we are setting the item value in our &lt;code&gt;messages&lt;/code&gt; map that corresponds to the person sending the transaction to the passed message.&lt;/p&gt;

&lt;p&gt;Finally, we are incrementing the value of our &lt;code&gt;total-sups&lt;/code&gt; variable using the &lt;code&gt;+&lt;/code&gt; operator.&lt;/p&gt;

&lt;p&gt;This is saying: set the &lt;code&gt;total-sups&lt;/code&gt; value to the current &lt;code&gt;total-sups&lt;/code&gt; value plus 1.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/Polish_notation" rel="noopener noreferrer"&gt;Polish notation&lt;/a&gt; used in Clarity can take some getting used to, but practice saying to yourself what the code is doing and you'll pick it up quickly.&lt;/p&gt;

&lt;p&gt;A helpful mental model can be to think of the symbol as the function name, and the numbers being operated on as parameters.&lt;/p&gt;

&lt;p&gt;Finally, if the function runs successfully we return a string saying so.&lt;/p&gt;

&lt;p&gt;To check and see if we have any syntax errors, we can run &lt;code&gt;clarinet check&lt;/code&gt; inside the &lt;code&gt;backend&lt;/code&gt; folder of our project.&lt;/p&gt;

&lt;p&gt;If you've followed along so far, it will output that the syntax is correct, but we have a warning regarding our &lt;code&gt;message&lt;/code&gt; variable:&lt;/p&gt;

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

&lt;p&gt;What's going on here?&lt;/p&gt;

&lt;p&gt;Remember that Clarity is purpose-built to help us write secure code. In the spirit of that ethos, Clarinet has some checks that help us do the same thing.&lt;/p&gt;

&lt;p&gt;Clarinet is helping us watch out for untrusted data. Blindly accepting untrusted user input is the cause for a large amount of software security vulnerabilities.&lt;/p&gt;

&lt;p&gt;Since this is a public function, all of our data is untrusted if it is accepted as a parameter to our &lt;code&gt;write-sup&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;This warning is being given as a result of a recent addition to Clarinet called the check-checker.&lt;/p&gt;

&lt;p&gt;When we run &lt;code&gt;clarinet check&lt;/code&gt; it will check to see if untrusted input data is being checked by our code to make sure it is legitimate.&lt;/p&gt;

&lt;p&gt;In our case, we have the untrusted input source of &lt;code&gt;message&lt;/code&gt; and are using that to modify our &lt;code&gt;messages&lt;/code&gt; map.&lt;/p&gt;

&lt;p&gt;To clear it and pass the check, we need to add some sort of check on the untrusted input. However, we actually do want the user to be able to put whatever they want here, since that's the whole point of adding the message.&lt;/p&gt;

&lt;p&gt;We're not doing anything with this data except assigning it to the user's principal in our map, and the user should be able to write whatever they want.&lt;/p&gt;

&lt;p&gt;So to get around this error and tell the check-checker all is well, we can add this right above the &lt;code&gt;map-set&lt;/code&gt; call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;;; #[allow(unchecked_data)]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And with that, our check passes.&lt;/p&gt;

&lt;p&gt;As the developer, it's your responsibility to add any checks that might need to be run in order to make sure only the data you are expecting is allowed to pass through to the function.&lt;/p&gt;

&lt;p&gt;This feature is important to understand as it has security implications. I highly recommend reading &lt;a href="https://www.hiro.so/blog/new-safety-checks-in-clarinet" rel="noopener noreferrer"&gt;Hiro's post&lt;/a&gt; on the topic.&lt;/p&gt;

&lt;p&gt;You just wrote a Clarity smart contract. Let's switch over to the front end so we can actually use it now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Front End with Next and Stacks.js
&lt;/h2&gt;

&lt;p&gt;First let's just get some boilerplate front end code up and running. We're not focusing on learning React here so go ahead and just copy this and paste it into &lt;code&gt;frontend/pages/index.tsx&lt;/code&gt; to update the main page of the Next app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useEffect } from "react";
import Head from "next/head";

export default function Home() {
  const [message, setMessage] = useState("");
  const [price, setPrice] = useState(5);
  const [userData, setUserData] = useState({});
  const [loggedIn, setLoggedIn] = useState(false);

  const handleMessageChange = (e) =&amp;gt; {
    setMessage(e.target.value);
  };

  const handlePriceChange = (e) =&amp;gt; {
    setPrice(e.target.value);
  };

  const handleSubmit = (e) =&amp;gt; {
    e.preventDefault();
    // Do Stacks things
  };

  return (
    &amp;lt;div className="flex flex-col items-center justify-center min-h-screen py-2"&amp;gt;
      &amp;lt;Head&amp;gt;
        &amp;lt;title&amp;gt;Sup&amp;lt;/title&amp;gt;
        &amp;lt;link rel="icon" href="/favicon.ico" /&amp;gt;
      &amp;lt;/Head&amp;gt;

      &amp;lt;main className="flex flex-col items-center justify-center w-full flex-1 px-20 text-center"&amp;gt;
        &amp;lt;h1 className="text-6xl font-bold mb-24"&amp;gt;Sup&amp;lt;/h1&amp;gt;
        &amp;lt;form onSubmit={handleSubmit}&amp;gt;
          &amp;lt;p&amp;gt;
            Say
            &amp;lt;input
              className="p-6 border rounded mx-2"
              type="text"
              value={message}
              onChange={handleMessageChange}
              placeholder="something"
            /&amp;gt;
            for
            &amp;lt;input
              className="p-6 border rounded mx-2"
              type="number"
              value={price}
              onChange={handlePriceChange}
            /&amp;gt;{" "}
            STX
          &amp;lt;/p&amp;gt;
          &amp;lt;button
            type="submit"
            className="p-6 bg-green-500 text-white mt-8 rounded"
          &amp;gt;
            Post Message
          &amp;lt;/button&amp;gt;
        &amp;lt;/form&amp;gt;
      &amp;lt;/main&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is just setting up a basic React form.&lt;/p&gt;

&lt;p&gt;Now we can start adding some functionality for interacting with Stacks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication
&lt;/h3&gt;

&lt;p&gt;When we build web3 apps we do authentication a bit differently. Rather than setting up the typical user flow with a username or email and password, we simply allow the user to connect to our application with their wallet.&lt;/p&gt;

&lt;p&gt;If you come from the Ethereum world, you're likely familiar with MetaMask or a similar browser-based wallet.&lt;/p&gt;

&lt;p&gt;In the Stacks world the most common wallet is the Stacks Wallet built by Hiro.&lt;/p&gt;

&lt;p&gt;Stacks.js comes with a &lt;code&gt;connect&lt;/code&gt; package that we'll use to hook into the Hiro Wallet for Web and authenticate our wallet with our web app.&lt;/p&gt;

&lt;p&gt;If you're curious about how authentication with the web wallet actually works, the &lt;a href="https://docs.stacks.co/build-apps/references/authentication" rel="noopener noreferrer"&gt;Stacks website&lt;/a&gt; has some great documentation explaining the process.&lt;/p&gt;

&lt;p&gt;We're going to focus on the practicalities of getting it implemented here.&lt;/p&gt;

&lt;p&gt;The first thing we need to do is install the dependency. Make sure you are in the &lt;code&gt;frontend&lt;/code&gt; folder and run&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Now open up that &lt;code&gt;index&lt;/code&gt; file with all our React code and let's get this set up.&lt;/p&gt;

&lt;p&gt;Add the following at the top of the file right under the other import statement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { AppConfig, UserSession, showConnect } from '@stacks/connect';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this right above our state declarations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const appConfig = new AppConfig(['publish_data']);
const userSession = new UserSession({ appConfig });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a production app, you'd likely want to make this available globally using some sort of state management library like React Context or Zustand.&lt;/p&gt;

&lt;p&gt;What we are doing here is initializing the auth configuration by telling &lt;code&gt;connect&lt;/code&gt; that we need the &lt;code&gt;publish_data&lt;/code&gt; permissions scope. This will allow us to actually publish data and interact with the app.&lt;/p&gt;

&lt;p&gt;Next we need to set up the function to handle the authentication.&lt;/p&gt;

&lt;p&gt;Add this right under our &lt;code&gt;handleSubmit&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function authenticate() {
    showConnect({
        appDetails: {
            name: "Sup",
            icon: "https://assets.website-files.com/618b0aafa4afde65f2fe38fe/618b0aafa4afde2ae1fe3a1f_icon-isotipo.svg",
        },
        redirectTo: "/",
        onFinish: () =&amp;gt; {
            window.location.reload();
        },
        userSession,
    });
}

useEffect(() =&amp;gt; {
    if (userSession.isSignInPending()) {
        userSession.handlePendingSignIn().then((userData) =&amp;gt; {
            setUserData(userData);
        });
    } else if (userSession.isUserSignedIn()) {
        setLoggedIn(true);
        setUserData(userSession.loadUserData());
    }
}, []);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the function we'll call when we click the button to actually connect to our wallet, which we'll do in just a minute.&lt;/p&gt;

&lt;p&gt;Note: If you get an error about not being able to find the &lt;code&gt;regenerator-runtime&lt;/code&gt; package, running &lt;code&gt;npm i regenerator-runtime&lt;/code&gt; should fix that.&lt;/p&gt;

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

&lt;p&gt;This code is pretty self-explanatory, but at a high level it is calling the &lt;code&gt;showConnect&lt;/code&gt; function which will trigger the Hiro wallet to show the connect window. The wallet will take care of the authentication functionality from there.&lt;/p&gt;

&lt;p&gt;After it does so, it will run the &lt;code&gt;onFinish&lt;/code&gt; function, we add any post-authentication work needs to be done there. In this case, we reload the page so our &lt;code&gt;userSession&lt;/code&gt; gets picked up.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;appDetails&lt;/code&gt; passes a couple things that the Hiro window will show. For demo purposes, we're just giving it the Stacks logo.&lt;/p&gt;

&lt;p&gt;The second part of this is a &lt;code&gt;useEffect&lt;/code&gt; call that will run on page load and set our user session data, as well as setting our &lt;code&gt;loggedIn&lt;/code&gt; state to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we need to add a button for the user to connect to the wallet. Let's add that right above our Sup &lt;code&gt;h1&lt;/code&gt; tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div className="flex w-full items-end justify-center"&amp;gt;
  &amp;lt;button
    className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded mb-6"
    onClick={() =&amp;gt; authenticate()}
  &amp;gt;
    Connect to Wallet
  &amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After you add that, switch to the testnet in your web wallet and let's see if it works.&lt;/p&gt;

&lt;p&gt;In order to do that we first need to get a dev blockchain running using Clarinet so that we have something to work with.&lt;/p&gt;

&lt;p&gt;Make sure you have &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; installed and switch into the &lt;code&gt;backend&lt;/code&gt; folder. Once you're in there, run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clarinet integrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will set up a local blockchain on our system for testing purposes.&lt;/p&gt;

&lt;p&gt;This will take a while to run the first time, and you'll see a crazy looking dashboard which will have the system log, service status, mempool summary, and a minimal block explorer.&lt;/p&gt;

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

&lt;p&gt;Once everything has successfully started up, we can begin interacting with our app on the local DevNet chain.&lt;/p&gt;

&lt;p&gt;Now let's use that data and display the Sup form if the user is logged in and the connect button if they are not.&lt;/p&gt;

&lt;p&gt;We want to change the code a bit so that the form only shows up if we are logged in with our wallet. In addition, we only want the connect wallet button to show if we are not connected currently.&lt;/p&gt;

&lt;p&gt;Swap out the code in the &lt;code&gt;index&lt;/code&gt; file with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useEffect } from "react";
import Head from "next/head";
import { AppConfig, UserSession, showConnect } from "@stacks/connect";

export default function Home() {
  const appConfig = new AppConfig(["publish_data"]);
  const userSession = new UserSession({ appConfig });

  const [message, setMessage] = useState("");
  const [price, setPrice] = useState(5);
  const [userData, setUserData] = useState({});
  const [loggedIn, setLoggedIn] = useState(false);

  const handleMessageChange = (e) =&amp;gt; {
    setMessage(e.target.value);
  };

  const handlePriceChange = (e) =&amp;gt; {
    setPrice(e.target.value);
  };

  const handleSubmit = (e) =&amp;gt; {
    e.preventDefault();
    // Do Stacks things
  };

  function authenticate() {
    showConnect({
      appDetails: {
        name: "Sup",
        icon: "https://assets.website-files.com/618b0aafa4afde65f2fe38fe/618b0aafa4afde2ae1fe3a1f_icon-isotipo.svg",
      },
      redirectTo: "/",
      onFinish: () =&amp;gt; {
        window.location.reload();
      },
      userSession,
    });
  }

  useEffect(() =&amp;gt; {
    if (userSession.isSignInPending()) {
      userSession.handlePendingSignIn().then((userData) =&amp;gt; {
        setUserData(userData);
      });
    } else if (userSession.isUserSignedIn()) {
      setLoggedIn(true);
      setUserData(userSession.loadUserData());
    }
  }, []);

  return (
    &amp;lt;div className="flex flex-col items-center justify-center min-h-screen py-2"&amp;gt;
      &amp;lt;Head&amp;gt;
        &amp;lt;title&amp;gt;Sup&amp;lt;/title&amp;gt;
        &amp;lt;link rel="icon" href="/favicon.ico" /&amp;gt;
      &amp;lt;/Head&amp;gt;

      &amp;lt;main className="flex flex-col items-center justify-center w-full flex-1 px-20 text-center"&amp;gt;
        &amp;lt;div className="flex flex-col w-full items-center justify-center"&amp;gt;
          &amp;lt;h1 className="text-6xl font-bold mb-24"&amp;gt;Sup&amp;lt;/h1&amp;gt;
          {loggedIn ? (
            &amp;lt;form onSubmit={handleSubmit}&amp;gt;
              &amp;lt;p&amp;gt;
                Say
                &amp;lt;input
                  className="p-6 border rounded mx-2"
                  type="text"
                  value={message}
                  onChange={handleMessageChange}
                  placeholder="something"
                /&amp;gt;
                for
                &amp;lt;input
                  className="p-6 border rounded mx-2"
                  type="number"
                  value={price}
                  onChange={handlePriceChange}
                /&amp;gt;{" "}
                STX
              &amp;lt;/p&amp;gt;
              &amp;lt;button
                type="submit"
                className="p-6 bg-green-500 text-white mt-8 rounded"
              &amp;gt;
                Post Message
              &amp;lt;/button&amp;gt;
            &amp;lt;/form&amp;gt;
          ) : (
            &amp;lt;button
              className="bg-white-500 hover:bg-gray-300 border-black border-2 font-bold py-2 px-4 rounded mb-6"
              onClick={() =&amp;gt; authenticate()}
            &amp;gt;
              Connect to Wallet
            &amp;lt;/button&amp;gt;
          )}
        &amp;lt;/div&amp;gt;
      &amp;lt;/main&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alright, we've got basic authentication going and we are conditionally displaying our form if we are connected to our wallet. &lt;/p&gt;

&lt;p&gt;Now let's go ahead and see how we can use this form to actually post a message to the chain by paying STX.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing Data
&lt;/h3&gt;

&lt;p&gt;The first thing we want to do here is set up our frontend so that when we submit the form, we are generating a new transaction to the Stacks blockchain.&lt;/p&gt;

&lt;p&gt;There's a fair amount of setup we have to do to get this working properly on our local chain, so let's do that really quick.&lt;/p&gt;

&lt;p&gt;When we ran &lt;code&gt;clarinet integrate&lt;/code&gt; we started running a local Stacks chain on our machine at &lt;code&gt;http://localhost:3999&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This gives us a lot of benefits, the main one being that we can test and interact with our smart contract without having to deploy it to a public testnet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding STX to Your Local Account
&lt;/h3&gt;

&lt;p&gt;In our app we need to interact as if we are a logged in user. So we need to hook our web wallet into our local DevNet chain and get logged in as the first account.&lt;/p&gt;

&lt;p&gt;Here's how to do this:&lt;/p&gt;

&lt;p&gt;Switch to the &lt;code&gt;Devnet&lt;/code&gt; network in the web wallet user interface by hitting the menu button in the top right and selecting 'Change Network' and select 'Devnet'.&lt;/p&gt;

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

&lt;p&gt;Then make sure a user account exists on that network and is currently logged in.&lt;/p&gt;

&lt;p&gt;Next, hit that same menu button and select 'View Secret Key'&lt;/p&gt;

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

&lt;p&gt;This will bring up the secret key used to authenticate that address. Take that secret key and copy it over to the &lt;code&gt;memonic&lt;/code&gt; field in the &lt;code&gt;Devnet.toml&lt;/code&gt; file for &lt;code&gt;accounts.wallet_1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, take the account address from the Hiro Web Wallet and copy it over the &lt;code&gt;stx_address&lt;/code&gt; field in the same file.&lt;/p&gt;

&lt;p&gt;Do that, restart the DevNet, and you should have a bunch of STX in your Account 1.&lt;/p&gt;

&lt;p&gt;Now we are ready to write the frontend code that will handle writing our message.&lt;/p&gt;

&lt;p&gt;First we need a few new imports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useEffect } from "react";
import Head from "next/head";
import {
    AppConfig,
    UserSession,
    showConnect,
    openContractCall,
} from "@stacks/connect";
import { uintCV, stringUtf8CV } from "@stacks/transactions";
import { StacksMocknet } from "@stacks/network";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's add each of these pieces one by one and go over what they are doing.&lt;/p&gt;

&lt;p&gt;First we need to set up our network with &lt;code&gt;StacksMocknet&lt;/code&gt;. Mocknet is the same as localnet or DevNet.&lt;/p&gt;

&lt;p&gt;Add this right below the state variable declarations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Set up the network
const network = new StacksMocknet();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that in a production application we would want to set up some sort of environment variable here to set the network based on what environment we were in.&lt;/p&gt;

&lt;p&gt;Next up let's add a couple of other state variables to store the contract address and name, as well as the sup message itself and some loading variables. In a production app, we'd want to set up some sort of constants file and set these conditionally based on our environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [supContractAddress, setSupContractAddress] = useState(
    "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM"
);
const [supContractName, setSupContractName] = useState("sup");
const [error, setError] = useState("");
const [loading, setLoading] = useState(true);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quick note: Be sure to replace the contract address here with the deployer address generated on your system by &lt;code&gt;clarinet integrate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next we need to update our &lt;code&gt;handleSubmit&lt;/code&gt; function to call the &lt;code&gt;write-sup&lt;/code&gt; function in our contract:&lt;br&gt;
&lt;/p&gt;

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

    const functionArgs = [stringUtf8CV(message), uintCV(price * 1000000)];

    const options = {
        contractAddress: supContractAddress,
        contractName: "sup",
        functionName: "write-sup",
        functionArgs,
        network,
        appDetails: {
            name: "Sup",
            icon: window.location.origin + "/vercel.svg",
        },
        onFinish: (data) =&amp;gt; {
            console.log("Stacks Transaction:", data.stacksTransaction);
            console.log("Transaction ID:", data.txId);
            console.log("Raw transaction:", data.txRaw);
        },
    };

    await openContractCall(options);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alright we've got a few things going on here.&lt;/p&gt;

&lt;p&gt;First we're creating a constant called &lt;code&gt;functionArgs&lt;/code&gt; where we are setting up the arguments we need to pass to our function.&lt;/p&gt;

&lt;p&gt;We are setting the price to be equal to &lt;code&gt;price * 1000000&lt;/code&gt; because in our contract, prices are denoted in microstacks. 1,000,000 microstacks is equal to 1 STX.&lt;/p&gt;

&lt;p&gt;The other option here would be to set the price to 5000000 instead and do the conversion in our input field.&lt;/p&gt;

&lt;p&gt;When we set up arguments to pass to a Clarity function, we need to turn them into Clarity variables. That's what we're doing here with the &lt;code&gt;stringUtf8CV&lt;/code&gt; and &lt;code&gt;uintCV&lt;/code&gt; functions.&lt;/p&gt;

&lt;p&gt;You can see what all the different functions are in &lt;a href="https://github.com/hirosystems/stacks.js/blob/master/packages/transactions/src/clarity/clarityValue.ts" rel="noopener noreferrer"&gt;this file&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next we're setting up an options object where we pass in everything we just set up and do some stuff after it finishes being called.&lt;/p&gt;

&lt;p&gt;Finally, we actually call the contract.&lt;/p&gt;

&lt;p&gt;But we have one more piece to add here. If you begin the process of submitting this transaction, you'll see a message at the top of the Hiro Web Wallet screen saying that no stx will be transferred:&lt;/p&gt;

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

&lt;p&gt;But we set the price to be 5 STX, so what's going on here?&lt;/p&gt;

&lt;p&gt;These are the post-conditions I mentioned earlier in the article.&lt;/p&gt;

&lt;p&gt;If we try to run this now, it will fail because the supplied post-conditions were not met. What is actually happening here is that we didn't set up any post-conditions to tell our wallet that we were going to be transferring some STX.&lt;/p&gt;

&lt;p&gt;So it defaulted to thinking nothing would be transferred. These post-conditions are one of the many built-in features of Clarity that can help us to write secure code.&lt;/p&gt;

&lt;p&gt;To fix this we need to add some post-conditions.&lt;/p&gt;

&lt;p&gt;Add the following underneath where we create the &lt;code&gt;functionArgs&lt;/code&gt; constant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const postConditionAddress = userSession.loadUserData().profile.stxAddress.testnet;
const postConditionCode = FungibleConditionCode.LessEqual;
const postConditionAmount = price * 1000000;
const postConditions = [
    makeStandardSTXPostCondition(
        postConditionAddress,
        postConditionCode,
        postConditionAmount
    ),
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the imports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useEffect, useCallback } from "react";
import Head from "next/head";
import {
    AppConfig,
    UserSession,
    showConnect,
    openContractCall,
} from "@stacks/connect";
import {
    uintCV,
    stringUtf8CV,
    standardPrincipalCV,
    hexToCV,
    cvToHex,
    makeStandardSTXPostCondition,
    FungibleConditionCode,
} from "@stacks/transactions";
import { StacksMocknet } from "@stacks/network";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And pass in the post conditions to our contract call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
network,
postConditions,
appDetails: {
    name: "Sup",
    icon: window.location.origin + "/vercel.svg",
},
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if we run this, we'll see the correct post-condition message and everything should run successfully.&lt;/p&gt;

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

&lt;p&gt;Awesome! You just made an app that writes data to the Stacks blockchain and successfully transfers STX in the process.&lt;/p&gt;

&lt;p&gt;Now let's go about reading that data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reading Data
&lt;/h3&gt;

&lt;p&gt;Reading data is a bit more straightforward because we are going to be calling one of our &lt;code&gt;read-only&lt;/code&gt; functions (&lt;code&gt;get-messages&lt;/code&gt; in this case) and don't have to create a transaction, since we aren't modifying the blockchain.&lt;/p&gt;

&lt;p&gt;For this we can use a function from the &lt;code&gt;@stacks/transactions&lt;/code&gt; package called &lt;code&gt;callReadOnlyFunction&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, go ahead and import that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
    uintCV,
    stringUtf8CV,
    standardPrincipalCV,
    hexToCV,
    cvToHex,
    makeStandardSTXPostCondition,
    FungibleConditionCode,
    callReadOnlyFunction
} from "@stacks/transactions";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we need to install another package in the frontend folder by running &lt;code&gt;npm i @use-it/interval&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That is a custom hook that makes it easy to run a function on a certain interval, we'll get to that in a minute.&lt;/p&gt;

&lt;p&gt;Import that, and let's get building.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import useInterval from "@use-it/interval";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's how we're going to handle getting the message. We're going to set up a callback function to fetch the message corresponding to the logged in user.&lt;/p&gt;

&lt;p&gt;Then we're going to call that function on load and every 30 seconds to check to see if it has changed. Another option would be to use the API's websockets functionality which would give this app a better UX. I leave that as an exercise for the reader.&lt;/p&gt;

&lt;p&gt;Let's add that below the &lt;code&gt;handleSubmit&lt;/code&gt; call to get this going.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const getMessage = useCallback(async () =&amp;gt; {
    if (
        userSession &amp;amp;&amp;amp;
        userSession.isUserSignedIn() &amp;amp;&amp;amp;
        userSession.loadUserData()
    ) {
        const userAddress = userSession.loadUserData().profile.stxAddress.testnet;
        const clarityAddress = standardPrincipalCV(userAddress);
        const options = {
            contractAddress: supContractAddress,
            contractName: supContractName,
            functionName: "get-message",
            network,
            functionArgs: [clarityAddress],
            senderAddress: userAddress,
        };

        const result = await callReadOnlyFunction(options);
        console.log(result);
    }
}, []);

// Run the getMessage function at load to get the message from the contract
useEffect(getMessage, [userSession]);

// Poll the Stacks API every 30 seconds looking for changes
useInterval(getMessage, 30000);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to add a new state variable for storing the posted message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [postedMessage, setPostedMessage] = useState("none");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's a fair amount going on here so let's walk through it.&lt;/p&gt;

&lt;p&gt;The first thing we are doing here is defining a &lt;code&gt;useCallback&lt;/code&gt; hook. If you jump down to the bottom of the code, we are running this function any time the &lt;code&gt;userSession&lt;/code&gt; variable changes and re-running it every 30 seconds.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;getMessage&lt;/code&gt; function itself first checks to see if we are logged in and then sets up our read-only contract call with some options.&lt;/p&gt;

&lt;p&gt;Take a look at the options here. When we are working with Clarity values, we need to do a bit of work to convert the values from the client into a format that Clarity can understand, hence the &lt;code&gt;standardPrincipalCV(userAddress)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you run this all, write a sup, you should see the value being logged to the console as soon as the transaction finishes processing.&lt;/p&gt;

&lt;p&gt;Now we have one more step to go. We're going to actually display the message we have written.&lt;/p&gt;

&lt;p&gt;We're pulling it in, we just need to add some logic to either display it if it exists, or to display some sort of 'not found' message if our smart contract returns &lt;code&gt;none&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we need to change the &lt;code&gt;console.log&lt;/code&gt; statement to set this when our &lt;code&gt;get-message&lt;/code&gt; function finishes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (result.value) {
    setPostedMessage(result.value.data);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Final step: we need to conditionally display the message if it exists.&lt;/p&gt;

&lt;p&gt;Add this right under the closing &lt;code&gt;&amp;lt;/form&amp;gt;&lt;/code&gt; tag. You'll also need to wrap both the form and this new addition in a fragment so React can render it correctly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div className="mt-12"&amp;gt;
    {postedMessage !== "none" ? (
        &amp;lt;p&amp;gt;You said "{postedMessage}"&amp;lt;/p&amp;gt;
    ) : (
        &amp;lt;p&amp;gt;You haven't posted anything yet.&amp;lt;/p&amp;gt;
    )}
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if we write our message and wait a bit for the transaction to process on the local chain and the block to settle, we'll see it display in the UI. Note that this could take a minute or two, you can monitor the progress in the Clarinet console.&lt;/p&gt;

&lt;p&gt;Congratulations! You've just made your first complete, full-stack Stacks app.&lt;/p&gt;

&lt;p&gt;All this code &lt;a href="https://github.com/kenrogers/sup" rel="noopener noreferrer"&gt;lives on GitHub&lt;/a&gt; if you need to compare with anything. This is only the beginning of your Stacks development journey, there's a lot more to learn and a lot more to build.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to Go From Here
&lt;/h2&gt;

&lt;p&gt;You now have a basic Stacks app under your belt. If you are getting started on your Stacks development journey, there are a few things I recommend doing from here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Get plugged in
&lt;/h3&gt;

&lt;p&gt;I highly recommend joining the &lt;a href="https://discord.gg/jKrNqfZW" rel="noopener noreferrer"&gt;Stacks Discord&lt;/a&gt;. You can find me on Discord as kennny#0001 (that's three n's). My DMs and friend requests are open.&lt;/p&gt;

&lt;p&gt;Feel free to tag me in the Stacks Discord or DM me with any questions, feedback, suggestions, or just to say hi.&lt;/p&gt;

&lt;p&gt;I would also love to &lt;a href="https://twitter.com/KenTheRogers" rel="noopener noreferrer"&gt;connect on Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add features
&lt;/h3&gt;

&lt;p&gt;By far the best way to learn is by building things on your own. You've built a solid foundation here and learned the fundamentals, but you need to build on your own to really cement the knowledge.&lt;/p&gt;

&lt;p&gt;Here are a few ideas for features to add to this to further your learning: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Utilize the &lt;code&gt;get-sups&lt;/code&gt; variable and getter we created on the frontend&lt;/li&gt;
&lt;li&gt;Switch to websockets&lt;/li&gt;
&lt;li&gt;Deploy to testnet&lt;/li&gt;
&lt;li&gt;Run your own API node&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Look into these topics and others and remember to reach out if you need any guidance!&lt;/p&gt;

&lt;h3&gt;
  
  
  Further your Clarity knowledge
&lt;/h3&gt;

&lt;p&gt;The Stacks Foundation runs a class called Clarity Universe that teaches you smart contract development with Clarity from the ground up.&lt;/p&gt;

&lt;p&gt;If you are interested in learning more about Clarity, &lt;a href="https://clarity-lang.org/universe" rel="noopener noreferrer"&gt;sign up for the waitlist&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Work on a real project
&lt;/h3&gt;

&lt;p&gt;The Stacks Foundation is interested in funding people building useful things for the Stacks Ecosystem. If you feel ready to use your knowledge to build something for the real world, &lt;a href="https://stacks.org/grants" rel="noopener noreferrer"&gt;apply for a grant&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep learning and practicing
&lt;/h3&gt;

&lt;p&gt;Finally, be sure you continue your journey by learning and building as much as you can. I'm going to be creating lots of content targeted at helping devs build awesome things on Stacks, so if you have any feedback on how to improve this tutorial or suggestions for future content, I would absolutely love it if you reached out on Twitter or Discord.&lt;/p&gt;

</description>
      <category>web3</category>
      <category>blockchain</category>
      <category>stacks</category>
      <category>bitcoin</category>
    </item>
    <item>
      <title>Create &amp; Connect</title>
      <dc:creator>kenny</dc:creator>
      <pubDate>Mon, 23 Aug 2021 22:19:46 +0000</pubDate>
      <link>https://forem.com/krgrs/create-connect-3c83</link>
      <guid>https://forem.com/krgrs/create-connect-3c83</guid>
      <description>&lt;h2&gt;
  
  
  A Simple, Daily System to Launch and Grow a Successful Dev Career
&lt;/h2&gt;

&lt;p&gt;I've recently become obsessed with the compounding effects of small, consistent, daily actions.&lt;/p&gt;

&lt;p&gt;Nowhere is the benefit of this more apparent than in building a personal brand and growing a successful career.&lt;/p&gt;

&lt;p&gt;The world is changing rapidly, traditional credentials no longer carry the weight they once did. The ubiquity of low-cost online sources of information means that a knowledge gap is no longer the main differentiating factor between candidates.&lt;/p&gt;

&lt;p&gt;Anyone can go online, learn extremely valuable tech skills and use those to get a job. Thanks to places like FreeCodeCamp and Hashnode, you don't even need to pay anything in order for this to happen.&lt;/p&gt;

&lt;p&gt;Take a second and really think about how incredible this is.&lt;/p&gt;

&lt;p&gt;We humans tend to take things we currently have for granted, no matter how incredible they may have seemed even in the recent past.&lt;/p&gt;

&lt;p&gt;The massive amount of information available to anyone with an internet connection has created an amazing amount of opportunity for people seeking to launch and grow a career on their own terms.&lt;/p&gt;

&lt;p&gt;But it has also created two major problems in its wake. As is usually the case, our minds have not caught up with technological advances.&lt;/p&gt;

&lt;p&gt;We are still used to having a clear-cut path to follow and wanting that clear-cut path.&lt;/p&gt;

&lt;p&gt;The vast amount of tutorials, courses, and bootcamps has decentralized the learning content, but the tradeoff is that it is now up to us to forge our own path, because it won't be laid out for us.&lt;/p&gt;

&lt;p&gt;Don't get me wrong, this is a good thing, but it is challenging.&lt;/p&gt;

&lt;p&gt;The two problems both stem from this central concept, they are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Figuring out exactly what you should learn and how&lt;/li&gt;
&lt;li&gt; Getting noticed by the people that can move your career forward&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This blog post seeks to provide a simple system that addresses both of these problems. I say simple, but simple does not always mean easy.&lt;/p&gt;

&lt;p&gt;I named this system Create &amp;amp; Connect. It involves two very simple daily actions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Creating and shipping something every day&lt;/li&gt;
&lt;li&gt; Reaching out to one new person every day&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. These two simple actions when compounded daily have life-changing implications when done consistently over time.&lt;/p&gt;

&lt;p&gt;My goal with this article is to give you a gameplan for launching and building a successful career as a developer from scratch, regardless of how busy you are.&lt;/p&gt;

&lt;p&gt;It's broken up into three main parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Why This Works&lt;/li&gt;
&lt;li&gt;  How to Do It&lt;/li&gt;
&lt;li&gt;  A Step-by-Step Plan to Get Started Today&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's do this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Works
&lt;/h2&gt;

&lt;p&gt;There are multiple reasons why this system works, on both an external and internal level.&lt;/p&gt;

&lt;p&gt;What I mean by that is that this system will not only help you establish a personal brand and a presence online while growing your network, but it will also help you to build the kind of discipline and persistence it takes to be able to be the person that ships things.&lt;/p&gt;

&lt;p&gt;The internal, mental changes you will get from this system are as beneficial, if not more so than the external personal branding and network benefits you'll get.&lt;/p&gt;

&lt;p&gt;Consistently creating and shipping things every single day not only build discipline and habits but also will unleash this flood of creativity and help you start doing your best work.&lt;/p&gt;

&lt;p&gt;Creativity is not a gift, it's not a fleeting mood. It's a choice, a habit. The more you create, the more creative you will become.&lt;/p&gt;

&lt;p&gt;Creating every day will build your creativity muscle allowing you to make better stuff and get better at your craft, while simultaneously building your online presence in the process.&lt;/p&gt;

&lt;p&gt;I've mentioned the concepts of an online presence and a network a few times now. I'll get into this in more detail in a future post, but the basic idea is that &lt;strong&gt;building a body of real work and getting that work in front of the right eyes is the best way to build a career you love&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The Create &amp;amp; Connect system allows you to do both.&lt;/p&gt;

&lt;p&gt;This has the added benefit of eliminating decision fatigue and information overload. Your only goal is to complete the system each and every day.&lt;/p&gt;

&lt;p&gt;The long-term goal of building a successful career will take care of itself if you show up every day and get these two things done.&lt;/p&gt;

&lt;p&gt;By forcing yourself to create and ship something every day, you'll build a strong body of work and the discipline necessary to build valuable things even when you don't feel like it.&lt;/p&gt;

&lt;p&gt;By reaching out to the right people every day, you'll build a network of people that can help bring you opportunities and propel your career forward.&lt;/p&gt;

&lt;p&gt;Let's get into the practicalities of how to actually get this done.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Do It
&lt;/h2&gt;

&lt;p&gt;Now we know why it's a good idea to do this stuff every day. Hopefully, you're convinced. If so, let's get into how to actually go about doing these things.&lt;/p&gt;

&lt;p&gt;Please don't overcomplicate this. Just start and take action, today. Don't get hung up on questioning everything and making everything perfect. There lies madness.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create
&lt;/h3&gt;

&lt;p&gt;What exactly do we mean when we say "create"? All I really mean by this is creating something that did not exist before and making it publicly accessible.&lt;/p&gt;

&lt;p&gt;For developers, this is mainly going to mean content and code.&lt;/p&gt;

&lt;p&gt;So your goal for the "create" part of the system is to build and ship either a piece of a project or a piece of content every day.&lt;/p&gt;

&lt;p&gt;For the code part, you'll need a GitHub account if you don't have one. In order for it to count, you need to be deploying something substantial to a GitHub repo. This could be a new feature, a bug fix, or even clarifying something in a README.&lt;/p&gt;

&lt;p&gt;The other form of creating is publishing content.&lt;/p&gt;

&lt;p&gt;The lowest barrier-to-entry method of doing this, by far, is creating a blog on  &lt;a href="https://hashnode.com"&gt;Hashnode&lt;/a&gt; . This is actually my first post on Hashnode, and I'm kicking myself for not getting set up on this platform sooner.&lt;/p&gt;

&lt;p&gt;It allows you to get your own blog up and running in minutes, and you can even hook it up to a custom domain, all for free.&lt;/p&gt;

&lt;p&gt;If in doubt, start here.&lt;/p&gt;

&lt;p&gt;However, you can also start a YouTube channel or a podcast if those formats are more your thing. I can't provide any insight there since I've done neither.&lt;/p&gt;

&lt;p&gt;So every day you should either be shipping code or content, ideally both if you have the time.&lt;/p&gt;

&lt;p&gt;Your next question is likely to be what exactly you should be making or writing about. Unfortunately, there's no easy answer here.&lt;/p&gt;

&lt;p&gt;This is where most people get tripped up and fail. They either never start because they get overwhelmed with making a decision, or they give up after a few days.&lt;/p&gt;

&lt;p&gt;Don't let that be you.&lt;/p&gt;

&lt;p&gt;Remember, one of the main benefits of this daily habit is that it will steadily grow your creativity and your ability to ship over time. It will not be perfect or even necessarily very good in the beginning.&lt;/p&gt;

&lt;p&gt;That's okay. The goal is to show up and ship every day.&lt;/p&gt;

&lt;p&gt;I don't want to leave you hanging, so I'll provide a sample plan and idea for your first post in the step-by-step plan section below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect
&lt;/h3&gt;

&lt;p&gt;So you're creating something every day, now let's talk about getting in touch and connecting with someone new every day.&lt;/p&gt;

&lt;p&gt;This one was a game-changer for me. Like a lot of developers, I'm an introvert, and the idea of networking makes me want to vomit. That's why we're not doing anything like that here.&lt;/p&gt;

&lt;p&gt;All we are doing is reaching out to people we genuinely admire, telling them why we do and introducing ourselves. That's it.&lt;/p&gt;

&lt;p&gt;This simple method is how I got my first job as a developer with no experience. I had a body of work because I had been creating every day, and I started reaching out to people whose work I admired introducing myself.&lt;/p&gt;

&lt;p&gt;Again, don't overcomplicate this.&lt;/p&gt;

&lt;p&gt;This involves an ongoing process and a daily routine.&lt;/p&gt;

&lt;p&gt;The ongoing process is gathering a list of people as you go through your day that you admire. As you read content and come across interesting projects, keep a file of people and companies you would like to work for.&lt;/p&gt;

&lt;p&gt;You can do this in a simple spreadsheet with the following columns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Name&lt;/li&gt;
&lt;li&gt;  Company&lt;/li&gt;
&lt;li&gt;  Reason you admire them&lt;/li&gt;
&lt;li&gt;  Contact Date&lt;/li&gt;
&lt;li&gt;  Answered Date&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep it simple.&lt;/p&gt;

&lt;p&gt;Every time you come across someone whose work you admire and who you think you might like to work for, add them to this list.&lt;/p&gt;

&lt;p&gt;Then, every day, choose one person from the list, find their email, and send them a simple, short email telling them what you specifically admire about their work and introducing yourself, what you are working on, and what your goals are.&lt;/p&gt;

&lt;p&gt;Don't be sleazy about this. I see a lot of advice out there to just initiate a conversation or provide a compliment and then follow up later with what you really want.&lt;/p&gt;

&lt;p&gt;I don't like that approach.&lt;/p&gt;

&lt;p&gt;Be direct. Networking is only sleazy because people try to pretend it's something it's not.&lt;/p&gt;

&lt;p&gt;In this email you want to accomplish a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Make sure the person knows this email was written specifically for them&lt;/li&gt;
&lt;li&gt;  Provide a genuine reason why you are interested in them&lt;/li&gt;
&lt;li&gt;  Tell them about what your goals are and why that relates to your interest in them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's look at an example. Let's say I'm just beginning my development journey and have been really interested in building UIs in React. I've created quite a few things and have written a few blog posts on Hashnode about it.&lt;/p&gt;

&lt;p&gt;I come across a company that says they use React in their front end. I really like what the company does and I think it would be cool to work for them, so I decide to find the contact information of the founder, Chris, and reach out.&lt;/p&gt;

&lt;p&gt;Note that it doesn't always have to be, and in some cases shouldn't be, the founder. If the company is larger, you may be better off reaching out to another developer or manager rather than a founder or C-level exec. Use your judgment here.&lt;/p&gt;

&lt;p&gt;I use  &lt;a href="https://hunter.io"&gt;Hunter&lt;/a&gt;  to find his email address and write the following:&lt;/p&gt;

&lt;p&gt;*Hi Chris,&lt;/p&gt;

&lt;p&gt;My name is Kenny. You don't know me but I'm a React developer and wanted to reach out to let you know how awesome I think Acme is.&lt;/p&gt;

&lt;p&gt;I recently read your post on why the NFT ecosystem is blowing up and how Acme is playing a role in that and thought it was really interesting. The fact that Acme provides a platform for non-technical people to get into the world of NFTs is huge and will play a big role in making blockchain accessible to more people.&lt;/p&gt;

&lt;p&gt;I've been building a lot in React and noticed that the frontend of your platform is built with React. I'm just getting started in my dev journey but am looking to meet people I'd love to work for.&lt;/p&gt;

&lt;p&gt;You seem like one of those people.&lt;/p&gt;

&lt;p&gt;Do you have any room on your team for an eager-to-learn React developer to help you build out an amazing UI for Acme?&lt;/p&gt;

&lt;p&gt;I'd absolutely love to work for you. You can check out some of my work on GitHub and my writing on my blog to get to know me better.&lt;/p&gt;

&lt;p&gt;Looking forward to hearing from you!&lt;/p&gt;

&lt;p&gt;Kenny*&lt;/p&gt;

&lt;p&gt;Simple. Honest. Direct.&lt;/p&gt;

&lt;p&gt;Those are the key elements you want to hit when sending out emails like this. Something very similar to this led to my first job.&lt;/p&gt;

&lt;p&gt;Keep in mind that the goal of these emails is not necessarily to get hired, although that is certainly possible and would be awesome.&lt;/p&gt;

&lt;p&gt;The main goal is to get on peoples' radar and start meeting people so that even if now is not a good time and you are not a good fit for them, you are on their mind when that changes, or they can refer you to others who you might be a better fit for.&lt;/p&gt;

&lt;p&gt;If you want to really blow them out of the water, build a small custom project just for them and send it over. I recommend taking a look at &lt;a href="https://crash.co"&gt;Crash&lt;/a&gt; for more on that.&lt;/p&gt;

&lt;p&gt;Now that you know why this works and how to do it, let's go over a sample daily plan you can use to get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Step-by-Step Plan
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Get Your Foundation Set Up
&lt;/h3&gt;

&lt;p&gt;If you don't already have a &lt;a href="https://github.com"&gt;GitHub&lt;/a&gt; and &lt;a href="https://hashnode.com"&gt;Hashnode&lt;/a&gt; account (or another public blog) set up, do that now. If you prefer to use YouTube or a podcast, get that set up.&lt;/p&gt;

&lt;p&gt;You need to have a foundation to build on before you start building.&lt;/p&gt;

&lt;h3&gt;
  
  
  Block Out Time
&lt;/h3&gt;

&lt;p&gt;This part is usually overlooked but super important. Block out time to do these things on your calendar and stick to it every day.&lt;/p&gt;

&lt;p&gt;I recommend an hour per day if you are able, but do what you can with your particular schedule.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Something
&lt;/h3&gt;

&lt;p&gt;My favorite way of creating things is by following a course or tutorial and then creating something unique on my own using the same concept.&lt;/p&gt;

&lt;p&gt;So find a course or tutorial you like, follow along to learn the basics, then build something on your own that utilizes the same concepts.&lt;/p&gt;

&lt;p&gt;This is how you'll learn the best and what will stand out most in your portfolio.&lt;/p&gt;

&lt;p&gt;This is your task for the first day.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write Something
&lt;/h3&gt;

&lt;p&gt;Now that you made something, write about it! Take what you just made and walk people through how you did it, lessons learned, challenges overcome, etc.&lt;/p&gt;

&lt;p&gt;Your only goal is to share what you are learning and working on. You don't have to pretend to be an authority on something if you aren't. Focus on learning and building in public.&lt;/p&gt;

&lt;p&gt;You can continue with this alternating creating and writing if it works for you, or you can write as you go and ship code and a blog post on the same day.&lt;/p&gt;

&lt;p&gt;Experiment with both to see what works best for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start Your List
&lt;/h3&gt;

&lt;p&gt;As you go through your day and read content and interact with people, start developing that list of people to contact we talked about earlier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write Your First Email
&lt;/h3&gt;

&lt;p&gt;Now take one of those people and write your first email using the template I gave you above. Be sure to modify it to suit your communication style.&lt;/p&gt;

&lt;p&gt;That's it. You now have a blueprint for building a successful dev career.&lt;/p&gt;

&lt;p&gt;Please don't overthink this. The most important thing is to actually take action and do something. Yes, it will be hard and uncomfortable, anything worth doing always is.&lt;/p&gt;

&lt;p&gt;But the more you do it the easier it gets, the better you'll be at it, and the more opportunities will come your way.&lt;/p&gt;




&lt;p&gt;My name is Kenny. I write in-depth, practical guides on JavaScript development and building a fulfilling career as a developer.&lt;/p&gt;

&lt;p&gt;Read more of my stuff and get notified whenever I write something new at my personal site: &lt;a href="https://krgrs.dev"&gt;krgrs.dev&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Mastering the Mental Aspect of Learning to Code and Getting Hired</title>
      <dc:creator>kenny</dc:creator>
      <pubDate>Fri, 15 Jan 2021 19:27:46 +0000</pubDate>
      <link>https://forem.com/krgrs/mastering-the-mental-aspect-of-learning-to-code-and-getting-hired-4o45</link>
      <guid>https://forem.com/krgrs/mastering-the-mental-aspect-of-learning-to-code-and-getting-hired-4o45</guid>
      <description>&lt;p&gt;I've been talking to a lot of aspiring developers lately about their biggest struggles with getting their first jobs.&lt;/p&gt;

&lt;p&gt;In those conversations, I've heard a lot about people struggling with the mental side of learning to code and leveraging that knowledge into a job.&lt;/p&gt;

&lt;p&gt;Things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How do I know when I've learned enough?&lt;/li&gt;
&lt;li&gt;I'm struggling with the confidence to know that I'm ready&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our minds are complicated beasts, and mindset struggles like these are very common.&lt;/p&gt;

&lt;p&gt;Rather than give a concrete answer to these questions, I want to talk about shifting the way you view web development itself, as well as the process of launching and building a career in a way that will potentially make the questions themselves irrelevant.&lt;/p&gt;

&lt;p&gt;One, because I don't think there is a concrete straightforward answer to this. Mindset issues are tough because we all have our own experiences, personality traits, and biases that lead us to believe certain things.&lt;/p&gt;

&lt;p&gt;And two, because shifting the way you view the development industry and the job-hunting process will have far-reaching positive side-effects to the way you go about launching and growing your career.&lt;/p&gt;

&lt;p&gt;For some people, these questions are stemming from a confidence issue of not feeling ready enough, for others they are coming from a place of just genuinely not knowing when the right time to start looking for jobs is.&lt;/p&gt;

&lt;p&gt;I think for most it's probably a combination of both, which then feed off of each other and can cause all kinds of doubt and anxiety to creep in.&lt;/p&gt;

&lt;p&gt;Add in getting rejected or ghosted by employers, and you have a recipe for immense frustration.&lt;/p&gt;

&lt;p&gt;So what can we do about this? Let's talk about a few mental shifts and then get into some of the practical things you can do to address these issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn to accept what you cannot control while maximizing what you can control
&lt;/h2&gt;

&lt;p&gt;Rejection is inevitable on the road to your first job. There are certain things that are just outside of our control.&lt;/p&gt;

&lt;p&gt;Two people may follow the exact same process to get hired and for one person it may take a week and for another, it may take 6 months.&lt;/p&gt;

&lt;p&gt;Don't waste energy focusing on the things that are outside of your control, instead focus on the parts you can control, stick to them consistently, and make that your measure of success.&lt;/p&gt;

&lt;p&gt;For example, you cannot control exactly who will read your resume, what their biases are, what kind of mood they are in, who else has already applied to the job, what order they see your resume in, and countless other little things that all go into effect in a hiring process.&lt;/p&gt;

&lt;p&gt;But you can control maximizing your online presence so as many people see you as possible, you can control optimizing that presence and your resume to give yourself the best chance of standing out, you can create a compelling portfolio so when someone comes across it, you convince them of your skills.&lt;/p&gt;

&lt;p&gt;Getting a job is this balancing act between luck and action. Yes, luck plays a factor in almost everything, but you can drastically influence the amount of luck that comes your way by taking action on smart strategies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand that coding is a never-ending process of learning for everyone
&lt;/h2&gt;

&lt;p&gt;Nobody has achieved mastery of coding. As soon as you think you have, you stop learning. Embrace being a lifelong learner.&lt;/p&gt;

&lt;p&gt;Not only is this the way to make sure you continue improving and continue learning, but it's the most impressive attitude to have for potential employers, especially at entry-level jobs.&lt;/p&gt;

&lt;p&gt;Employers will of course expect some level of technical skill, and having experience can definitely help demonstrate that.&lt;/p&gt;

&lt;p&gt;But every single employer I've talked to has said that for a junior dev, personality traits like enthusiasm and being willing and eager to learn and be coached are as important, if not more so, than technical skill.&lt;/p&gt;

&lt;p&gt;Embrace your newness by becoming a lifelong learner. Whenever you feel inadequate in your code, remember a few things.&lt;/p&gt;

&lt;p&gt;Everyone (and I mean everyone) feels that way sometimes, even people who have been doing it for years.&lt;/p&gt;

&lt;p&gt;I've been coding in JS for 6 years professionally, not a ton of time but a decent amount, and I still have to Google stuff every day, and still feel totally inadequate when I read and watch some tutorials and courses online.&lt;/p&gt;

&lt;p&gt;Know that those polished tutorials you watch and read and courses came with tons of preparation, frustration, Googling error messages, asking questions, and self-doubt.&lt;/p&gt;

&lt;p&gt;Imposter syndrome is a sign that you know you still have a lot to learn. Temper that self-doubt with the confidence that comes from putting in the work and meet in the middle at humility. As long as you are honest and continually working on improving, you're good and you are not an imposter.&lt;/p&gt;

&lt;p&gt;So when you think that you don't know enough to start applying for jobs or are trying to wait for that magic moment when you feel confident enough to do a certain thing, know that it will likely never come.&lt;/p&gt;

&lt;p&gt;You have to take action before you feel ready in order to develop confidence, more on this below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand that a job hunt should be a continual process, not a set of concrete stages
&lt;/h2&gt;

&lt;p&gt;A lot of people see the road to landing a job as a step-by-step progression where each stage is separate and one can only be started one the previous stage is finished:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Learn to code&lt;/li&gt;
&lt;li&gt;Start applying&lt;/li&gt;
&lt;li&gt;Get a job&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I think this is where a lot of the "how do I know if I know enough?" questions stem from.&lt;/p&gt;

&lt;p&gt;But let's look at this a little differently. Instead of viewing this process as a set of separate stages, look at it all as one continuous process that you are always working through.&lt;/p&gt;

&lt;p&gt;So instead of learning and then applying until you find a job, you should be learning, building your portfolio, writing content, networking, and applying all at the same time, continuously.&lt;/p&gt;

&lt;p&gt;That sounds like doing too many things at once, but each of these things can work together and help the others.&lt;/p&gt;

&lt;p&gt;Here's what I mean.&lt;/p&gt;

&lt;p&gt;Going through tutorials is great, but you are really only learning when you build something on your own, building something on your own also allows you to build up an effective portfolio that will stand out to employers.&lt;/p&gt;

&lt;p&gt;Writing about what you are building not only helps you be more intentional in what you are learning and doing, it can also help cement what you are learning into your brain, and it adds another valuable signal to your online presence.&lt;/p&gt;

&lt;p&gt;Finally, connecting with others and showing them what you are working on can provide helpful feedback on your work while also growing your visibility.&lt;/p&gt;

&lt;p&gt;These things can all be done together as part of a system of daily and weekly actions that you complete. For an example of how to set up this system, refer to an article I recently wrote for FreeCodeCamp, &lt;a href="https://www.freecodecamp.org/news/how-to-become-a-professional-developer/"&gt;How to Get a Job as a Professional Developer in 2021&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The main thing I want you to understand is that getting hired is not usually as simple as hitting a point of being "ready" or knowing "enough" and then starting to apply.&lt;/p&gt;

&lt;p&gt;It's a continuous process of learning, building, and networking so that more and more people can find you and be impressed when they do.&lt;/p&gt;

&lt;p&gt;Sending in applications is a part of this, but it is only a part and should be coupled with consistently learning, building, and networking.&lt;/p&gt;

&lt;p&gt;But how can I start applying for jobs and networking if I am just getting started?&lt;/p&gt;

&lt;p&gt;Applying for jobs and networking are not necessarily the same thing. You can be reaching out to people in the industry, building relationships immediately, even when all you are learning is HTML and CSS.&lt;/p&gt;

&lt;p&gt;Building a network and online presence is something you should start doing immediately, as soon as you start learning.&lt;/p&gt;

&lt;p&gt;Commit to writing one post per week going over what you are currently working on. Go over it from the perspective of someone teaching it.&lt;/p&gt;

&lt;p&gt;Reach out to one new person each day introducing yourself. See Reach Out by Molly Beck for more information on how to do this right.&lt;/p&gt;

&lt;p&gt;Then, I would start applying to jobs once you have a portfolio of one or two complete projects that solve real, unique problems.&lt;/p&gt;

&lt;p&gt;What I mean is make something that does not yet exist and that you did not make by following a tutorial or course.&lt;/p&gt;

&lt;p&gt;This thing should solve a real problem that you or someone else has, and it should be complete and usable.&lt;/p&gt;

&lt;p&gt;Having complete projects shows that you are capable of building something from start to finish and that you understand the development cycle as a whole.&lt;/p&gt;

&lt;p&gt;Finally, confidence is not something that you can achieve by just thinking differently.&lt;/p&gt;

&lt;p&gt;Confidence is earned by repeatedly showing up and doing the work.&lt;/p&gt;

&lt;p&gt;This is harder in the beginning because we have to take leaps of faith and take action without the confidence present.&lt;/p&gt;

&lt;p&gt;But over time, as you continue to learn, continue to build, and continue to meet more people, your confidence will grow naturally.&lt;/p&gt;

&lt;p&gt;Don't get me wrong, you will still occasionally struggle with imposter syndrome, we all do, but it will begin to happen less and less the more you do great work and get feedback on that great work so that you can continue to improve.&lt;/p&gt;

&lt;p&gt;The only way you could be an imposter is if you do one of two extremes.&lt;/p&gt;

&lt;p&gt;You flat out lie about your experience and abilities. But this is easily avoided by creating real things and pointing to them, letting your work and writing do the skill-demonstration for you.&lt;/p&gt;

&lt;p&gt;The other way is if you get overconfident and think that you have little or nothing left to learn. Ironically, if you feel like you are an imposter, that's a big sign on its own that you are not because you are aware of how much you still have left to learn.&lt;/p&gt;

&lt;p&gt;Mastering the mental side of becoming a developer is not something that will happen overnight, and it's not something that will happen without taking action.&lt;/p&gt;

&lt;p&gt;Confidence comes from consistent action towards your goals. The best actions to take are building things that solve real problems, writing about those things, and building a network of people that can bring you opportunities.&lt;/p&gt;

&lt;p&gt;If you would like a detailed, step-by-step walkthrough of exactly how to go about setting up an online presence, building real things, and networking, along with a community of myself and other developers to support and mentor you along the way, I think you'll like my course and mentoring group, &lt;a href="https://gum.co/lever"&gt;Lever&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also &lt;a href="https://twitter.com/KenTheRogers"&gt;follow me on Twitter&lt;/a&gt; for more tips and advice on building a successful dev career.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Self-taught devs: what's keeping you from landing your first job?</title>
      <dc:creator>kenny</dc:creator>
      <pubDate>Mon, 14 Dec 2020 20:35:49 +0000</pubDate>
      <link>https://forem.com/krgrs/self-taught-devs-what-s-keeping-you-from-landing-your-first-job-j89</link>
      <guid>https://forem.com/krgrs/self-taught-devs-what-s-keeping-you-from-landing-your-first-job-j89</guid>
      <description>&lt;p&gt;For all the self-taught developers here that have not been able to get jobs yet, I'm curious: what is your biggest obstacle to landing that first job?&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Looking for a few aspiring developers for a career strategy session</title>
      <dc:creator>kenny</dc:creator>
      <pubDate>Mon, 14 Dec 2020 20:28:59 +0000</pubDate>
      <link>https://forem.com/krgrs/looking-for-a-few-aspiring-developers-for-a-career-strategy-session-7lm</link>
      <guid>https://forem.com/krgrs/looking-for-a-few-aspiring-developers-for-a-career-strategy-session-7lm</guid>
      <description>&lt;p&gt;Hey there!&lt;/p&gt;

&lt;p&gt;I'm looking for a few aspiring self-taught developers that are struggling to get their first jobs.&lt;/p&gt;

&lt;p&gt;For the last few years, I've been working on a process for self-taught developers to build credibility and land a job without previous experience.&lt;/p&gt;

&lt;p&gt;The process is simple but extremely effective, and I'm looking for a few highly motivated self-taught developers to share it with.&lt;/p&gt;

&lt;p&gt;If you're interested, send me an email at &lt;a href="mailto:ken@kenrogers.co"&gt;ken@kenrogers.co&lt;/a&gt; and we can set up a video chat to go over how it works. Should only take about 10 minutes to go over everything.&lt;/p&gt;

&lt;p&gt;Thanks!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Getting Your First Job as a Self-taught Developer</title>
      <dc:creator>kenny</dc:creator>
      <pubDate>Mon, 07 Dec 2020 22:13:50 +0000</pubDate>
      <link>https://forem.com/krgrs/getting-your-first-job-as-a-self-taught-developer-3ek5</link>
      <guid>https://forem.com/krgrs/getting-your-first-job-as-a-self-taught-developer-3ek5</guid>
      <description>&lt;p&gt;Back in 2014, I got my first job as a junior developer with no formal education and no experience. You can read the full story if you're interested.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;div class="ltag__link__content"&gt;
    &lt;div class="missing"&gt;
      &lt;h2&gt;Article No Longer Available&lt;/h2&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;But this post isn't about my story, it's about yours.&lt;/p&gt;

&lt;p&gt;If you are a self-taught developer struggling to land that first job, stuck in an endless river of applications, resumes, and rejections, this post will give you a roadmap to building credibility, a real-world portfolio, a valuable network, and ultimately, getting that first job.&lt;/p&gt;

&lt;p&gt;This post is going to be a minimum effective dose kind of article. &lt;/p&gt;

&lt;p&gt;I took everything I know about how myself and others have gotten their first jobs and distilled it down into a simple, actionable process.&lt;/p&gt;

&lt;p&gt;If you take what you learn here and actually apply it, I am very confident you will launch and grow a successful career as a developer.&lt;/p&gt;

&lt;p&gt;You can read what I've written here, take a few hours to implement it, and have a complete system in place for getting a great job, and be miles ahead of other people that will continue to send their applications and resumes off into the abyss.&lt;/p&gt;

&lt;p&gt;It will be broken up into 7 parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Changing your mindset&lt;/li&gt;
&lt;li&gt;Establishing your online presence&lt;/li&gt;
&lt;li&gt;Building a real-world portfolio&lt;/li&gt;
&lt;li&gt;Writing your first post&lt;/li&gt;
&lt;li&gt;Building a solid network&lt;/li&gt;
&lt;li&gt;Creating a system&lt;/li&gt;
&lt;li&gt;Growing from here&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's get into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Changing your mindset
&lt;/h2&gt;

&lt;p&gt;First, I want to tell you a few things that might take a bit of adjustment to your worldview.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sending out applications to as many companies as possible is not the best way to get a job.&lt;/li&gt;
&lt;li&gt;You do not need existing experience or credentials to get a great job&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me explain why I believe these things and hopefully convince you of the same.&lt;/p&gt;

&lt;p&gt;First, in regards to sending out applications.&lt;/p&gt;

&lt;p&gt;Just because job boards exist and there are lots of jobs on those boards, does not mean they are the only places to find jobs.&lt;/p&gt;

&lt;p&gt;They are the most obviously visible place to find jobs, but that's about it.&lt;/p&gt;

&lt;p&gt;There are countless other positions waiting to be filled that will never be advertised publically or posted on a website.&lt;/p&gt;

&lt;p&gt;In his &lt;a href="https://www.joshwcomeau.com/career/no-cs-degree-required/"&gt;post on getting a dev job without a degree&lt;/a&gt;, Josh Comeau notes that only 15% of the developers he polled got their job through the traditional application/job board process.&lt;/p&gt;

&lt;p&gt;While this is technically just anecdotal evidence, it lines up with my own experience and the experience of most of the developers I know.&lt;/p&gt;

&lt;p&gt;The methods in which a company goes about hiring say a lot about their priorities and values.&lt;/p&gt;

&lt;p&gt;Smaller, "startup-style" companies that value innovation and efficiently solving problems over tradition and corporate structures tend to treat hiring developers in alignment with those values.&lt;/p&gt;

&lt;p&gt;They will often not post jobs and look for talented developers through social media or their network.&lt;/p&gt;

&lt;p&gt;Your goal is to be a part of that network and build up the skills necessary to impress them when they do find you or you find them.&lt;/p&gt;

&lt;p&gt;Now on to the credentials issue.&lt;/p&gt;

&lt;p&gt;Let's look at what value a degree or existing experience actually has for an employer, and see if there is a way we can replicate that value as self-taught developers without those things.&lt;/p&gt;

&lt;p&gt;All hiring decisions are risk assessments:&lt;/p&gt;

&lt;p&gt;"Will hiring this person bring more value (both monetarily and culturally) to the company than it will cost to hire them?"&lt;/p&gt;

&lt;p&gt;If the answer to that question is yes to a higher degree than all other candidates, an offer is made.&lt;/p&gt;

&lt;p&gt;Degrees and existing experience are signals to employers that tilt the scales in your favor in that risk assessment.&lt;/p&gt;

&lt;p&gt;Degrees as signals are becoming less valuable every year. And experience can easily be replicated by taking the initiative to solve problems into your own hands.&lt;/p&gt;

&lt;p&gt;When you combine that with the cultural signal you can send by writing, learning in public, and actively reaching out to new people, you can create a risk-minimizing signal stronger than both a degree and existing experience.&lt;/p&gt;

&lt;p&gt;That process is what we'll be covering throughout this guide and what I cover in detail in &lt;a href="https://kenrogers.co/cc"&gt;Create &amp;amp; Connect&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Establishing your online presence
&lt;/h2&gt;

&lt;p&gt;The first step in creating these signals is to build up a presence online.&lt;/p&gt;

&lt;p&gt;If employers can’t find you, they can’t hire you.&lt;/p&gt;

&lt;p&gt;If your online presence online is contained in the faceless resume and applications you send to companies you are at an extreme disadvantage.&lt;/p&gt;

&lt;p&gt;You don’t necessarily need a website at first, although I definitely recommend creating one at some point.&lt;/p&gt;

&lt;p&gt;For now, a profile at these three websites is a great starting point:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dev&lt;/li&gt;
&lt;li&gt;LinkedIn&lt;/li&gt;
&lt;li&gt;GitHub&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Be sure to fill it out with a relevant bio and a good headshot.&lt;/p&gt;

&lt;p&gt;These three sites will serve as your bases of operations for writing, showing off your code skills, and networking, respectively.&lt;/p&gt;

&lt;p&gt;We’ll cover each of these three components next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a real-world portfolio
&lt;/h2&gt;

&lt;p&gt;Now that you have a basic online presence set up, it’s time to actually use it and fill it with relevant information about what you can do.&lt;/p&gt;

&lt;p&gt;A major mistake I see new and aspiring developers making is only having toy apps or apps made by following tutorials and courses.&lt;/p&gt;

&lt;p&gt;If you want to establish credibility and send a strong signal to employers, you need to show that you can solve real problems.&lt;/p&gt;

&lt;p&gt;You aren’t ultimately paid as a developer to write code. You are paid to solve problems using code as the mechanism.&lt;/p&gt;

&lt;p&gt;So fill your portfolio with real projects that solve real problems.&lt;/p&gt;

&lt;p&gt;Think about problems you face in your own life that could be wolves with code, then build something to solve them.&lt;/p&gt;

&lt;p&gt;If you can’t think of any, ask people you know what their problems are and solve those.&lt;/p&gt;

&lt;p&gt;If you want to be a real overachiever, make a list of companies you want to work for, build something for them, and then reach out to them expressing your interest in working for them and show them what you made.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing your first post
&lt;/h2&gt;

&lt;p&gt;Writing is one of the most powerful things you can do for your career, especially if you are new to the game.&lt;/p&gt;

&lt;p&gt;I credit writing as one of the primary reasons I have the job I do now.&lt;/p&gt;

&lt;p&gt;It allows you to communicate your thought and problem-solving process and serves as a living portfolio and a constantly evolving record of your work and growth.&lt;/p&gt;

&lt;p&gt;One of the biggest hurdles people run into is not knowing what to write about.&lt;/p&gt;

&lt;p&gt;Fortunately, this problem is easily solved because of our real world projects.&lt;/p&gt;

&lt;p&gt;Just write about the process of building it as if you are teaching someone.&lt;/p&gt;

&lt;p&gt;So you can start a new series for each new project you create and go over what you did to build it and why.&lt;/p&gt;

&lt;p&gt;Use a platform like Dev to write these. It’s extremely easy to use and has an active, engaged community.&lt;/p&gt;

&lt;p&gt;Plus you can easily integrate it with a static site generator and have your posts automatically populate using Stackbit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a solid network
&lt;/h2&gt;

&lt;p&gt;Alright, you’ve got your portfolio in the works and you’ve started writing.&lt;/p&gt;

&lt;p&gt;The third piece of the puzzle is actively reaching out and building relationships with people.&lt;/p&gt;

&lt;p&gt;There are three groups of people I recommend doing this with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recruiters&lt;/li&gt;
&lt;li&gt;Potential employers&lt;/li&gt;
&lt;li&gt;Fellow developers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This doesn’t have to be complicated. Just be a genuine person who wants to build real relationships with people.&lt;/p&gt;

&lt;p&gt;I got my first developer job by emailing local development shops introducing myself, saying I was an aspiring developer and wanted to meet some shops in town, and linking to my GitHub profile and my favorite project.&lt;/p&gt;

&lt;p&gt;Use LinkedIn, Google, and social media to start reaching out to people and introducing yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a system
&lt;/h2&gt;

&lt;p&gt;This is all well and good but it can be a bit overwhelming to try and tackle all of this.&lt;/p&gt;

&lt;p&gt;It might seem easier to create your resume and have the same information on hand to fill out a hundred applications.&lt;/p&gt;

&lt;p&gt;But that way lies madness.&lt;/p&gt;

&lt;p&gt;The steps I’ve outlined here can be streamlined into a system of small daily actions you can take to progress your career.&lt;/p&gt;

&lt;p&gt;The important thing is to block out time in your calendar for each component.&lt;/p&gt;

&lt;p&gt;So every day block out as much time as you can for creating, writing, and connecting.&lt;/p&gt;

&lt;p&gt;Then focus on that one thing during that time.&lt;/p&gt;

&lt;p&gt;Create a recurring time block in your calendar and commit to that thing each day.&lt;/p&gt;

&lt;p&gt;Over time these times blocks will add up and if you focus on completing those actions each day as your measure of success, you will quickly build up a solid portfolio of work and writing and a valuable network.&lt;/p&gt;

&lt;p&gt;It can be as small as reaching out to one new person per day, coding your project for 30 minutes, and writing about what you did for 15 minutes.&lt;/p&gt;

&lt;p&gt;You write Monday through Thursday and edit and post on Friday.&lt;/p&gt;

&lt;p&gt;The takeaway is to figure out what schedule works for you, block time out to do it, and stick to it consistently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Growing from here
&lt;/h2&gt;

&lt;p&gt;These actions might seem small and simple but they can form the foundation for the rest of your career.&lt;/p&gt;

&lt;p&gt;If you commit to doing these things consistently then over time you will build an incredibly valuable reputation in the industry and won’t have to worry about finding work.&lt;/p&gt;

&lt;p&gt;Over time you can adjust your strategy and focus as you find what works, but for right now the important thing is to just start.&lt;/p&gt;

&lt;p&gt;If you follow what I’ve outlined here you will have a successful career.&lt;/p&gt;

&lt;p&gt;My goal is to help 1,000 developers get hired in 2021. Here's how you can be a part of that 👉🏻 &lt;a href="https://gum.co/launchyourdevcareer"&gt;Launch Your Dev Career&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If I had to start my career from scratch, this is exactly what I would do to land my first job.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Every developer should write. Here's how to get started</title>
      <dc:creator>kenny</dc:creator>
      <pubDate>Wed, 25 Nov 2020 01:34:00 +0000</pubDate>
      <link>https://forem.com/krgrs/every-developer-should-write-here-s-how-to-get-started-atomic-dev-tips-3koh</link>
      <guid>https://forem.com/krgrs/every-developer-should-write-here-s-how-to-get-started-atomic-dev-tips-3koh</guid>
      <description>&lt;p&gt;Writing is one of the most impactful, high-leverage things I have ever done for my career.&lt;/p&gt;

&lt;p&gt;Writing has three main benefits that have made a big difference in my life and career:&lt;/p&gt;

&lt;h2&gt;
  
  
  It helps me solidify and ensures I understand my ideas and processes
&lt;/h2&gt;

&lt;p&gt;There is something about writing that forces you to really process and articulate abstract ideas you may have floating around in your head.&lt;/p&gt;

&lt;p&gt;When you go through the process of writing about something, you really have to think through what you are actually trying to say to make sure the reader can understand it.&lt;/p&gt;

&lt;p&gt;This process leads to increased clarity for yourself along with the reader.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demonstrates your skillset and problem-solving process
&lt;/h2&gt;

&lt;p&gt;Portfolios are great, but they can sometimes suffer because they are static ways of demonstrating your work.&lt;/p&gt;

&lt;p&gt;When you write alongside building things, it gives people a glimpse into your thought and problem-solving process, which can make your portfolio projects much more dynamic, engaging, and goes a long way towards communicating your value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Communicates your values and cultural fit to potential employers
&lt;/h2&gt;

&lt;p&gt;Finally, possibly my favorite benefit and often the most overlooked.&lt;/p&gt;

&lt;p&gt;Writing can communicate your values to employers which can help them in determining whether or not you would be a good fit culturally within their company.&lt;/p&gt;

&lt;p&gt;Though not talked bout as often, this component of career growth is often as important as technical skills.&lt;/p&gt;

&lt;p&gt;By communicating your personality and values in your writing, you give people a look at who you are, what makes you tick, and what is important to you.&lt;/p&gt;

&lt;p&gt;It allows people you have never met to get to know a little more, which can be extremely helpful when job hunting.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to get started writing
&lt;/h2&gt;

&lt;p&gt;Okay great, writing can help your career, but getting started can seem like a big hurdle.&lt;/p&gt;

&lt;p&gt;Here's an easy way you can get started in the next 30 minutes with your first post.&lt;/p&gt;

&lt;p&gt;First, create an account and fill out all the information here on Dev. This is an awesome place to start writing with a low barrier to actually getting started.&lt;/p&gt;

&lt;p&gt;Next, start a new post and write about your story up until now and where you want to go as a developer.&lt;/p&gt;

&lt;p&gt;Talk about where you came from, what other jobs you've had, why you want to be a developer, and what you've done so far to make that happen.&lt;/p&gt;

&lt;p&gt;Then post it.&lt;/p&gt;

&lt;p&gt;This is not meant to be read by thousands of people, it's not meant to be the best piece of writing you'll ever do.&lt;/p&gt;

&lt;p&gt;It's meant to be the first piece of writing. The initial hurdle to jump.&lt;/p&gt;

&lt;p&gt;Posting publicly is very important. &lt;/p&gt;

&lt;p&gt;Put yourself out there. It's a fantastic way to grow.&lt;/p&gt;

&lt;p&gt;After you write that post, comment here with a link to it so I can check it out!&lt;/p&gt;

&lt;p&gt;Looking to land your first job as a developer? You may like my course and mentoring group, &lt;a href="https://gum.co/launchyourdevcareer"&gt;Launch Your Dev Career&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also &lt;a href="https://twitter.com/KenTheRogers"&gt;follow me on Twitter&lt;/a&gt; for more tips on launching and building a successful, fulfilling career as a developer.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>career</category>
      <category>writing</category>
    </item>
    <item>
      <title>[Atomic Dev Tips] Be a Problem Solver</title>
      <dc:creator>kenny</dc:creator>
      <pubDate>Thu, 05 Nov 2020 21:51:39 +0000</pubDate>
      <link>https://forem.com/krgrs/quick-dev-tips-be-a-problem-solver-4ga8</link>
      <guid>https://forem.com/krgrs/quick-dev-tips-be-a-problem-solver-4ga8</guid>
      <description>&lt;p&gt;&lt;strong&gt;Atomic Dev Tips is an ongoing series of short, actionable, high-leverage posts on how to be the best developer you can be.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the first in that series of posts. Follow me here on Dev or on your social media platform of choice if you'd like to keep up with the series and any other content I create.&lt;/p&gt;

&lt;p&gt;One of the most valuable things I've learned in my 6 years as a developer is the importance of viewing your primary role as being a problem solver.&lt;/p&gt;

&lt;p&gt;You should not think of yourself as a developer, coder, or engineer. You should think of yourself first as someone who solves problems for people.&lt;/p&gt;

&lt;p&gt;Code is just the tool you use to accomplish that goal.&lt;/p&gt;

&lt;p&gt;This idea will bleed out into everything you do if you can make it a foundational part of your identity.&lt;/p&gt;

&lt;p&gt;Instead of wondering what sample projects to build for your portfolio, start noticing annoyances in your own life and the lives of others.&lt;/p&gt;

&lt;p&gt;When assigned a new project at work, you can have valuable input and feedback into the development cycle if you look at your role as a problem solver, not just someone who codes up someone else's solutions.&lt;/p&gt;

&lt;p&gt;Cultivate the skill of being able to identify these problems and flesh out software-based solutions to them.&lt;/p&gt;

&lt;p&gt;This problem-solving mentality is a major factor in success not only as a developer but in any career you choose, whether working for someone else or yourself.&lt;/p&gt;

&lt;p&gt;This is one of the main principles at work in my workshop, &lt;a href="https://kenrogers.co/cc"&gt;Create &amp;amp; Connect&lt;/a&gt;, teaching aspiring developers how to land their first jobs.&lt;/p&gt;

&lt;p&gt;Cultivating this mentality is how you can set yourself apart from other people who are just developing without understanding the underlying reasons behind why they are building things.&lt;/p&gt;

&lt;p&gt;So, starting today, take note of the problems you see in your life. Keep an ongoing idea notebook, digital or analog, doesn't matter, and start writing them down.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
