Need a crash course on Bitcoin layers?
→ READ OUR FREE GUIDE
Need a crash course on Bitcoin layers?
→ READ OUR FREE GUIDE
Need a crash course on Bitcoin layers?
→ READ OUR FREE GUIDE
Need a crash course on Bitcoin layers?
→ READ OUR FREE GUIDE
Need a crash course on Bitcoin layers?
→ READ OUR FREE GUIDE

Announcing Stacks.js v7

Stacks.js is a critical tool for Stacks devs. It handles some of the most common functions for any application right out of the box, including broadcasting transactions and constructing post conditions. But after a few years, Stacks.js was due for a tuneup. Want to see what’s new?

Type
Product update
Topic(s)
Product
Stacks
Published
October 30, 2024
Author(s)
Full Stack Engineer
Contents

We first started working on Stacks.js in 2015 in anticipation of Blockstack (which later became Stacks). From the very beginning, our vision for the tool was clear: to make decentralized app development easy. Stacks.js is a collection of JavaScript libraries for web apps that handles some of the basic functions that every developer needs, such as broadcasting transactions to the Stacks network, constructing post conditions, and more.

Over time, as the Stacks protocol and ecosystem has grown, so has the complexity of Stacks.js libraries. The latest release of Stacks.js, v7.0.0, streamlines some of that complexity, which has two effects:

  • It’s easier to debug and inspect your code.
  • Stacks.js is more intuitive and easier to use.

This latest release of Stacks.js is compatible with Stacks Connect, a sister JavaScript library for developers that handles user authentication and message signing. 

Easier Debugging With Stacks.js

We want to make Stacks.js easy and safe to use, which means making the debugging process seamless and the code easy to follow. When safely interacting with a blockchain, you need many representations for advanced data structures. To understand what’s going on in a piece of code, we want objects and data structures to be human-readable. So, we redesigned Stacks.js to be more oriented around descriptive strings.


// OLD
{
   type: 11, // unclear what type number refers to
   list: [ ... ], // unclear naming of data property
}

// NEW
{
   type: 'list', // string literals show the readable type
   value: [ ... ], // always 'value'
}

Debugging in Stacks.js has always been tricky historically. Before this latest release, creating Clarity values resulted in unintelligible type and value numbers, confusing even experienced Stacks developers. As another example, private keys included unnecessary type properties with raw byte arrays. Going forward we try to make the "public" interfaces as straight-forward as possible.

The latest version of Stacks.js switches to a system where most values will be represented as strings. These changes make values easier to inspect and debug, and we are able to unlock improvements with post conditions and Clarity representations.

Improved Resources for Post Conditions

Stacks.js enables you to create new post conditions, a unique safety feature of Stacks. While post conditions make for safer smart contracts, they can be tricky to figure out at first. Stack.js v7  revamps the <code-rich-text>PostCondition<code-rich-text> type, making post-conditions easier to inspect. Plus, there’s no need to import multiple helpers to create a single post-condition anymore.

Below is an example of the updated <code-rich-text>PostCondition<code-rich-text> types.


// STX post-condition
const stxPostCondition: StxPostCondition = {
  type: 'stx-postcondition',
  address: 'SP2JXKMSH007NPYAQHKJPQMAQYAD90NQGTVJVQ02B',
  condition: 'eq', // available: 'eq', 'lt', 'lte', 'gt', 'gte'
  amount: '100',
};

// Fungible token post-condition
const ftPostCondition: FungiblePostCondition = {
  type: 'ft-postcondition',
  address: 'SP2JXKMSH007NPYAQHKJPQMAQYAD90NQGTVJVQ02B',
  condition: 'gte', // greater-than-or-equal-to
  amount: '100',
  asset: 'SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.my-ft-token::my-token',
};

// Non-fungible token post-condition
const nftPostCondition: NonFungiblePostCondition = {
  type: 'nft-postcondition',
  address: 'SP2JXKMSH007NPYAQHKJPQMAQYAD90NQGTVJVQ02B',
  condition: 'sent',
  asset: 'SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.my-nft::my-asset',
  assetId: Cl.uint(602),
};

Check out the full type definitions and this guide for a deeper dive on post conditions.

Clarity Representations

To interact with smart contracts on Stacks, we use the Clarity programming language. But when we’re using JavaScript we need to be able to represent data structures so Clarity understands what we mean. Similar to the changes highlighted above, we are making these a lot more readable!

The <code-rich-text>ClarityType<code-rich-text> enum was replaced by a more readable version. The previous (wire format compatible) enum is still available as <code-rich-text>ClarityWireType<code-rich-text>. These types are considered somewhat internal and shouldn't cause breaking changes for most use-cases.

Previously, there was a mix of <code-rich-text>value<code-rich-text>, <code-rich-text>list<code-rich-text>, <code-rich-text>buffer<code-rich-text> etc. The property holding the value of the data type is now called <code-rich-text>value<code-rich-text> in all cases. For <code-rich-text>bigint<code-rich-text> values, the type of the <code-rich-text>value<code-rich-text> property can now also be a <code-rich-text>string<code-rich-text>, for better serialization compatibility. Read more about the Clarity representation.


{
-  type: 1,
+  type: "uint",
-  value: 12n,
+  value: "12",
}
{
-  type: 11,
+  type: "list",
-  list: [ ... ],
+  value: [ ... ],
}

Note: this update breaks the signatures of many existing functions, so it’s important to update contracts and code accordingly. We recommend using TypeScript or similar build tools to detect these breaking changes automatically.

A More Intuitive and Consistent Experience

With this release, we wanted to make Stacks.js more intuitive, consistent and easy to use. There are two main categories of changes we did to achieve this goal: introducing a to b helpers and updating network objects and fetching logic.

Getting from A to B in Stacks.js

One of the most common support questions in the #stacks-js discord channel is how to derive one value from another. Where possible, Stacks.js now offers a function to translate between different representations and concepts. The naming is consistent across the board and uses A To B naming.

As a developer, you should never have to search for functions. Start typing what you have (e.g., <code-rich-text>privateKey<code-rich-text>), add a <code-rich-text>To<code-rich-text>, and let your text editor auto-complete the available functions in Stacks.js. For example, if we have a private key and want to get the address, we can use the <code-rich-text>privateKeyToAddress<code-rich-text> function.


import { privateKeyToAddress } from "@stacks/transactions";

const privateKey = "f5a3...2801";
const address = privateKeyToAddress(privateKey); // SP1MXSZF4NFC8JQ1TTYGEC2WADMC7Y3GHVZYRX6RF

Networking Objects and Fetching Logic

The term network can have different meanings depending on the context. Network can of course refer to the protocol network or network object where you want to deploy your contracts such as <code-rich-text>mainnet<code-rich-text> or <code-rich-text>testnet<code-rich-text>, but it can also refer to “networking” logic (e.g. fetching in JavaScript).

For a long time in Stacks.js, "network" instances (instantiations of the network class) were used for both "networking" and "network" definitions. This caused confusion, as most users use <code-rich-text>mainnet<code-rich-text> or <code-rich-text>testnet<code-rich-text> for most of their interactions. 

The "networking" (fetching) logic can now be separately defined from the network object. This split should make it more obvious when functions are using network object properties vs when they are doing actual networking. If a function takes a <code-rich-text>client<code-rich-text> parameter alongside the <code-rich-text>network<code-rich-text> parameter, we know it will make an HTTP request.

In Stacks.js v7, "network" objects are static constants and don't require instantiation. In most cases, developers shouldn't need the <code-rich-text>@stacks/network<code-rich-text> package anymore. Instead, the network parameter can be used with string literals: <code-rich-text>mainnet<code-rich-text>, <code-rich-text>testnet<code-rich-text>, <code-rich-text>devnet<code-rich-text>, <code-rich-text>mocknet<code-rich-text>.


// OLD:
import { StacksTestnet } from '@stacks/network';
makeSTXTokenTransfer({
  network: new StacksTestnet({ url: "mynode.com"}),
  // ...
});

// NEW:
makeSTXTokenTransfer({
  network: 'testnet',
  client: { baseUrl: "mynode.com" }
  // ...
});

We also wanted to make fetching methods more consistent and intuitive. Previous versions of Stacks.js had different methods for fetching functions such as <code-rich-text>estimateFee<code-rich-text>, <code-rich-text>getAbi<code-rich-text>, and <code-rich-text>callReadOnlyFunction<code-rich-text>.

To make it easier to discover all fetching functions, they now all start with <code-rich-text>fetch<code-rich-text>.

The following methods were renamed:

  • <code-rich-text>estimateFee<code-rich-text> → <code-rich-text>fetchFeeEstimate<code-rich-text>
  • <code-rich-text>estimateTransfer<code-rich-text> → <code-rich-text>fetchFeeEstimateTransfer<code-rich-text>
  • <code-rich-text>estimateTransaction<code-rich-text> → <code-rich-text>fetchFeeEstimateTransaction<code-rich-text>
  • <code-rich-text>getAbi<code-rich-text> → <code-rich-text>fetchAbi<code-rich-text>
  • <code-rich-text>getNonce<code-rich-text> → <code-rich-text>fetchNonce<code-rich-text>
  • <code-rich-text>getContractMapEntry<code-rich-text> → <code-rich-text>fetchContractMapEntry<code-rich-text>
  • <code-rich-text>callReadOnlyFunction<code-rich-text> → <code-rich-text>fetchCallReadOnlyFunction<code-rich-text>

Note: <code-rich-text>broadcastTransaction<code-rich-text> wasn't renamed to highlight the uniqueness of the method. Namely, the node/API that this method is sent to "broadcasts" the transaction to the mempool.

Breaking Changes to Stacks.js

While we’re confident that these improvements will result in an improved developer experience, there are some notable breaking changes that developers should keep in mind. We cover the most common changes in this blog post, but be sure to read the full migration guide.

  • The <code-rich-text>@stacks/network<code-rich-text> new <code-rich-text>StacksNetwork()<code-rich-text> objects were removed. Instead <code-rich-text>@stacks/network<code-rich-text> now exports the objects <code-rich-text>STACKS_MAINNET<code-rich-text>, <code-rich-text>STACKS_TESNET<code-rich-text>, and <code-rich-text>STACKS_DEVNET<code-rich-text>, which are static (and shouldn't be changed for most use-cases). Read more...
  • Most fetch (aka networking) methods were renamed to indicate they send HTTP requests. The new methods are named <code-rich-text>fetchXyz<code-rich-text> and are compatible with the old <code-rich-text>Xyz<code-rich-text> interfaces. Read more...
  • Reducing wrapper types, which create annoyances for the developer, rather than being able to use values directly. Read more...
  • The <code-rich-text>ClarityType<code-rich-text> enum was replaced by a human-readable version. The previous (wire format compatible) enum is still available as <code-rich-text>ClarityWireType<code-rich-text>. Read more...
  • The previous <code-rich-text>post-conditions<code-rich-text> types and <code-rich-text>create..<code-rich-text> methods were replaced with a human-readable representation. Read more...
  • <code-rich-text>StacksTransaction.serialize<code-rich-text> and other <code-rich-text>serializeXyz<code-rich-text> methods were changed to return <code-rich-text>string<code-rich-text> (hex-encoded) instead of <code-rich-text>Uint8Array<code-rich-text>. Compatible <code-rich-text>serializeXzyBytes<code-rich-text> methods were added to ease the migration. Read more...
  • The <code-rich-text>AssetInfo<code-rich-text> type was renamed to <code-rich-text>Asset<code-rich-text> for accuracy. The Asset helper methods were also renamed to to remove the <code-rich-text>Info<code-rich-text> suffix. Read more...
  • Remove legacy CLI methods. Read more...
  • Disable legacy triplesec mnemonic encryption support. Read more...
  • Advanced: Rename <code-rich-text>MessageType<code-rich-text> and related concepts to <code-rich-text>WireType<code-rich-text>. Read more...
  • Advanced: Removes two's complement compatibility from <code-rich-text>intToBigInt<code-rich-text> parser method. Read more...
  • Advanced: Refactorings and less visible updates. Read more…

Conclusion

We hope you like all of the new changes to Stacks.js. For more details, view the changelog in Hiro docs as well as the latest Stacks.js concept docs. If you have questions or feedback, please reach out to us on the #stacks-js channel on Discord under Hiro Developer Tools.

Product updates & dev resources straight to your inbox
Your Email is in an invalid format
Checkbox is required.
Thanks for
subscribing.
Oops! Something went wrong while submitting the form.
Copy link
Mailbox
Hiro news & product updates straight to your inbox
Only relevant communications. We promise we won’t spam.

Related stories