How to build Clarity apps, today

While we put the final touches on launching a public testnet, we wanted to share how you can get started building a Clarity app.

Here’s the screenshare version:

This is not official documentation! Things will change quickly, and some of these instructions may get out of date.

While we’ve been working on Clarity and the new Stacks Blockchain for a long time, a few recent developments have unlocked new abilities for using them. This guide is meant to introduce you to many of these new pieces, and by the end, you should be able to use them to build your own app.

Basic dependencies

Before getting started, you need a development environment with Rustup, Git, and Yarn installed.

Setting up the Stacks Blockchain

You’ll need to run a Stacks node locally on your machine.

If you haven’t already, follow the setup instructions for downloading and building the Stacks Blockchain.

Once you’ve done that, use Git to checkout the feature/genesis branch:

git checkout feature/genesis
cargo build

Next, we’re going to customize the genesis block, to give a bunch of STX to an address that we control.

Open up Stacks.toml, and add the following lines to the bottom:

[[mstx_balance]]
address = "ST3SX4MA9EXP7YNEMQ1HW2RPC6P6YR3E74S6XEYEY"
amount = 100000000

Create a “mempool” folder on your machine. Later on, we’ll drop files into this folder, and it’ll include those transactions in the Blockchain.

You can use whatever file you want. If you’re on unix, something like this could work:

mkdir -p /Users/myname/stacks/mempool

Replace myname with your username, or use whatever folder you want. Then, take whatever folder you just created, and replace the mempool section in Stacks.toml with that folder:

[mempool]
path = "/Users/myname/stacks/mempool"

Cool, we can run the chain now! In a terminal, run:

cargo run --bin blockstack-core testnet Stacks.toml

Our Stacks node is running! Feel free to stop and restart this whenever you want. When you restart it, it’ll start the chain from scratch.

Publish the demo app smart contract

We have a simple Clarity contract inside the UX monorepo, located at packages/test-app/contracts/stream.clar. We need to publish it.

In your terminal, in the Stacks node folder, run this command to generate a “publish contract” transaction:

cargo run --bin blockstack-cli publish ef52e331703f06aa81774dcf209580ca07c7925ed0b22302230d6317dab6b0f801 0 0 stream ~/blockstack/ux/packages/test-app/contracts/stream.clar --testnet | xxd -r -p > tx1.bin

Make sure you replace the path for stream.clar with whatever is correct on your machine.

Next, move the tx1.bin file we just created into your mempool:

cp tx1.bin /Users/myname/stacks/mempool

Replace the second folder with your correct mempool folder, from the earlier step.

Use a web app with your Clarity contract

Now, you can try out our demo application at our hosted preview site.

First, login with Blockstack.

A note about weird behavior with nonce

Currently, we don’t have a good mechanism to keep track of the nonce of an account. Because of this, the authenticator always uses a nonce of 0. If you want to broadcast more than one transaction from the same account, you’ll have to restart your Stacks node. That also means you’ll need to re-deploy the contract. Or, if you’re running these apps locally, you can manually bump up the nonce here. This will be fixed soon!

I also recommend you create a new ID, otherwise you might end up with a weird state with nonce. We’ll have that all working appropriately when we have a public testnet.

You can start using the ‘Smart Contract’ widgets.

Note: the faucet only works when running the app locally.

Hello, Clarity

Click the button in the ‘Hello Clarity’ section. This will open up the authenticator, and prompt you to sign a transaction that calls the say-hi method. The only thing this function does is return (ok hello-world.

Confirm the transaction, and you’ll have the TX hash copied onto your clipboard. To broadcast this transaction, we need to add it to our local mempool folder. Run this in the terminal:

echo "my-clipboard-tx-hash" | xxd -p -r > tx2.bin
cp tx2.bin /Users/myname/stacks/mempool

Be sure to replace the my-clipboard-tx-hash with your actual TX hash, and replace the mempool folder with the one you made earlier.

Now, switch over to the terminal running your Stacks node. You should see a log message that indicates your transaction was processed, and you should see the result of this function!

Status

We also have a simple function that lets you store a “status” in the state of this smart contract. The stream.clar contract has a statuses map, which stores a single status for each “sender” who called the function.

Enter your status in the ‘Status’ input. Click ‘Submit’, and view the transaction details in the authenticator’s popup. You should be able to verify that the status you’re sending is the same as what you entered in the demo app.

Confirm the transaction in the authenticator, then copy the same steps from the “Hello Clarity” section above for including the transaction in your Stacks node.

When it’s confirmed, you should see something like this:

Run the demo app on your machine:

Now that you’ve tried out the basic of the Stacks node, you can start playing around with a real app that uses Clarity smart contracts!

We’ll be using the code in the UX Monorepo for this section.

Clone the repo and checkout the new branch:

git clone [email protected]:blockstack/ux.git
cd ux
git checkout feat/clarity

Next, we install dependencies. We need to specify the BLOCKSTACK_CORE_SOURCE_BRANCH environment variable when running yarn, because it will instruct clarity-js-sdk to build binaries from source. This ensures you have the most up-to-date binaries. As these things mature, we’ll make sure that we always provide the right binaries for every platform out of the box, so you don’t have to install from source.

BLOCKSTACK_CORE_SOURCE_BRANCH="feature/genesis" yarn

Now, you can run everything:

yarn dev

This runs three apps:

Now that your app is running, you can repeat all of the above steps to test out the web app with a Clarity contract!

Updating the Clarity Contract and running tests

Now, you’ll start to learn about how you can actually extend this example app to write your own Clarity apps.

In an editor, the UX monorepo, and view packages/test-app/contracts/stream.clar . This is our example Clarity contract.

We have lots of other examples for other contracts, and I’d encourage you to read them in order to learn:

You can also open up packages/test-app/tests/contracts.test.ts to see the (basic) tests we have setup.

When you’re toying with this contract, it helps to run the tests in watch mode:

yarn lerna run test:watch --stream --scope test-app

One of these tests checks to make sure you have a valid Clarity contract (i.e. no type or syntax errors).

The other tests actually invoke Clarity functions, and then test that the result is correct.

I’d encourage you to dive into clarity-js-sdk to see how you can write tests for your own code.

Update the demo app to use your new code

The demo app is built with React, and if you have a basic understanding of React, you can see how we’re passing parameters to the Authenticator to sign a transaction.

In an editor, open packages/test-app/components/cards/write-status.tsx . This component uses @blockstack/connect, using a new function called doContractCall.

Note: the API for signing transactions with @blockstack/connect is just a prototype. Expect this functionality to change a lot in the coming weeks, which may introduce breaking changes. We’ll keep you updated!

The main code to pay attention to looks like this:

const { doContractCall } = useConnect();

const status = 'hey, im on clarity';

await doContractCall({
  contractAddress: 'ST22T6ZS7HVWEMZHHFK77H4GTNDTWNPQAX8WZAKHJ',
  functionName: 'write-status!',
  functionArgs: [status],
  contractName: 'stream',
});

Each of these parameters is required. Hopefully they’re mostly straightforward, but please ask clarifying questions and we’ll update this and our documentation.

Go change the world

OK, are you still here? Yeah, things are pretty alpha right now. We will continue to refine this workflow, and new developments of the Stacks node and developer tools should reduce all the steps here by 80+%.

If you’re eager to start working on a Clarity app, you now have many of the puzzle pieces to get started.

Please share feedback with the team. We know you’ll likely run into bugs at some point. We’ll keep working on those, and together we can get the Stacks 2.0 world to a mature state in no time.

10 Likes

Cool!

What helps me when developing my smart contract is to check the contract before deployment:

cargo run --bin clarity-cli check ~/blockstack/ux/packages/test-app/contracts/stream.clar

Note, that the smart contracts in clarity-sdk-js use an old syntax (as of 29 Mar)

1 Like

When I try to load this page my browser redirects to
https://xn--deploy-preview-301authenticator-demo-of8v.netlify.com/
and the page returned just says “not found”

Btw, I’m testing on a Pi4 running Ubuntu and I see now I didn’t install Yarn dependency. So trying this now:

curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update && sudo apt-get install yarn
sudo yarn install //several times until “success up to date”

[email protected]:~/blockstack/ux$ sudo yarn install
yarn install v1.22.4
[1/4] Resolving packages…
[2/4] Fetching packages…
info [email protected]: The platform “linux” is incompatible with this module.
info “[email protected]” is an optional dependency and failed compatibility check. Excluding it from installation.
info [email protected]: The platform “linux” is incompatible with this module.
info “[email protected]” is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies…
[4/4] Building fresh packages…
[9/13] ⠁ playwright-firefox
[10/13] ⠁ playwright-webkit
[11/13] ⠂ @blockstack/clarity-native-bin
[7/13] ⠂ playwright
error /home/ubuntu/blockstack/ux/node_modules/@blockstack/clarity-native-bin: Command failed.
Exit code: 1
Command: node postInstallScript.js
Arguments:
Directory: /home/ubuntu/blockstack/ux/node_modules/@blockstack/clarity-native-bin
Output:
System arch “arm64” not supported. Must build from source.

1 Like

@hank I updated the syntax of the smart contracts in the clarity-sdk-js, but I don’t understand how to best implement the rocket market.

The code changes are here: https://github.com/blockstack/clarity-js-sdk/pull/57

How can I access an nft from a different contract? How can I test this with clarity-cli?

Yes, Clarity syntax has changed since those sample contracts were made - sorry about that. We’ll have to get those updated. I really appreciate your willingness to help.

I would reach out to @ludovic, I think he wrote the Rocket market tutorial

1 Like

I managed to deploy the three rocket contracts, :partying_face:

@hank what does it mean if a transaction is not committed?

INFO [1585667428.189] [src/chainstate/stacks/db/transactions.rs:407] 
  Contract-call to ST398K1WZTBVY6FE2YEHM6HP20VSNVSSPJTW0D53M.rocket-factory.ClarityName("order-rocket") args [Int(2)] 
  returned Response(ResponseData { committed: false, data: Int(1) })

The returned data looks good tough

Update
committed:false means that the transaction return err and data is the argument of err

2 Likes

I did some progress:

I can order a rocket (new rocket id returned), but now I fail to claim it. The orderbook map does not return my order entry, in the claim-rocket function, just none. What could be wrong? Is it because the entry is a tuple?

I have the same issue with the fungible-token contract when trying to approve an allowance. map-set is called but map-get? returns none.

Update 2
I managed to approve token transfer allowance. (the issue was that I used my keys incorrectly) Now, I do not see any changes in the balances when I transfer tokens…

Update 3
Ludo explained to me that my transactions are rejected because I am transferring assets and because no post conditions are provided (when using blockstack-cli serialization). Therefore, it makes sense that map-get? returns none.
Conclusion: For now, don’t transfer assets or use the stacks-transaction-js/pull/33 version or submit a blockstack-cli PR.

1 Like

What could be wrong? Is it because the entry is a tuple?

@friedger Clarity’s implicit tuples has been replaced by a new literal syntax.

Instead of the double parentheses around the key/value pair(s) :

(map-get? orderbook ((buyer tx-sender)))

or using the tuple constructor:

(map-get? orderbook (tuple (buyer tx-sender)))

you can now use angel bracket literals:

(map-get? orderbook {buyer tx-sender})

The previous implicit syntax is mostly eliminated from the Clarity implementation, and will be phased out from the reference and examples.

@njordhov As soon as the contract checker complains I will update the examples, for now, the checker complains about invalid map definition and let bindings.

Update
I know understand that blockstack-cli transaction serializer is behind the stacks-transaction-js, therefore, I get the map definition errors with the cli.

1 Like

Thanks for the bug reports!

I’ve fixed the Netlify preview URL. The issue was that the URL had a double-dash in it, which this forum turned into – instead of --. It should be fixed now.

The other error on yarn install relates to how we’re packaging the Stacks node binaries inside of this NPM package. Obviously, we aren’t packaging a binary that works on your platform. We’ll look into this - I’m sure we’ll have to package different versions of the binaries for different platforms.

A subsequent attempt built OK on my Pi4 Ubuntu. yarn install and yarn dev seems to have run OK now, although there was nothing running on localhost:5555. The authenticator appeared to run correctly.

Hey @fluidvoice, I’ve done some more digging into clarity-js-sdk, and I’ve updated this forum post. When running yarn, set the environment variable BLOCKSTACK_CORE_SOURCE_BRANCH. So, for example, most users can do:

BLOCKSTACK_CORE_SOURCE_BRANCH="feature/genesis" yarn

This will build from source, using whatever git branch you specify. Feel free to use master as well - I don’t think the clarity-cli has any big changes between those branches (@jude ?).

However, you’ll still run into problems on arm64, because you can’t build binaries for that platform yet. Luckily, @dant has a PR that fixes this! https://github.com/blockstack/stacks-blockchain/pull/1354 . Once that is merged, you’ll be able to easily build clarity-js-sdk from source.

2 Likes

branch feature/genesis has been merged. Maybe we need a new post now using the http post calls, instead of copying files.

When running npm init clarity-starter (with Rust installed) I get the following error >

$ npm init clarity-starter
System arch “ia32” not supported. Must build from source.
Updating git repository https://github.com/blockstack/blockstack-core.git
error: multiple packages with binaries found: bitcoin-neon-controller, blockstack-core, stacks-node
Cargo build failed with exit code 101
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! @blockstack/[email protected] postinstall: node postInstallScript.js
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the @blockstack/[email protected] postinstall script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

Can anyone help?

Super awe·some