-
Notifications
You must be signed in to change notification settings - Fork 140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NEP-491: Non-refundable storage #491
Conversation
Thank you @jakmeier for submitting this NEP. As a moderator, I reviewed this NEP and it meets the proposed template guidelines. I am moving this NEP to the REVIEW stage and would like to ask the @near/wg-protocol working group members to assign 2 Technical Reviewers to complete a technical review (see expectations below). Just for clarity, Technical Reviewers play a crucial role in scaling NEAR ecosystem as they provide their in-depth expertise in the niche topic while work group members can stay on guard of the NEAR ecosystem. The discussions may get too deep and it would be inefficient for each WG member to dive into every single comment, so NEAR Developer Governance designed this process that includes subject matter experts helping us to scale by writing a summary with the raised concerns and how they were addressed. Technical Review Guidelines
Technical Summary guidelines:
Here is a nice example and a template for your convenience:
Please tag the @near/nep-moderators once you are done, so we can move this NEP to the voting stage. Thanks again. |
@near/wg-protocol reminder, can you please assign SMEs as frol asked 2 weeks ago? This effort is entirely blocked on your input here. Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, just some newbie comments here, feel free to ignore if I don't make much sense.
- How should a wallet display non-refundable balances? (proposal: up to wallet | ||
providers, probably a new separate field) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do wallets even need to display non-refundable balance to users (what for) ? My impression was "non-refundable balance" is working specifically towards hiding the complexity of storage-staking from users, is this even an achievable goal ? Blockchain explorers would probably need to display "non-refundable balance" though at least for info/debugging purposes.
On a similar topic, the name "non-refundable balance" might be unnecessarily vague given the intent of this proposal, wouldn't something like "dedicated storage balance" or "storage-tied balance"/"storage-restricted balance" better describe the concept ? Since it's gonna show up in blockchain explorers this makes it a bit more self-explanatory, I think. Unless it does become a more generic concept eventually (in which case more generic name is warranted ofc).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @norwnd , thanks for your input, it's very much welcome! :)
Do wallets even need to display non-refundable balance to users (what for) ?
Not displaying it is a valid choice for a wallet IMO. But right now, I assume most wallets are doing some kind of computation to show how much of the balance is currently open for withdrawal, vs the amount that's reserved to cover storage staking. If they have this computation, they need to update how it works once this proposal gets through.
My impression was "non-refundable balance" is working specifically towards hiding the complexity of storage-staking from users, is this even an achievable goal ?
Interesting question. The original motivation here isn't so much to simplify things. It's more about enabling a certain use case. But I can see how, if presented correctly, we can maybe make it simpler from a user point of view, as they don't even have to know there is storage staking for their account. I like that!
wouldn't something like "dedicated storage balance" or "storage-tied balance"/"storage-restricted balance" better describe the concept ?
I'm open to name changes. I very much dislike "non-refundable balance". But I would like to have a clear distinction between "refundable balance that's currently locked due to storage usage" (which we already have today) and the new concept of "balance that can only ever be used for storage in this account and will be burnt when the account is deleted". In your suggestions, it seems like the line between the two is blurry.
I've considered "storage credits", but that sounds like you can trade them between accounts.
Another idea: Perhaps we should just "purchase" an amount of bytes, and add a field like free_bytes
, as in, no storage staking required for these bytes. Sounds a bit crazy to me but maybe that would make the concept easier to grasp. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In your suggestions, it seems like the line between the two is blurry.
Yep, it was just to illustrate that point, your free_bytes
concept feels much better (alternative names to consider: purchased/prepayed/bought
+_
+bytes/storage
perhaps).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original motivation here isn't so much to simplify things. It's more about enabling a certain use case. But I can see how, if presented correctly, we can maybe make it simpler from a user point of view, as they don't even have to know there is storage staking for their account.
Long term though, UX-wise both for users and devs the "Alternative: Move away from storage staking" is still probably desirable, if achievable in sustainable manner.
@bowenwang1996 I'm not sure who to nominate here as a technical reviewer on behalf of the protocol working group. Do you have someone in mind? |
@birchmd, @bowenwang1996: I am happy to volunteer. |
Non-refundable storage staking is a further improvement over | ||
[NEP-448](https://github.com/near/NEPs/pull/448) (Zero Balance Accounts) which | ||
addressed the same issue but is limited to 770 bytes per account. By lifting the | ||
limit, sponsored accounts can be used in combination with smart contracts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps the following part could use a bit more details (expanded on, in some section below):
By lifting the limit
with respect to how it interacts with "free 770 bytes per account" concept. Because strictly speaking, the way I understand this prop, it's not exactly a generalization of #448 but rather a standalone feature that extends it conceptually.
It seems both features interplay nicely together, just want to make sure it doesn't create unnecessary burden for developers when they decide which one to go with.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the proposal @jakmeier ! I am providing my SME review as requested by @bowenwang1996
I appreciate your thoroughness in describing alternatives to this proposal. You anticipated many of the questions I would have asked!
My remaining concern is if the additional protocol complexity added by this change is justified by the claimed benefit of removing the incentive to spam and delete free accounts. It is true that it removes the "first-order" incentive for this behaviour, but there are "second-order" incentives a bad actor could have. For example, someone who holds many NEAR tokens may be incentivized to cause a large number of NEAR tokens to be taken out of circulation as a means of inflating the NEAR price. Or perhaps a competitor to the business offering the free accounts would be happy to drain the funds of their rival to gain market advantage.
My main point is that business that are offering pre-funded accounts to users will probably still need to implement some kind of spam protection themselves because there could still be bad actors that benefit from spamming. And if it is true that all businesses are implementing this spam protection themselves then do we also need this non-refundable protection in the protocol?
I understand this is a somewhat subjective question. If the community is asking for this feature then it probably provides value to them. But I just want to make sure we are recognizing that this is not a silver bullet to solve free account spam issues.
@birchmd thanks for the review! You raise a very good question! I completely agree that we should carefully consider how important the feature is and weigh it against added complexity in the protocol. @DavidM-D can you maybe make a stronger case for why we need a solution to the storage-refund problem? Specifically answering the comment by @birchmd . |
This is always going to be possible regardless of this proposal. Anyone holding near can just "not use it" or even go as far as "burn" it e.g. by sending it to an unusable account like implicit account with address 00000.... . What I would worry about is the malicious case where an attacker drains the funds allocated for free accounts by spamming. For that reason I agree that we need spam protection. I don't think it's feasible as part of protocol as we cannot really tell apart spamming from increased traffic. I would rather see the business implement its own, app level, solution to this problem. |
To put my two cents in, I am OK with the current proposal but I would preferr the "Allow refunds to original sponsor" variation. I consider this a more future-proof implementation. Based on the NEP it seems like it is not needed today but it is also not harmful to the users. The drawback is the added complexity but in my opinion it's worth it. |
As a working group member, I lean towards rejecting this proposal for the following reasons:
|
As a working group member, I lean towards rejecting this proposal:
|
Posting on behalf on the protocol working group:
Considering that storage refund is a major blocker for a few important applications, notably fast auth account recovery, the protocol working group agreed to approve this NEP to unblock them. |
During Protocol working group meeting, @mm-near suggested updating the action name to clarify that token will be burnt when reserving storage. The currently proposed name is ReserveStorage and I would like to collect feedback and get alignment on what the new name should be. To keep the discussion moving, here is my proposal on naming principles
When it comes to the actual naming, my brain doesn't go further than something like GrantStorageByBurningToken. If anyone has a suggestion/thought, happy to hear. cc. @staffik |
Thank you to everyone who attended the sixth Protocol Work Group call today! The work group members reviewed the NEP and reached the following consensus: Status: Approved 👍 @birchmd : https://github.com/near/NEPs/pull/491#issuecomment-1850078450 After further discussion, Bowen broke the tie and the working group approved the NEP. Meeting Recording: @jakmeier Thank you for authoring this NEP! Next Steps: |
@jakmeier , @birchmd , @mfornet , @DavidM-D , please share your thoughts on the naming :) |
@walnut-the-cat I like your guidelines for naming! My only issue with Another idea could be to intentionally make the name only make sense when part of a larger transaction (since this type of action can only happen as part of a batch transaction creating a new account). Maybe call it
|
Some people didn't like "nonrefundable" to begin with. But I just can't think of something that sounds nicer without becoming more vague. The alternatives I found in the discussion are "dedicated storage balance", "storage-tied balance", "storage-restricted balance" by @norwnd in their comment in August. To me, these sound more vague than nonrefundable storage but I think it's worth brining them up again here.
In conclusion, I personally think |
This semantically limits this action to account creation context (at least in my head), and I don't see a reason to have this limitation. I don't like the idea of introducing "WithNonrefundableStorage" as an Action. One suggestion that was not considered here is to introduce a more generic extendible action (draft naming {
"actions": {
"CreateAccount": {},
"Transfer": {
"deposit": "500100",
},
"AddKey": ...,
"ConfigureAccount": [
{
"property": "NONREFUNDABLE_STORAGE",
"value": "500000"
}
]
}
} The benefits I see here:
The downside probably rules the benefits out:
|
A general
Yes, this was my intention. The current NEP says
so I wanted the name of the action to reflect this. |
Yeah the proposal as it stands actually only works for account creation. Using it in more general ways might sound appealing. But as discussed in the public WG meeting, there is no desire to use it more generally and actually it is quite a lot more work to do. Putting in this extra work would be energy spent on the wrong priorities. Among other reasons, because the long-term solution to storage costs probably will look different from today's design. |
I don't want to drop bombs here, so I will leave it up to the WG. Another naming idea is |
For a named account creation the transaction would be:
that looks a bit weird to me. The original (temporary) name for the action was |
What about
It is quite close to
and as a standalone action for implicit account creation. It is quite long but I could not find a better alternative to the |
For anyone interested, the PR is ready for review near/nearcore#9600. |
@staffik @jakmeier question: it looks like the nonrefundable balance is essentially burnt but the burning is not recorded on the protocol level. What was the rationale behind this decision vs explicitly burning the balance and record amount + locked >= max(0, storage_usage - permanent_storage_bytes) * storage_amount_per_byte This way the burning of tokens is reflected on the protocol level (total supply is decreased). At the same time, it is less confusing for users and integration partners who need to understand what |
I think one rationale was to make it easier if we decide to implement returning the nonrefundable balance to the sponsor. But otherwise, |
## Context NEP: near/NEPs#491 * Please note that action name was not agreed upon (see the end of the NEP discussion for more details). For now, I've used `NonrefundableStorageTransfer` name that was proposed in near/NEPs#491 (comment). ### Goal We aim to enable the sponsorship of accounts with arbitrary storage (for example, with a contract that exceeds the zero balance account limit). Currently, there is a financial incentive to deplete such a sponsor by deleting the account and then cashing in. ## Summary This PR introduces a non-refundable balance, which is a type of balance that can only be transferred to an account at the time of its creation. It is burned upon account deletion. This change eliminates the possibility of cashing out sponsored accounts. ### Changes - Add `protocol_feature_nonrefundable_transfer_nep491` and change nightly protocol version. - Introduce `AccountVersion::V2` as the new default version. - Extend `Account` with a `nonrefundable` field that will only be used by accounts V2 or higher. - Introduce `NonrefundableStorageTransfer` action that behaves similar to `Transfer` but it modifies the `nonrefundable` instead of the `amount` account field. Both `nonrefundable` and `amount` are used to calculate the storage allowance. - Introduce new error type `NonRefundableBalanceToExistingAccount` that it is raised on an attempt to make a non-refundable transfer outside of a transaction that creates an account. - Use serialization sentinel (`u128::MAX`) as a first field during Borsh serialization in case of V2 accounts, to distinguish between V1 and V2 accounts. From V2, the `version` field is Borsh serialized and subsequent versions can use that field. - Add custom Serde deserialization that uses V1 version in case the `version` field is missing. This is required when we parse the mainnet genesis file, so that the mainnet genesis hash does not change. - Add non-refundable transfer tests. - Add serde/borsh (de)serialization tests for all types of account. - Update balance checker, `other_burnt_amount` is updated when deleting an account that had a non-refundable balance. Update related tests. - Minor refactors. ### Original description of a draft implementation by @jakmeier > > The purpose of this reference implementation is to show the proposed protocol changes in practice. > It should be sufficient to convince the reader that all technical challenges have been identified and that there is a solution. > (If that's your goal, I recommend looking at only the changes of the first two commits, as the following commits contain only non-essential changes, such as fixing tests.) > > However, this is not a full implementation. (edit: finishing as much as possible has started, some items are ~~done~~) > - ~~tests are not fixed~~ > - ~~boilerplate code changes are still left as todo!()~~ > - ~~(rosetta) rpc node code does not compile~~ > - ~~changes are not behind feature flags~~ > - ~~some refactoring would make sense~~ > - need to implement more tests for the new feature > - some questions regarding desired behavior need to be decided in NEP discussion (What happens on delete? Is a top-up after creation possible?) > - naming should be decided as part of the NEP discussion => might require variable renaming > - implementation details for ActionView / AccountView need to be decided (with whom?) > - Implementation details around account parsing of old/new versions and its error handling needs to be agreed upon. The PR contains a suggestion. --------- Co-authored-by: Jure Bajic <[email protected]> Co-authored-by: Adam Chudaś <[email protected]>
@bowenwang1996 good point! The question if non-refundable storage is still part of the total supply was first raised very early on. I cannot remember strong opinions on either side. Even the NEP decision was not completely clear about this, IIRC. And I believe the final decision was essentially made implicitly in the implementation in near/nearcore#9600, where I had a placeholder implementation for the reference implementation with a TODO which now morphed into the final implementation. For arguments speaking for not counting it as burnt:
But after the NEP discussion finished, it also seemed to me that we should maybe just consider the token value burnt. It makes more sense from a user's perspective. Which is also reflected in my comment from Jan 27:
I don't see a reason why we couldn't still change this if everyone here agrees it makes more sense to burn. |
If no one disagrees, I think we should change the implementation. I will just confirm with Coinbase if they are ok with this change. |
According to the discussion: near/NEPs#491 (comment) we decided to use `permanent_storage_bytes` account field instead of `nonrefundable`. Non-refundable storage transfer amount will now we explicitly burnt and the nonrefundable storage will now be reflected as `permanent_storage_bytes`. This way is much less confusing for users and integration partners.
rendered: https://github.com/jakmeier/NEPs/blob/non_refundable_storage/neps/nep-0491.md
NEP Status (Updated by NEP Moderators)
Status: Approved
Meeting Recording:
https://bit.ly/483Wo6X
SME reviews:
Protocol Work Group voting indications (❔ | 👍 | 👎 ):