How Stacking DAO Uses NFTs to Create Withdrawal Receipts

Hey, this is Philip and Niel, core contributors to Stacking DAO. In this post, we'll talk about why liquid staking is a big deal and how we built the withdrawal system for stSTX, a liquid stacking token in the Stacks ecosystem.

Type
Tutorial
Topic(s)
Ecosystem
Stacks
Published
March 14, 2024
Author(s)
Stacking DAO Contributor
Stacking DAO Contributor
Dive into the code of one of the newest projects in the Stacks ecosystem.
Contents

Liquid stacking is the single biggest category in DeFi, accounting for 60% of DeFi’s total TVL across all chains—which in dollars translates to more than $62B. It’s proven incredibly popular and is a way for users to secure a blockchain network (earning yield in the process) while their assets remain liquid.

With Stacking DAO, we’ve brought a variation of a liquid staking protocol to the Stacks ecosystem, but before we talk about how we built it, let’s set some context.

What Is a Liquid Staking Protocol?

Many blockchain networks today are Proof of Stake, a consensus mechanism in which there are validators that “stake”, or lock up, tokens in the network protocol. This secures the network both by a) offering an incentive, where validators receive rewards for processing and validating blocks and b) offering a penalty system, where their staked assets can be slashed for fraudulent or malicious behavior.

Staking is great for the health of the ecosystem. Not only does it secure the network, but it’s a way for token holders to generate yield. In exchange for locking their tokens, they can earn anywhere from 3-20% annual yield.

However, that yield comes at a cost. When a user stakes tokens, those tokens become illiquid. They cannot trade them, nor can they use them in other applications (e.g. a user could not post a staked asset as collateral in a lending application.

To solve that issue, liquid staking protocols were created. Through these protocols, users can stake an asset and receive a synthetic token in exchange. These synthetic tokens are effectively IOUs; they are fully liquid and can be traded or used in apps, and they can be redeemed for the underlying staked asset at any time.

Liquid staking protocols have proven to be one of the core primitives in successful DeFi ecosystems.

The first liquid staking protocol went live in December 2020 through Lido, and since then these protocols have skyrocketed in popularity, to over $45B in TVL. Today, there are a range of providers in the majority of Proof of Stake networks. These protocols do introduce some centralization concerns, but the product-market-fit is undeniable.

These protocols have proven to be one of the core primitives in successful DeFi ecosystems, enabling network security and liquidity at the same time. It also enables all kinds of interesting use cases, such as compounding yield (earn yield on an asset that is already earning yield), self-repaying loans, and more.

Is it any wonder we wanted to bring a similar protocol to Stacks?

Staking vs Stacking

Staking in Proof of Stake networks and Stacking in Stacks have a lot in common. Similar to staking, users can “stack” their STX tokens in order to secure the network. In exchange, they earn BTC-denominated yield.

Let’s compare staking in Ethereum to Stacking on Stacks to give you a sense of how these consensus mechanisms compare.

To stack or to stake, that is the question

At a high level, Stacking has the same pros and cons as staking, so after seeing the success of liquid staking protocols in other ecosystems, it was an obvious bet to create a “liquid stacking protocol” for ours.

Enter Stacking DAO.

Meet Stacking DAO

Stacking DAO is a new liquid stacking protocol on Stacks, and since its launch on December 18, 2023, we’ve already seen $75M+ in TVL, effectively doubling the size of DeFi on Stacks. After ALEX, Stacking DAO is the second largest DeFi protocol on Stacks. 

A snapshot of Stacking DAO's growth, stats taken from the website on March 14th
We hope to be a magnet for DeFi on Stacks.

At a high level, users can stack their STX through this protocol and mint stSTX tokens in return. These stSTX tokens are liquid, accumulate Stacking rewards and can then be used in other apps in the Stacks ecosystem.

Unlike traditional stacking, which generates a yield in BTC, Stacking DAO generates yield in STX, and this yield autocompounds via the protocol. There are a few reasons for this. First, this enables STX holders to be long STX more easily. Second, from an implementation perspective, it is much easier (and more secure) to build a protocol that focuses on a single token instead of two different tokens. It’s a smaller surface area.

So from a user perspective, this means that using the protocol looks a lot like a straightforward trade in which a user swaps STX for stSTX. Behind the scenes, the protocol will then stack their STX, and the stacking yield accrues to the protocol for auto-compounding.

This means that with each cycle, the price of stSTX will grow (so, for example, if a user swaps 1 STX for 1 stSTX at the protocol launch, then after several stacking cycles, they will be able to swap that 1 stSTX back for 1.x STX—the original STX plus x, the earned stacking yield for that deposit).

At the protocol level, this solution is non-custodial. Assets are held by contracts not by an organization, but there is a DAO that takes a small commission from stacking yield in order to maintain and build the protocol.

In the future, we also have plans to address some of the centralization problems we’ve seen with liquid staking providers in other ecosystems, and we intend to delegate to external pools and signers post Nakamoto launch, which will help bootstrap a decentralized signer network on Stacks. 

With this protocol, we’ve brought the liquid staking protocols of other ecosystems to Stacks, and we hope to be a magnet for DeFi on Stacks in the same way that these protocols have been for other ecosystems. For example, 37% of stETH is used in DeFi on Ethereum.

And so far, so good. We’ve already seen the Stacking DAO protocol ignite a spark in DeFi and create a big liquidity unlock. For example, in just a few months, Bitflow grew from $0 to $35M+ in TVL, largely driven by its integration with stSTX, and Zest reached $5M+ in TVL in the first few weeks of its launch. We hope to have similar success with upcoming integrations with other apps, including Arkadiko, and more.

Breaking Down the Code: Processing Withdrawals

One design challenge in building Stacking DAO was around user withdrawals. Stacking on Stacks occurs in ~two-week-long stacking cycles, and if a user wants to withdraw just a portion of their stacked STX, they have to a) unlock their entire stack of locked STX in order to withdraw just a portion of it and b) wait until the end of the current two-week cycle for their stacked STX to unlock.

To minimize the impact of a) on Stacking DAO’s yield, we actually break deposits algorithmically into 10 different stacking addresses, so every two-week cycle, we can unstack just 1 of those vaults to process user withdrawals while the other 9 continue stacking. And as for b), we actually use NFTs to create receipts for withdrawals to improve the user experience.

When a user initiates a withdrawal, they transfer their stSTX tokens to the protocol. This is because the user needs to signal to the Stacking DAO protocol to unlock STX from stacking, and the protocol must make sure it can actually burn the corresponding stSTX tokens at the end of the two-week stacking cycle.

This creates a suboptimal UX where a user no longer has their stSTX tokens anymore, but they haven’t received their STX in return yet either. We decided to introduce an NFT that represents the initiation of the user’s withdrawal, so that there’s always representation of a user’s Stacking DAO position in their wallet.

We use NFTs to create receipts for protocol withdrawals.

This NFT can then be burned after the stacking cycle ends and redeemed for the corresponding STX, but in order to function, we need to couple each withdrawal NFT with some data, as seen in the code below.

First is the <code-rich-text>unlock-burn-height<code-rich-text>, which indicates to the protocol when this NFT can be used to make an actual withdrawal (the end of that particular two-week stacking cycle). Secondly, there is the <code-rich-text>ststx-amount<code-rich-text> the user has transferred to the protocol to initiate their withdrawal, and the <code-rich-text>stx-amount<code-rich-text> the user will receive on actual withdrawal.


(define-map withdrawals-by-nft
 {
   nft-id: uint
 }
 {
   unlock-burn-height: uint,
   stx-amount: uint,
   ststx-amount: uint
 }
)

Let’s have a look at the <code-rich-text>init-withdraw<code-rich-text> method which can be used to initiate a withdrawal and mint their withdrawal NFT. When calling this method, the user must indicate the amount of stSTX they want to turn back into STX.


(define-public (init-withdraw
 (reserve )
 (direct-helpers )
 (ststx-amount uint)
)
 …..
)

Next to the <code-rich-text>ststx-amount<code-rich-text> the protocol also needs to know the values for <code-rich-text>unlock-burn-height<code-rich-text>, <code-rich-text>stx-amount<code-rich-text>, and of course the ID for the NFT. These values are calculated first.


(define-public (init-withdraw
 (reserve )
 (direct-helpers )
 (ststx-amount uint)
)
 (let (
   (sender tx-sender)
   (unlock-burn-height (unwrap-panic (get-withdraw-unlock-burn-height)))


   (stx-ststx (try! (contract-call? .data-core-v1 get-stx-per-ststx reserve)))
   (stx-amount (/ (* ststx-amount stx-ststx) u1000000))
   (total-stx (try! (contract-call? reserve get-total-stx)))


   (nft-id (unwrap-panic (contract-call? .ststx-withdraw-nft get-last-token-id)))
 )
   ….
 )
)

Now that we have all the needed info, we can implement the actual logic. First we make sure to save all the NFT data. This is done in a separate contract to decouple data from logic. This decoupling makes it easier to make updates to the protocol later.

Then 3 things happen in the code:

  1. Indicate the amount of STX the protocol must unlock for this user at the end of the cycle
  2. Transfer the user’s stSTX tokens to the contract (these tokens will be burnt on actual withdrawal)
  3. Mint the NFT to the user’s wallet

(define-public (init-withdraw
 (reserve )
 (direct-helpers )
 (ststx-amount uint)
)
 (let (
    ….
 )
   ….


   (try! (contract-call? .data-core-v1 set-withdrawals-by-nft nft-id stx-amount ststx-amount unlock-burn-height))
  
   (try! (as-contract (contract-call? reserve lock-stx-for-withdrawal stx-amount)))
   (try! (contract-call? .ststx-token transfer ststx-amount tx-sender (as-contract tx-sender) none))
   (try! (as-contract (contract-call? .ststx-withdraw-nft mint-for-protocol sender)))


   (ok nft-id)
 )
)

That’s it. Now the user has an NFT representation of their withdrawal in their wallet. Once the two-week stacking cycle ends, the locked STX are unlocked and transferred by the protocol to a reserve contract. The user’s NFT can then be burned via the protocol and redeemed for the corresponding amount of STX tokens in that reserve contract. This NFT can also be transferred or sold, since anyone holding the NFT can redeem it for STX.

Unlocking Liquidity in Stacks DeFi

With Stacking DAO, we not only want to make stacking a liquid, and better, experience for users, but we hope that this protocol will unlock liquidity in DeFi apps across the Stacks ecosystem. We are starting to see that thesis play out with early traction on Bitflow and Zest, and we hope that continues to accelerate in the future.

If you want to learn more about Stacking DAO, give us a follow on Twitter and check out our website.

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