<?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: Stacks</title>
    <description>The latest articles on Forem by Stacks (@stacks).</description>
    <link>https://forem.com/stacks</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%2Forganization%2Fprofile_image%2F5926%2F6e566201-425a-4158-84d1-2160d2ff378f.png</url>
      <title>Forem: Stacks</title>
      <link>https://forem.com/stacks</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/stacks"/>
    <language>en</language>
    <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>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>
  </channel>
</rss>
