Storage Fees improvements ( and few random ideas on the way )

Hey @bluesign - 1 MB per FLOW is exactly what FLIP 66 is proposing, except that it proposes reducing the minimum storage space available to 10kB instead of 100kB. We had made that change based on (1) the feedback on the high account-creation cost (and thus high CAC for dApps), and (2) 95% of accounts anyway using <10KB storage.
For my understanding, could you pls elaborate on the tweaked formula you’re suggesting?

3 Likes

my formula is a bit simple:

Account cost is same as FLIP 66 ( 0.01 FLOW as part of the account-creation transaction (1) ) but instead of giving 10kb, we give 100kb.

so technically we give 90kb bonus to each account: storage_available = 90kb + FLIP66 formula

This way we guarantee that we almost don’t affect any current accounts ( %99.9 instead of %95 ) and avoid high account-creation cost.

as I mentioned before: Top 20 accounts with 75GB storage counts for 35% of the state ( which is around 205GB ) Considering there are approx 20M accounts , they are like %0.0001

The main reasoning here is: we don’t actually want developers to keep less data on NFT, we want to just punish developers for excessive pre-minting ( in one case it is like 100 million pre-minted NFTs )

As you stated (2) , 95% of accounts anyway using <10KB storage anyway, where they have 100kb limit now, they will keep using 10kb anyway.

I think ideal solution is the one that makes developers to change behaviour than make regular user to take some action.

5 Likes

That sounds like a great idea to me @bluesign

4 Likes

Thanks for the explanation @bluesign - I like it. Would you mind posting this on FLIP 66’s forum post pls so everyone who commented can participate and share their thoughts!

4 Likes

It seems like most folks understand (or are at least resigned to!) the idea that Flow’s approach to storage fees isn’t going to change, but I thought it would be worth sharing how I think about this subject.

I think the best way to present this is to list the ideas I’m aware of as a solution to this problem, and lay out the problems I’m aware of for each of them. And they all have problems! So it’s not really about selecting the best solution, it’s really about selecting the “least bad” solution… :sweat_smile:

  1. Pay on Allocation, Global Price (The Ethereum Model)

    The basic idea here is that you would pay extra tx fees when you allocate new data, and refund it (possibly at a reduced rate) when data is deleted, but everyone pays the same rate.

    The worst issue with this approach is that it leads to state growth due to speculation (remember that the problem we’re trying to solve is to encourage minimal state growth!). If we refund tokens when you free up storage at a global rate, there is a huge incentive to allocate garbage storage to push up the storage price and sell at a profit! Very bad incentives.

    The Ethereum designers seem aware of this issue and tried to solve this by only refunding gas, and not refunding ETH. Unfortunately, this kind of stuck them with the worst of both worlds. There’s a ton of low-value data on Ethereum that has far too small of an incentive to clean up, while there’s still things like Gas Token that store garbage data just to arbitrage gas prices.

    I haven’t seen any variations on this approach that don’t create bad incentives: They don’t provide enough incentive to clean up stale data, or they provide incentives to create junk data, or they do both!

  2. Pay on Allocation, Individual Pricing (The @bluesign Model)

    The basic idea here is that you would pay extra tx fees when you allocate new data, and some (or all) of those funds would be returned when the data is deleted.

    My first concern with this one is how to even track this. Imagine I have a Resource that stores a variable-length array of integers. If I grow that list, I pay the current allocation price, but how much gets refunded if I delete an integer from the array? Do we keep track of the price for each element in the array? The min? Max? Average?

    My second issue is that this doesn’t create a strong incentive to delete old data. If I have a piece of data that was allocated when storage was cheap, but now storage is expensive, I don’t have the proper incentive to clean that up.

    Indeed, as @AlexTheArchitect pointed out, it creates an incentive to create a bunch of junk data that you can use as storage again in the future. You think the price of storage is going to go up? Allocate a bunch of empty space to be used later. This is not the kind of optimization I want Flow dapp developers to be thinking about! :wink:

  3. The Storage Token (The EOS Model)

    You have a secondary token that is used for storage.

    EOS tried this and it was a disaster. It’s another bad incentive: I buy up all of the storage tokens to increase the price, and I can hold you (and every other project) hostage because you either pay, or shut down your whole project.

    (I’ll be honest, I don’t know all the details of what exactly happened on EOS with their storage token and how they addressed it. But once you see the possible attack, it’s hard to imagine how it wouldn’t be a problem.)

    I liked @AlexTheArchitect’s idea that you can always just pay directly for storage with Flow, which prevents the “cornering the market” attack… until I realized that it has the opposite problem. That approach effectively lets me “mint” any number of storage tokens at the current price. If I suspect the price will go up at some point, I just mint a million or a billion storage tokens (allocate a new object, immediately delete it and stash the storage token. GOTO 10). Anyone who does this can sell them at the old price (or close to it) and the network can’t ever really increase the cost of storage. (And if you put a cap on how many storage tokens can be created, you’re back to the EOS problem.)

  4. Storage Rent (The Model Solana Got Rid Of)

    An account buys units of “spacetime”, a certain amount of storage over a certain period of time. If an account uses more “byte-years” than it has purchased, the contents of that account can be deleted.

    I’m not sure how much I have to go into the disadvantages of this. It’s an approach that only an economist could love. To ask users to remember to pay their rent, and then delete their stuff if they forget isn’t just “not user friendly”, it’s downright user hostile…

  5. Pay Once (The AR Weave Model)

    When you allocate storage you pay a relatively large fee, but the data remains indefinitely. The economic theory here is that it’s kind of like paying into an endowment. Like, I pay $5 to store my file, and (conceptually) the “interest” on that $5 pays for the storage indefinitely. AR Weave also counts on the price of storage going down over time (a reasonable assumption).

    I think this is a poor fit for data that can be processed. For something like AR Weave, where the data is stored once and retrieved rarely, I think this model can work. Inside a smart contract block chain, however, every byte of data needs to be in the “working set” of memory so it can be processed at any time by any transaction. The “ceiling” on data storage in a smart contract chain is much, much lower than in a data archive chain.

    IMHO, the worst part of this is that there is zero incentive to remove stale data. From the standpoint of the chain, it’s just as valuable to create an incentive for someone to delete a MB of data as it is to incentivize someone to structure their data to take up a MB less space. A MB is a MB.

  6. Storage Staking (The Flow Model)

    Each account can store an amount of data dictated by the amount of tokens they have. If they have a lot of tokens, they can store a lot of data. Transactions fail if they result in too much data (or not enough tokens) in any account. If an account is “off-side” it doesn’t get deleted, but it can’t be used for anything until the imbalance is fixed. Any transaction from any account can deposit funds into the account to address the issue (provided they have a FLOW receiver).

    For users that use FLOW as their primary currency, this approach is really pretty straightforward and maps very closely to something like DropBox. I have a storage limit, and if I want that limit to go up, I need more money. (Except that, unlike DropBox and Storage Rent, I don’t spend that money, I just stake that money until I stop needing the storage space.)

    However, this approach works poorly in a world where most people’s balances are held in something OTHER than the native token. And, because of the example set by Dapper Wallet and NBA Top Shot, we have a lot of users on Flow who use USDC and/or Dapper Credit instead of the native FLOW currency.

In the end, we should be looking for the best balance of correct incentives and user experience. I would argue that options 1, 2, and 3 have counter-productive incentives, option 4 creates a bad UX, and option 5 would be more expensive and lacks a “clean-up” incentive. Option 6 has problems, but I would argue that the best solution to these problems would be to normalize the usage of FLOW for all users. That’s the token that provides the crypto-economic security protecting the contents of their account, after all!

2 Likes

First of all a small fix, Pay on Allocation, Individual Pricing (The @bluesign Model), my model was more like pay on write, redeem on destroy. For each bytes written, some fee is paid, and this fee is tracked on owner resource. ( for struct types we have a box resource, that is holding the struct )

Imagine I have a Resource that stores a variable-length array of integers. If I grow that list, I pay the current allocation price, but how much gets refunded if I delete an integer from the array?

In this case refund is only when resource is deleted. Every time you modify (write to) the array, you charged a small amount, which is tracked in the resource.

As common case is resource owning resources, deleting ( destroying ) resource to redeem is the easiest solution.

My second issue is that this doesn’t create a strong incentive to delete old data. If I have a piece of data that was allocated when storage was cheap, but now storage is expensive, I don’t have the proper incentive to clean that up.

As we charge ( and stake ) more FLOW then actually size of the object ( as we accumulate on each write ) deleting gives a bigger incentive. Of course no economical model of redemption can make sense if we again decide to increase storage fees 100x or something. But considering storage pricing is going down over time, I don’t think we will need once we fix.

it creates an incentive to create a bunch of junk data that you can use as storage again in the future.

this has no effect, as writing is charged.

For users that use FLOW as their primary currency, this approach is really pretty straightforward and maps very closely to something like DropBox.

Dropbox is a fun thought experiment actually. ( I did this before, as it is for fun I ignore transaction fees :smiley: ) Let me share;

  • Dropbox had 30GB/paying user storage; with 130usd / paying user revenue. ( ~ 300 FLOW )

  • With 6000 FLOW staked on storage on Flow, I have like 300 FLOW lost to inflation (5%).

  • 6000 FLOW gives me 6GB of space with new pricing ( 100x increase proposal )

We are actually pretty competitive with dropbox here.

2 Likes

That does solve the bookkeeping problem, but it removes the incentive to clean-up non-resource data inside a resource.

Imagine I have a game piece resource that stores a lot of data during a game, but doesn’t need that data when the game isn’t being played. If I allocate the data at the beginning of a game, and then delete it at the end of the game (which feels like good hygiene!), the user pays for storage whenever a game starts, but don’t get it back at the end of each game. Taken to an extreme, this pattern could lead to a game piece that only requires a couple of kb to store, but which has cumulatively paid the cost of several MB of storage.

You could work around this by wrapping the game data in a resource, but I fear this would turn into a “best practice” of wrapping all sorts of value-type data in resource objects even when unnecessary. Tracking resources isn’t that expensive, but they’re not as cheap as raw data. At scale, this could be a big problem.

Having said all of that, this approach is definitely more tractable than the approach I thought you were proposing.

[EDIT: I wrote the following before I realized that the cryptoeconomic argument is more-or-less equally strong regardless of whether you pay on allocation or use account-based storage staking. I want to keep the text here since the cryptoeconomic point is really important, but I want to make it clear with this note that it doesn’t help us decided between the two options discussed here.]

I don’t think I put enough emphasis on the cryptoeconomic argument in my last post. If you have lots of “stuff” in your account, you are benefiting from the economic security of the blockchain. If you own FLOW, you are strengthening the economic security of the blockchain. Expecting users to provide additional strength when they depend on additional security is a sound and compelling argument to me.

2 Likes

Hi, I’m new to the topic. I have just been going through the discussion.

Is my understanding correct when I say that the storage fee model for FLOW is not going to change anytime soon because of the complexity behind if we want to change the current model ? Where does this topic land on your priority list ?

2 Likes

From my perspective, there are two angles to @Sahh question:

  • Flow is an open source, community-devoted and community-driven project. If the community feels strongly that storage fees should be revisited, it would be amazing for a group of dedicated people with sufficient subject-matter expertise to coordinate and drive this forward:
    • Everyone is warmly welcome in the Flow Working Groups. For this topic, probably the Cadence Language and Execution Working Group, would be the best place to align on the technical constraints.
    • From my perspective, the biggest challenge at the moment is to work out a sensible and detailed proposal how Storage Fees could look like on Flow. I think this discussion illustrates that there are plenty of ideas. Though, we would need a few people owning this topic and driving the research of an alternative solution forward and convincing a significant majority that their proposal is worth the effort.
    • Once there is a detailed proposal that receives broader support, we can talk about priorities and how to resource the engineering.
  • The second angle is whether the Flow Foundation would dedicate some of their resources to researching an alternative storage fee approach. Here, the answer is pretty clear: for the next two years, the Flow Foundation has most likely much more important work.
    • Keep in mind that we already have the current solution to storage pricing. It is probably not perfect but I feel it is ok. Furthermore, I find it plausible that no better solution exists (see Dete’s explanation). Certainly alternatives exist with different trade-offs but I wouldn’t say they are universally better.
    • In comparison, there are plenty of areas where we have researched and written down great solutions on paper, but the implementation is still pending (eg. parallel transaction execution, scaling storage to many terabytes, various details of Byzantine Fault Tolerance and permissionless participation, trusless data access, etc). From the Flow Foundation’s perspective, progress in such areas is much more important for the Flow ecosystem as a whole compared to changing an established and workable approach to another with different but equally painful tradeoffs.

Hope that sheds some light on the priorities for the Flow Foundation. Nevertheless, this does not preclude progress on an alternative storage fee proposal by the broader community.

1 Like