🌊 Superfluid Staking

In this thread I describe a concept of Superfluid Tokens. “Very Liquid” Tokens, which you can “stake” in some protocols, while not moving them from your wallet. This idea allows building a Sybil-resistant voting system (and other software with similar requirements) that does not require users to lock their tokens to obtain voting power. The concept can be cost-efficiently implemented in any language and can be used to extend any existing token, both: fungible and non-fungible.

This idea is based on a hackernoon post I made back in the days. The “Superfluid” prefix is borrowed from physics, where it describes a state of matter when a liquid can flow with zero viscosity, therefore not losing any kinetic energy it has.

Problem definition

Staking locks liquidity.

Sometimes it is a good thing and is necessary - when staked tokens are used for something, while they are locked. For example, when you stake your tokens to a liquidity pool (like in ICPSwap or Sonic). When you do that, your stake is used by other people who can exchange tokens from one to another because of that. Another example - bank deposits. You deposit your money into the bank, which uses them to issue loans to other people.

But sometimes it is not necessary. In my opinion, staking as a mean to obtain voting power in DAOs (like NNS) is not necessary - the money are just laying around doing nothing.

Q: I do not agree, mate, those money create yield.
A: But this yield is synthetic, it is not a profit the protocol made because of your stake. It is just a freshly minted reward for you holding the token and participating in the protocol. Those tokens weren’t used to invest into something, or to issue a loan to someone, or to provide liquidity so other people could exchange. They are just sitting there doing nothing.

There is a category of solutions to this situation called “Liquid Staking” (like WaterNeuron). They work by issuing you a twin-token in exchange for your stake. This twin-token is luqiud - you can use it to do other things, like paying for stuff online. But they inherit the same problem - when you stake this twin-token one more time it is no longer liquid. Plus, this twin-token is physically a different asset - it’s price will inevitably differ from the price of the original one, because this is how exchanges work. And last but not least, I personally hate when you have 20 different incarnations of the same asset in your wallet.

Finding the root cause

The need for staking in DAOs is purely technical - by forcing users to lock their tokens in a provable way, the protocol becomes Sybil-resistant.

Because in a simplified scenario all we need from a user is to prove they hold some amount of tokens right now. Based on this number, we could calculate their share and add it to the proposal as voting power, when they cast a vote.

We could do that in a naive way - when a user casts a vote, call icrc1_balance_of method of the ledger canister and use the result as voting power. But in this case, our system can be easily attacked by simply casting a vote, sending the tokens to another account and casting the vote again, repeating as many times as needed.

With staking we could check the balance of the stake and the timestamp when the tokens were locked. And if the stake was locked before creation of the poll, we could safely apply its voting power, because we know for sure that those are not freshly transferred tokens. So, we actually need staking, because it freezes tokens in time.

The solution

Can we implement something else that will give us timestamped balance infromation and therefore allow us to get rid of staking in votings? Of course we can! In analogy to transaction history canisters, we could implement a balance history canister, which would contain information about balance updates of each account over time and alongside the total supply history.

Q: Why would that work the same way as staking? This is just a balance history.
A: This is just boring (and at the same time exciting) logic. When I stake tokens with a traditional staking mechanism, it’s like I put my money in a time capsule. You can verify I still have them on me by checking the seal on the capsule, and once this seal is broken, I can no longer prove to you that I didn’t spend any of it. But a balance history canister contains all the time. It is like if you could watch me (and everyone else) from a satelite 24/7 - you would know for sure how much money do I have on me right now.

balance-history.drawio (3)

This canister would provide APIs to efficiently fetch account balance and the corresponding total supply at some particular point in time.

balance-history.drawio (2)

In practice

Let’s suppose we have a token with such a balance history canister attached. How do we use it for votings?

The simplest possible (and not very efficient) example would look like this. We have a canister that allows us to create a poll and then cast a vote. When we create a poll, the canister calls to the balance history canister and fetches the current total supply. When a user casts a vote, we use the same timestamp to fetch their balance from the balance history canister. This response we just interpret as user’s voting power and cast the vote.

balance-history.drawio (4)

Q: The voting happens in the context of some dedicated voting dapp. Does this mean that I have to hold my tokens on an account dedicated to that dapp in order to vote? How it is different from staking, if I can’t get my tokens out of one dapp anyway?
A: While this is true, it is not as bad as it might seem.
First of all, you need to have your tokens in the voting dapp only right before the voting is created. Once it is done, you can transfer it wherever you want and only return them back right before the next voting. They are completely liquid.
Second, wallets (and other dapps) could provide various APIs that would allow you to prove posession of the principal you’re using to manage the superfluid token. With this proof you can use the voting system while holding them in your wallet or other dapp.

So, this way, you stay liquid, while still proving you’re holding the token. This solution is completely different from traditional Liquid Staking solutions, simply because the Superfluid token stays the same after you “stake” it - it has the same value and same properties and capabilities as before staking. There is no price difference. And you can stake it in as many compatible protocols as you want, while still being able to spend it whenever you want.

There are other use-cases which can benefit from Superfluid tokens. For example dividends distribution - you can use a Superfluid asset, while still being able to receive dividends for holding it. The only addition here is that dividends distribution would have to probably happen at some specified moments in time, so there is a timestamp that can be used to fetch balance history canister.

Implementation tips

1 - Inter-canster calls optimisation

Dapps supporting superfluid tokens would especially benefit from user-orchestrated inter-canister calls. When casting a vote, users could fetch their own balance from the balance history canister via an update call and pass the certificate obtained from that call to the voting canister, which will verify it and save itself one inter-canister call.

2 - We don’t need full history

Unlike transaction history, there is no need in storing full balance history all the time. Votings rarely last longer than a month. So records older than two months are probably useless. This obviously depends on the particular use-case, but a sliding window pattern can be very helpful here.

3 - Making existing tokens superfluid is simple

All you need to do is to deploy the balance history canister and then make your Ledger canister periodically dump balances into that canister. It should be possible to update this way almost any token canister without introducing any breaking change.

4 - This can be standartized

So we could all benefit from sharing the interface.

Outro

Thanks for reading this far, you’re awesome!
Share your feedback on this concept and take care!

1 Like

Agreed. I think generalizations of this could be very interesting as well, such as a superfluid token that tracks all the SNS ledgers. In social networks, you would want to track different properties, not just balances, but that sounds harder to generalize usefully. Perhaps, ICP neurons could be replaced someday with something that tracks activity in canisters of the IC (preserving privacy), weighted appropriately.

1 Like

Hi @senior.joinu,

I’ve only skimmed the post so maybe I missed something but isn’t this just regular token voting as it is typically done in the EVM world using Snapshot, i.e. you take the token balance at a particular block height (snapshot) to determine the voting power.

@dragvs and team wanted to extend the ICRC-1 index canister with this feature for this project but struggled with the setup in the IC monorepo.

Yeah, this is a similar idea! And all of them quite similar to regular staking on a higher level, because they are all about freezing balances in time. But Superfluid tokens are powerful enough to replace on-chain staking, while allowing an efficient implementation. This is not a new idea. We sketched a similar solution in union during Supernova. But I wanted to describe, name and present it properly to give it a little bit more spotlight and maybe start some interesting discussions.

Most notable differences are:

  1. In Snapshot, there is a special action that the infrastructure has to do - download (or compute) the state snapshot and store it somewhere, so it can be accessed later. In superfluid tokens there is no action - “snapshotting” happens gradually in background.
  2. Imagine your voting platform is popular and hundreds of votings are created every hour. In Snapshot this would mean hundreds of snapshots being taken and stored every hour as well. With superfluid tokens there is no need in that - all of these votings can simply point to some timestamp in the history ledger (even at the same one) without creating any overhead.
  3. (Most important) Snapshot is off-chain, which means that data can be manipulated. Which makes it not very suitable for serious polls, when the result of the poll might execute some action on-chain (and they don’t provide this functionality, AFAIR). Superfluid tokens allow feature parity with staking-based voting protocols, because they are the part of the chain-state. In the hackernoon post linked above, I also implemented this as a smart-contract, not as an off-chain component.
  4. Also there are obvious differences related to the platform - Eth is slow and expensive, while the IC is fast and cheap. Which means that there is probably a significant delay between poll creation and becoming votable in Snapshot, due to the need of eliminating possible forks. On the IC all of that would be instant.

In short:

Snapshot Regular Staking Superfluid Tokens
Secure enough No Yes Yes
Asset remains liquid Yes No Yes
Can scale well No Yes Yes

Yeah, this is probably the hardest part. Because such a history balance functionality requires you to be able to not only search by timestamp, but also by account id. It is quite hard to find a valid scalable combination of data structures for it to work. Especially when you also want to somehow entwine it into an already existing index, like the ICRC-1’s one. This is why I propose to do this as a separate canister. So it can be pretty easily integrated into any existing token, despite the implementation details.

One more little note.
I don’t know how to check the exact luquidity which is currently staked in NNS and all SNS-es, but I assume it is tens of millions of USD (correct me if that’s bs).

By implementing this for ICRC-1 and adding this to all those tokens, this liquidity can be released, while still allowing receive rewards for token holding and vote on interesting proposals. Obviously, this would be a hard task to upgrade the neurons, so they could work with Superfluid tokens, but maybe this liquidity worth it, idk.

My interest is purely technical, as always…

The issue with this is that it is subject to cdp voting where an attacker can attack your network with nothing at risk. See Moving beyond coin voting governance

The simplest example is borrowing from a defi lending platform (eg. Compound). Someone who already holds ETH can lock up their ETH in a CDP (“collateralized debt position”) in one of these platforms, and once they do that the CDP contract allows them to borrow an amount of XYZ up to eg. half the value of the ETH that they put in. They can then do whatever they want with this XYZ. To recover their ETH, they would eventually need to pay back the XYZ that they borrowed, plus interest.

image

Note that throughout this process, the borrower has no financial exposure to XYZ. That is, if they use their XYZ to vote for a governance decision that destroys the value of XYZ, they do not lose a penny as a result. The XYZ they are holding is XYZ that they have to eventually pay back into the CDP regardless, so they do not care if its value goes up or down. And so we have achieved unbundling: the borrower has governance power without economic interest, and the lender has economic interest without governance power.

Any system that allows unregulated liquidity of locked tokens in coin-voting governance is theft from the network by shifting risk off of themselves onto those with at-risk stake in the network. You won’t see the theft until it all comes crashing down in a volatility event, but you will eventually see it and wonder, “why did we allow free riders? they rode off with all our value!”. We’re either all in the same boat or we are not all in the same boat.

There are lots of places where free liquidity coin voting is a great way to take a temperature check or to be part of a governance process, but when it is the ultimate arbiter of a piece of network execution code it creates massive exposure and very high risk of being overwhelmed by outside influence that seeks to take the system’s value.

Hey @skilesare
Thanks for the response and for the new information!

I’ve read the article and I agree with the infromation in it. Maybe I misunderstand something (and if I do, I’m sorry) but I don’t see how this is fundamentally different from what we have with regular staking today.

From the same article, two paragraphs lower:

Some DAO protocols are using timelock techniques to limit these attacks, requiring users to lock their coins and make them immovable for some period of time in order to vote. These techniques can limit buy-then-vote-then-sell attacks in the short term, but ultimately timelock mechanisms can be bypassed by users holding and voting with their coins through a contract that issues a wrapped version of the token (or, more trivially, a centralized exchange). As far as security mechanisms go, timelocks are more like a paywall on a newspaper website than they are like a lock and key.

I see the reason for this issue as a completely different topic. It has little to do with whether I have to physically lock tokens inside some box to obtain voting power, or whether the voting system itself would adjust my voting power based on how many times I voted before when I cast the next vote.

In the first scenario you can’t withdraw your liquidity in case of emergency - when you need the money stat (or when you found out that the project you’ve locked your tokens into for 4 years was a scam). In the second scenario you can withdraw, but you will lose some or all of the voting power you’ve accumulated. Both scenarios are prone to the problem you’ve mentioned, just in different ways.

Possible solutions for this problem lay in a completely different plane and they are well described in the same article. We either invent a good way to prove personhood or we make all tokens non-transferable.

Once again, if I’m missing something, please let me know! <3

I don’t think you are missing much. If Coinbase allowed NNS staking from Coinbase and they could vote for you it would give Coinbase a ton of power(this was one reason I pushed back against prioritizing staking via rosetta a couple of years ago.)

The “wrapping” mentioned above wasn’t as possible on the IC because we didn’t allow contracts to hold neurons. We are now changing that.

The scenario where you can’t withdraw in case of an emergency is a feature, not a bug. That is the skin-in-the-game feature. You can’t get out of the boat no matter how hard you try. Now we do have liquid stakes in a sense through something like idGeek and even just OTC Internet Identity swapping where people get in the same room with a trusted party that moves keys and removes seed phrases). I’ve argued in the past that the easier we make that the more likely it is for those kinds of things be used for ill-gotten gains, but the community seems to be convinced that it is a remote enough problem at the moment to start to open up the accessibility a bit.

One solution proposal was to put some kind of toxic waste on the neuron that can’t be forgotten so that if you buy one you always have the possibility that the original owner will claim it back. That seemed controversial and we are not doing that at the moment, but it remains a potential future solution.(You allude to proof of personhood which would also be a great solution).

There are just some problems with token voting that we haven’t quite solved. It solves sybils but opens up the network to financial capture. The fact that the NNS is completely dependent on it isn’t an issue YET, but may become one in the future…it is a much bigger issue for smaller DAOs like SNSs where the capital required for an attack is much less. We all love Dragginz, but it is the poster child for “If I have enough capital and you use coin voting I can make this DAO mine”.

Your super fluid proposal is great for getting virtual snapshots and taking polls and temperature checks, but I’d be wary of the IC moving to it completely for automatic execution proposals. One of the nice features of what we have now with time locks is that it would be very hard for people to move current locked NNS neurons to a coordinating attacker.

2 Likes

I do understand the reasoning now. Thanks a lot for spending the time with me writing this!

Seems like this concept is best suited for temperature checks then, just as you said.

1 Like

One thing on my agenda is some form of formalizing and indexing of icrc3(generic) transaction logs into an index canister/set of canisters in some reliable manner(and building the actual code to do it). If that intersects what you are working on in any way reach out and we can talk about it. It would be great to have instant on access to the previous state at block X for any canister that produces a transaction log. It enables a bunch of things beyond just voting and governance.

2 Likes

I’d love to do that. Going to dm you once I have some preliminary specs so there is something to start from.

1 Like