stacksgov / sips

Community-submitted Stacks Improvement Proposals (SIPs)
132 stars 80 forks source link

NFT(s) Staking SIP Research #123

Closed setzeus closed 5 months ago

setzeus commented 1 year ago

In adherence with this grant from cohort 18, I set out to discover the “best” way to setup a multi-NFT -> FT staking experience in an attempt to template, standardize & submit a SIP.

After ~6 months of solo & collaborative research, I’ve come to the conclusion that submitting a SIP around this experience is ill-advisedill-advised at this current time. Below, I’ll walk-through the core reasons why I believe it’s inappropriate followed by generalized “interesting” findings that may or may not be relevant to the community at large.

Why Not A Staking SIP?

1. “Staking” Is An Unspecific Term During my research, I found it incredibly hard to find internal or community consensus on how we define staking. Is it when a trusted source has control of your asset (custodial)? Is it when transferring and/or listing is blocked? Or is staking simply a synonym for ownership? Upon closer inspection, each of these definitions are ill-suited for standardization.

If we define staking solely as a matter of custody - that is, when someone has custody of your asset in exchange for rewards - how does that differ from lending? Moreover, if we define staking as ownership but with contract restrictions on transfer or listing, we're faced with a number of unclear choices. Should we define staking as ownership only when transfer is impossible? Or when listing (which isn’t in SIP09…) is impossible? Or both? Why? Broken down, this is merely ownership with arbitrary obstacles to access. Which leads us to the last definition: simple ownership. Perhaps we should define staking simply as ownership & as the response to (get-owner …)? On principal that seems the most accurate & by in-turn, anticlimactic since it suggest the right label for staking is “rewarded ownership.”

While I was conducting technical research, the ambiguity surrounding the definition of staking did not particularly concern me since the templated solutions addressed all three definitions. However, during the collaborative phase, when we presented our SIP & drafted it up for review, it became apparent how problematic this ambiguity was for the entire SIP basis. The lack of clarity around the definition of staking served as a major red flag.

2. Accommodating For Both Old & New NFTs The creation of a SIP focused on staking also presents a challenge when it comes to accommodating all NFTs, ie existing & new. Unless there is a community consensus on the "ownership" definition of staking, all existing NFTs require custodial staking. While it is possible to accommodate custodial staking, it is substandard as it means forgoing custody of an asset, which is sub-optimal. However, this trade-off on it’s own is likely acceptable.

Yet the issue isn't just with old NFTs being substandard, but also with new NFTs requiring changes to accommodate non-custodial staking. If this SIP were submitted & accepted, new NFTs would need to alter their transfer & listing functions to allow for non-custodial staking. While it is simple to add the necessary lines for non-custodial staking, requiring all new NFTs to consider this logic feels like an inappropriate encroachment on SIP-09 when it’s specifically teams building out ecosystems that’ll likely opt-into this architecture.

3. There Are Larger NFT Update Priorities On that last point, accommodating for a nearly-universal (though not officially part of the SIP), function like (list-in-ustx …) raised another issue: why prioritize a SIP for staking over a SIP for non-custodial marketplace functions? Almost every NFT launched these days has the following non-custodial functions: (list-in-ustx …), (unlist-in-ustx …), & (buy-in-ustx …). Maybe there is a day in the future where we consider an overall update to SIP-09 with optional features like non-custodial marketplace & staking functions, but on it’s own staking has a very weak argument for a standalone SIP.

For all of these reasons, after finishing two templates, an analysis & a SIP presentation, I couldn’t convincingly submit a SIP that’d cross the threshold for

Okay, But What’d you Learn?

1. What’s The Best Template For NFT(s) -> FT Staking? After examining two different architecture options, I came to the conclusion that the monolith model for staking, while suitable for individual teams, is not a viable option for standardization due to its poor security. Since this model accommodates NFT with custodial staking on a single contract, it becomes a vulnerable target for bad actors, particularly if the contract whitelists multiple collections. Moreover, with a single .staking contract, an owner can only stake to one ecosystem at a time. For example, if you have a CrashPunk and both CrashPunks and Bitcoin Monkeys offer staking rewards for CrashPunks, you would have to choose one team to stake with. Overall, while the monolith model may be "safe" for teams to implement, it is not recommended and certainly not worthy of a network standard. In contrast, the star model is a much more attractive candidate for the architecture of a staking-based SIP. As outlined in the report, this model requires a "staker-helper" contract deployed for each NFT added to a staking collection. While this approach does require two sets of trait definitions and the deployment of multiple contracts (since each NFT requires an "NFT-helper"), it does address most of the concerns found in the monolith model.

2. Nested Traits Are Possible! 
This was unbeknownst to me, but regardless of whether this SIP is submitted/accepted/rejected I was wonderfully surprised to learn that nested traits, as long as their defined in the same file, work! Specifically, in the Star model, in the sip-16 contract (16 is just an accidental placeholder number for this experiment), you can see the following signature in the stake-main trait: ;; Add whitelisted collection (add-whitelisted-collection (<stake-helper>) (response bool uint)) "stake-helper" is another trait also defined in that same file, ergo a trait defined & used within the definition of another trait! I haven’t quite wrapped my head around what traits of traits implies for possible future standards & dynamic contract calls but it’s something worth thinking about at length.

3. Weird Clarity Behavior With Traits My last significant discovery is that working with traits beyond the simplest form (i.e., a single parameter) is arduous, complex, & counterintuitive. Two specific scenarios demonstrate this:

  1. Retrieving a trait key/value pair from a tuple.
  2. Resurfacing a trait, which limits passing them down a chain function.

I faced both of these issues while constructing the Monolith and Star models, particularly when attempting to enhance user experience by adding "many" functions such as "stake-many," "stake-all," "claim-many," "claim-all," "unstake-many," and "unstake-all." I eventually overcame these bugs using awkward workarounds (like including brute-forcing functions with over 25+ optional trait parameters), but it was apparent that such an approach was unsuitable for a standard. This problem, which we can generalize as trait type-casting, requires, in my opinion, a decision in a following Clarity upgrade. As I came across these problems, I did see threads & issues referring to other people running into them. Some think we shouldn’t support sequences of traits; some think we should. Either way, I think this is a discussion the community needs to have because as it stands the behavior isn’t encouraged, but it isn’t actively discouraged either - at some point, it follows that we must either support this behavior and correct the type-casting, or completely prohibit it at the language level.

And that’s it! As mentioned throughout you can find the Monolith template, Star template, analysis & SIP community presentation linked here. It’s a shame this fell short of a SIP standard but I wanted to share the fruits of the research anyway - feel free to reach out for any questions, concerns or if you want to implement!


Will close after a month of non-activity.