near / near-wallet

Web wallet for NEAR Protocol which stores keys in browser's localStorage
https://wallet.near.org
MIT License
220 stars 176 forks source link

Epic: Account Creation Engine V1 #1752

Closed stefanopepe closed 3 years ago

stefanopepe commented 3 years ago

Problem

With V0, we wanted to streamline the account creation, allowing users to create their .near wallet without sending funds in advance - lowering the friction for account creation. The original problem was going through the legacy process of: implicit account creation > funding > deleting implicit account > sweeping funds to named account. With V0 the wallet provides a minimal amount of tokens, just enough to pay for the gas and the storage fees, allowing the user to select any desired name after solving a simple reCaptcha.

As we know, reCaptcha is a weak barrier against sybil attacks, so we end up enabling automated bots "namesquat" the entire .near namespace, without never really using these accounts. The Account Creation Engine V1 will mitigate the issue by keeping the named account availability on hold until the user sent additional tokens to it.

Related roadmap item: https://github.com/near/near-wallet-roadmap/issues/20

How did we discover this problem?

By surfing the explorer at the address https://explorer.near.org/accounts/coin-op.near we can see the list of created accounts in real-time. So far, a large portion of them lies there empty/unused, with costs in terms of blockspace and availability for future and more engaged users.

Acceptance criteria (needs to be triaged)

What are we planning to do about it?

  1. scope down the features, removing or reducing what is not really valuable for the user
  2. introduce a smart contract that is temporarily holding the .near account, releasing it when it receives the funds
  3. still keep a low number of initial tokens, to deter any sweeping of the funds

Overall, we have to:

What are we not planning to do about it?

Resources

NOTE: this is pre-release, needs review by @corwinharrell for UX and @MaximusHaximus for coding

Patrick1904 commented 3 years ago

Have a countdown of 48 hours to complete the transfer, or the name will be claimed back

I see a couple of potential issues with this approach:

  1. I create an account, and don't pay too much attention to what happens afterwards (which happens w/ the current funding flow a lot), or I don't have time to re-visit the wallet for days/weeks. I'm under the impression that I have an account on NEAR, but come back a few weeks later and my account is now gone. Or even worse, I send funds to my account a few weeks later, but I'm no longer in control of it.
  2. There doesn't seem to be much of an upside with having to fund the account within 48 hours to keep it, vs just funding it right away at the time of creation. If I don't have the funds available now, chances are I won't have them within 48 hours.

One way to limit abuse of 'free account creation' may be to require users to limit the number of free accounts that a user can create, and require that the user verifies this with an email or phone number. This would be inconvenient for any seed phrase and ledger users, but may be the price you pay for a free account.

  1. On the screen where we currently show reCAPTCHA: offer two options, where one is to create a free account, that requires the user to enter an email/phone and verify the code sent to the email/phone (same as we have right now). Once the email/phone has been used, the user cannot use it again.
  2. Another option is to offer users a free linkdrop w/ the same amount. The user can only use the same email/phone once.

Above options are not bullet proof, but seem to offer a bit higher barrier for abuse.

heycorwin commented 3 years ago

I agree that we should never grant an account to a user with full access only to have it reclaimed or revoked. This is unexpected (no matter how much it is explained beforehand), and also makes the user feel like there is a central authority that can modify their account access at any time.

My opinion is that if we are going to require that a user funds their own account, then we should require this before the account is created. There is no benefit for the user to create an account only to then require them to fund the account in order to retain access.

This pivot makes me question our original intent with reCAPTCHA. I understand that we need to address the fact that the current implementation can be abused, but if we knew that this would occur and that we would have to inevitably revert to a user-funded solution, I guess I'm missing what our goals were? My understanding was that we wanted to eliminate the need for users to fund their own accounts since this is not a one-click process. Now we are saying that we need to reintroduce the requirement for users to fund their own accounts, which to me seems to go against the intent of the reCAPTCHA implementation.

stefanopepe commented 3 years ago

reCaptcha was put there as a temporary measure to allow account creation without today's friction, while we can work on a more structured onboarding process that can properly mitigate all adversarial scenarios (sweeping funds and namesquatting). This link is still valid: https://github.com/near/near-wallet-roadmap/issues/20

Re original intent: we still have users that get confused when they fund their account, opening ticket such as:

Please note the funding step: this is not a "free account creation", this is a way to avoid the funding step. This reCaptcha is a first step in the direction of allowing users to register their named account, and fund it without going back and forth with the implicit address.

I'm open to having a different and easier flow than the above. I support the idea of having the funding only via one-time email and SMS, although you probably know that Gmail supports the name+string@gmail.com to create infinite aliases - so we may end up having the same issue of today, with just more code running (and still the .

TL;DR: this is not a free account creation filtered by a reCaptcha. This is a different onboarding approach that still requires the funding step - but without the confusing change of the address.

Incidentally, this way of creating accounts introduced namesquatting, and we are here now to mitigate that problem =)

Patrick1904 commented 3 years ago

TL;DR: this is not a free account creation filtered by a reCaptcha. This is a different onboarding approach that still requires the funding step - but without the confusing change of the address.

I think it's important how we frame it. I don't think we should give the user any indication that their account is actually claimed before it's been properly funded. So once the user has finished setting up their recovery method, we'd show them something like "Almost there... now send at least 1 NEAR to {accountId} within 48 hours to claim it."

However, even in this case, some users will end up sending NEAR to their account ID after the 48 hour period, and they'd lose the funds and account.

stefanopepe commented 3 years ago

However, even in this case, some users will end up sending NEAR to their account ID after the 48 hour period, and they'd lose the funds and account.

True, I can see the issue with that. 48 hours is an arbitrary number that can be adjusted, we may just have to measure the actual gap between reserving the name and paying for it.

In that case, the user may try again to register the named account or take the risk of being "front-runned" as soon as the name becomes available again. This is anyway an issue for real humans, and would anyway mitigate the risks of having a bunch of names squatted almost for free (at the cost of solving a reCaptcha)

heycorwin commented 3 years ago

TL;DR: this is not a free account creation filtered by a reCaptcha. This is a different onboarding approach that still requires the funding step - but without the confusing change of the address.

Cool yeah we're on the same page @stefanopepe. I forgot about the changes we intially proposed to funding implicit vs named 👍

Wanted to share a revised flow here to see what everyone thinks. There are still some rough edges here, but I wanted to address the critical path, so please ignore small details and try to focus on the order of events + copy.

Screen Shot 2021-05-17 at 1 51 42 PM
Patrick1904 commented 3 years ago

TL;DR: this is not a free account creation filtered by a reCaptcha. This is a different onboarding approach that still requires the funding step - but without the confusing change of the address.

Cool yeah we're on the same page @stefanopepe. I forgot about the changes we intially proposed to funding implicit vs named 👍

Wanted to share a revised flow here to see what everyone thinks. There are still some rough edges here, but I wanted to address the critical path, so please ignore small details and try to focus on the order of events + copy.

Screen Shot 2021-05-17 at 1 51 42 PM

I think this is an improvement over current funding flow. However, it seems that with any type of temporary reservation of account ID, implicit account/funding address, etc. we inevitably risk causing issues for some users as some users will think that they control the account before completing all the steps. I think it's easy to just assume that if I send funds to the indicated account ID/address (at any point), I've secured my account and do not have to take additional actions to complete the process.

I'm not sure if the user actually has to 'claim my account' once the funds have arrived - what is the action that the user is actually taking there? cc @vgrichina. Could we skip the middle step all together?

heycorwin commented 3 years ago

@Patrick1904 you're right that this step may not be necessary from a technical perspective. The goal here is to show the user that their initial deposit was successfully received and that their account has been activated. It's really just a form of reassurance and confirms their initial deposit details and account activation. Alternatively, we can combine this with the "Welcome to NEAR" screen.

stefanopepe commented 3 years ago

@Patrick1904 I suppose this is not too different from registering a domain name: the fact that nearprotocol.com is not registered and available doesn't mean you fully control it. You really control it when you complete the payment. In this case, we don't ask for a registration fee (as it's gently offered by coin-op.near in exchange for a reCaptcha) but we ask anyway for an initial deposit to complete the registration.

Since we have the "chicken and egg" problem of paying fees upfront to record the wallet address name, we need this additional step (along with @vgrichina contract) to avoid an overflow of fake users who simply squat names without really using them.

Patrick1904 commented 3 years ago

@Patrick1904 I suppose this is not too different from registering a domain name: the fact that nearprotocol.com is not registered and available doesn't mean you fully control it. You really control it when you complete the payment. In this case, we don't ask for a registration fee (as it's gently offered by coin-op.near in exchange for a reCaptcha) but we ask anyway for an initial deposit to complete the registration.

Yep fair point. I think the fact that the user receives the 'keys' to the account, especially the way we send the recovery email, does imply that the user has secured the account already. Same with Ledger, I've secured the key, so I assume that I now own the key.

Since we have the "chicken and egg" problem of paying fees upfront to record the wallet address name, we need this additional step (along with @vgrichina contract) to avoid an overflow of fake users who simply squat names without really using them.

That makes sense. Even if we have to make an additional action after the account has been funded, we could do it in the background, and as @corwinharrell suggested, combine the two steps if possible. We're already listening for the account to get funded in the background.

heycorwin commented 3 years ago

Here's what the different end states look like now (without the extra welcome screen @Patrick1904). I'll be adding some iconography potentially to better communicate the failed state, but just wanted to get the copy in.

  1. Reserved + Awaiting deposit (not yet funded)
  2. Deposit received (success screen)
  3. Deposit not received + account name is forfeit
Screen Shot 2021-05-17 at 3 19 58 PM
Patrick1904 commented 3 years ago

Looks great to me - assuming that the user won't have to take any additional chain action after sending enough funds to the account. That would be great because then it doesn't matter if the user comes back to the funding page again (after sending on binance, etc.), which seems to happen quite often.

ilblackdragon commented 3 years ago

I haven't read the whole thread but just wanted to chime in:

Have a countdown of 48 hours to complete the transfer, or the name will be claimed back

This is generally a setup for many many users loosing their assets. Users will ignore this and will not expect their account to disappear after some time. This is not something that happens in ANY other experience. Not in web2, real world or especially in crypto (where your keys -> your crypto).

Here are examples of failure modes:

Faucet is fine as a short term solution to create accounts for people and fund the storage for them. Otherwise, we should provide a way for people to create implicit accounts (#1453) that people can own. We can shoehorn some other options to create named accounts for people but all these options as far as I see always will be temporary.

stefanopepe commented 3 years ago

@ilblackdragon thanks for your feedback!

The idea is to keep the account on hold until it gets funding.

Essentially, until some tokens are deposited there's no way to access the dashboard and perform a login (to authorize transfers) like today. The 48 hours window is arbitrary and can be easily extended to a few weeks, or even one year.

The final account creation experience won't be too different from the current one, with a funding step that asks deposits to the named account instead of the implicit one (see the UI at https://github.com/near/near-wallet/issues/1752#issuecomment-842562506).

The experience shouldn't be too far from ENS, where you check if a name is available, wait for the on-chain consensus (in our case, a transaction by coin-op.near), and then have your address ready to receive tokens from any exchange.

From what I could test, when an account is manually deleted the transfer will fail with an RPC error account not found.

Corner cases I thought of:

  1. A bot might front-run distract/slow users and register the account ID as soon as 48 hours passed: at that point, any transfer from exchanges would succeed, but the owner is someone else. This is the biggest one, as some exchanges take a few days to complete the KYC.
  2. A user wants to deposit DAI or other bridged assets: it won't be possible without enabling the login to the Rainbow Bridge or ref.finance.
  3. An exchange might cache account IDs using binary search trees, such that an account not found error might not be correctly processed, and funds sent to a deleted account might be stuck in a limbo

The solution proposed by @vgrichina is to list expired names on Near Bet, but this wouldn't prevent the problem at 1.

Solutions/Mitigations:

  1. enable the user to extend the deposit window, by submitting their email or mobile phone number
  2. include alternative funding opportunities, such as https://faucet.paras.id/ or nearcrowd
  3. activate a grace period for expired names, such that they are not instantly deleted

Right now we have already one or more bots iteratively processing long lists of names, countries, famous brands (you name it) and I don't want to run this feature without this important passage.

heycorwin commented 3 years ago

The most recent version of the design/UX for this can be seen here

As @stefanopepe mentioned above, we can easily decide to extend the "reservation window" to be any length of time and to omit explicit references to this window, which in my opinion is the best solution here without adding additional overhead. That being said I just wanted to get this in front of everyone for feedback. I've spent a good amount of time on the UX and copy here and am fairly pleased with the language and how things are articulated in the context of the flow. I also believe all edge cases have been accounted for, but please feel free to point anything out that might have been missed.

Patrick1904 commented 3 years ago

I think regardless of how long we make the window, there will inevitably be some users that do not follow instructions and end up losing access to funds or/and accounts. It feels risky for me as a user to have to rely on checking to make sure I've actually secured my account within the time period, whether it's 48 hrs or more.

I very much prefer to give users the opportunity to claim a named account at creation, however, if we considered giving users an implicit account at first, and then make it super easy for users to create named accounts post account creation, using their implicit account for funding, we would essentially eliminate the issues. It could look something like this:

  1. User lands directly on recovery setup (skip /create step)
  2. User is prompted to send initial funds to the implicit address
  3. User can send funds to the address right away, or later. Once funds are received, user is able to recover the account. If the funds are received right away, the user is automatically logged in to the wallet (we listen for the funding in the background)
  4. After funding, user is greeted, and given the option to create additional named accounts. The first implicit account is never deleted, and all new accounts us the implicit account to fund account creation.

There's a few pro's with this approach:

  1. No account is ever deleted
  2. No time windows
  3. Users can choose to keep only their implicit account for additional privacy
  4. The account creation flow is shorter, and users can get through it without paying much attention to copy/instructions

The main con that I see with this approach is that we're not making the named account the primary option, even though it's a great NEAR feature, though it eliminates a lot of risks and potential confusion.

vgrichina commented 3 years ago

Have a countdown of 48 hours to complete the transfer, or the name will be claimed back

This is generally a setup for many many users loosing their assets. Users will ignore this and will not expect their account to disappear after some time. This is not something that happens in ANY other experience. Not in web2, real world or especially in crypto (where your keys -> your crypto).

I agree with this concern. We for sure cannot be letting in users immediately into account for such faucet. They should see funding screen any time they try to do any interaction, including when using recovery method to recover account.

Here are examples of failure modes:

  • User have initiated a transfer via bridge to this account... Account was claimed back after 48 hours and they lost their 100k DAI

User cannot do it before funding account and adding full access key.

  • User have logged in into an app without access key (just by signing on their account). The app pays for the user's fees to create NFTs. They lost their NFTs / proceeds from selling them later.

User cannot do it before funding account and adding full access key.

@ilblackdragon I feel like you are assuming that with .near funding user would get immediately usable account during registration. But that is not the intent, the intent is to make funding step use .near account.

I think the worst potential failure mode here is like following (far less probable than what we are seeing with implicit accounts IMO): 1) User gets .near account but doesn't fund it immediately even though they cannot proceed further than funding screen. 2) Account expires and is claimed by somebody else. 3) User decides it's finally good time to fund account

This can be mitigated if we reserve a specific suffix for accounts (say .wallet.near) and don't allow anybody to claim account if there is entry in DB already. This even can allow us to remove account on chain but still allow user to re-claim it later if they change their mind.

ilblackdragon commented 3 years ago

So this is not solving the problem that faucet and implicit account are solving - get an account that people can use in other apps even without immediate funding.

We are adding more and more options that allow people to either send assets from Ethereum or to earn directly.

Generally, we should be reducing friction to onboard people instead of increasing it. This still sounds like extra friction @vgrichina and more corner cases, people's money going somewhere and all because we for some reason don't want to add implicit accounts.

If we have a solution that doesn't involve breaking people's flow - let's do it otherwise let's do implicit accounts and stop this unending discussion.

ilblackdragon commented 3 years ago

Name squatting is not really an issue for .near but introducing a 1m delay between account creation on the same IP address can reduce this very dramatically without much user hit.

heycorwin commented 3 years ago

Sharing the latest iteration with the removal of language around the "reservation window". This way, users get a better impression that their account has been successfully created even before an initial deposit, but that it is still required to make use of the wallet.

Screen Shot 2021-05-24 at 4 25 55 PM

@stefanopepe, @Patrick1904 and I discussed this earlier today, and are looking for a bit of clarity around the strictness of the limitation that we are placing on the account before the user has made an initial deposit. If I understand correctly, we will persist the QR code screen until the user makes an initial deposit, and the user will not be able to interact with their wallet until this condition is met. Is this correct? @Patrick1904 you can weigh in here on the technical considerations of a "hard block".

ilblackdragon commented 3 years ago

Given bridge and other tools can receive tokens based on just account id - a user can easily register, not read the memo and ask a friend and or use bridge UI that doesn't require to login to send tokens to this account.

The example with I think I've registered illia.near, and then ask a friend to send me to that account 100k DAI is very simple.

Given you are breaking every single pattern that people are used to (after registering, one forever has an account) - I am still completely against anything temporary in account flow. Let's start moving into simplifying cognitive load on the user, not making it more complex.

On Mon, May 24, 2021 at 10:48 AM Corwin Harrell @.***> wrote:

Sharing the latest iteration with the removal of language around the "reservation window". This way, users get a better impression that their account has been successfully created even before an initial deposit, but that it is still required to make use of the wallet.

[image: Screen Shot 2021-05-24 at 1 41 45 PM] https://user-images.githubusercontent.com/5934188/119386963-45607e00-bc96-11eb-9576-64f7d4927301.png

@stefanopepe https://github.com/stefanopepe, @Patrick1904 https://github.com/Patrick1904 and I discussed this earlier today, and are looking for a bit of clarity around the strictness of the limitation that we are placing on the account before the user has made an initial deposit. If I understand correctly, we will persist the QR code screen until the user makes an initial deposit, and the user will not be able to interact with their wallet until this condition is met. Is this correct? @Patrick1904 https://github.com/Patrick1904 you can weigh in here on the technical considerations of a "hard block".

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/near/near-wallet/issues/1752#issuecomment-847222332, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABK27QYDXFY3CZYA2L3533TPKGPRANCNFSM4444OO7Q .

-- Best regards, Illia Polosukhin

heycorwin commented 3 years ago

@ilblackdragon I'm leaning on @stefanopepe here to provide context on the resolutions you two have arrived at during your discussions regarding this work, but I do have a couple of questions:

Given you are breaking every single pattern that people are used to (after registering, one forever has an account)

  1. What patterns are being broken in particular?

I am still completely against anything temporary in account flow. Let's start moving into simplifying the cognitive load on the user, not making it more complex.

  1. What temporary item are you referring to? And what component here is introducing complexity vs the existing flow? (My perception is that this is much more simple than previous iterations so I'm just trying to understand)
Patrick1904 commented 3 years ago

I suggest we add a flag in our contract-helper DB called initialFundedAccountBalance. The flag is set at the same time the account is created using the faucet. This ensures that the block is still in place should the user leaves the page, recover the same account in a different browser, etc.

Proposed changes:

  1. Add a flag to the account object in our contract-helper DB called initialFundedAccountBalance. Value is set to initial account balance when the account is created using faucet funds.

  2. Add a new endpoint to contract-helper (/accountState) that's called on the 'fund your account' page and once when the Wallet is loaded. The endpoint returns the initialFundedAccountBalance (if previously set) that is then compared to the users current account balance. If current account balance is greater than initialFundedAccountBalance, that means the user has sufficiently funded their account, and the Wallet will call an additional new contract-helper endpoint (/clearInitialFundedAccountBalance) to remove the flag and grant access to the Wallet UI. If the account balance is less than the initialFundedAccountBalance, the user will be re-directed back to the 'fund your account' page.

cc @MaximusHaximus

stefanopepe commented 3 years ago

To keep the ball rolling, I decided to move to an intermediate step that will ask the user to fund the account before giving access to the dashboard. No accounts will be deleted at this stage, and we'll use the learnings from this change to adopt the right name preservation strategy

MaximusHaximus commented 3 years ago

@Patrick1904 :+1: that'll do it! I think it's our best option without having something added to e.g. the wallet indexer that keeps track of whether a coin-op funded account has ever had funds sent to it.

/accountState route will be useful for when we allow users to customize more about the wallet itself and want it to persist across browsers (e.g. such as hiding a wrapped token they've traded in the past but don't currently hold) It's worth noting that we'll need to guard on the backend implementation of clearInitialFundedAccountBalance route to make sure there actually is enough funds in the account for this flag to be cleared at the time the UI posts to it (otherwise people will likely game the system :))

vgrichina commented 3 years ago

So this is not solving the problem that faucet and implicit account are solving - get an account that people can use in other apps even without immediate funding.

Not sure how exactly you can use implicit account in apps without funding, may you elaborate?

We are adding more and more options that allow people to either send assets from Ethereum or to earn directly.

The only option so far that allows to send assets from Ethereum without having funded NEAR account before is Liquality which has it's own implicit account support (as do multiple other third party wallets BTW).

Generally, we should be reducing friction to onboard people instead of increasing it. This still sounds like extra friction @vgrichina and more corner cases, people's money going somewhere and all because we for some reason don't want to add implicit accounts.

Letting users roll with implicit accounts creates extra friction towards them getting .near account and implicit accounts come with it's own trade offs and corner cases in terms of implementation.

.near account name that you picked is likely relatively valuable to you, while whatever implicit account is completely disposable before you have money on it. I don't think that merely supporting creating implicit accounts is immediately gonna solve all problems with onboarding (and data needed to see if it gonna convert better to anything meaningful).

I feel like we screwed up with introducing implicit accounts in general vs support to fund accounts at protocol level. So that you could send NEAR tokens to some special address like someaccount.near/create/JCdUG8doFbVHTCtxuy2RVXraHg8NRhxdCcpiyGgcBMAh and get account created.

If we have a solution that doesn't involve breaking people's flow - let's do it otherwise let's do implicit accounts and stop this unending discussion.

Not sure what do you mean by "doesn't involve breaking people's flow". We at some point have to break user's flow for them to pay for gas or somebody has to pay for gas for them, implicit or non-implicit accounts.

vgrichina commented 3 years ago

Given bridge and other tools can receive tokens based on just account id - a user can easily register, not read the memo and ask a friend and or use bridge UI that doesn't require to login to send tokens to this account. The example with I think I've registered illia.near, and then ask a friend to send me to that account 100k DAI is very simple.

@ilblackdragon I agree with this concern.

I think I commented elsewhere on potential solution (but somehow cannot find it). 1) We can reserve specific namespace for accounts created from wallet (e.g. .is.near or `.wallet). 2) These accounts don't even have to be funded / created for you to receive tokens. The only thing needed is that wallet records connection with recovery methods in DB and doesn't allow anybody else to reserve the same name. 3) As as user you should be able to create account for real and fund with NEAR. This can use pattern with temporary creation of account by faucet before funds are received. We can potentially introduce some FOMO to encourage funding earlier (like less minimum balance required in that case).

stefanopepe commented 3 years ago

The discussion went off-topic and it's hard to extrapolate actionable feedback around the problem statement.

While I agree we have a wide margin to improve the implicit account management (see #1453), this is not the thread to discuss such a feature. As a product designer, I need:

Actionable items:

MaximusHaximus commented 3 years ago

Just a follow-up note after chatting with @Patrick1904 about complexity of the current wallet frontend changes, and @stefanopepe about release schedule, and with a consideration that Monday is Memorial Day holiday in the USA.

Our intention is to be able to test the new code on Tuesday (06/01), with a possible release late on Tuesday or perhaps Wednesday, depending on what (if any) issues we shake out during testing.

However, we can add some funds to coin-op to be sure that the current free account flow is active for the beginning of the week. This should also give us some good comparison data to compare what percentage of accounts are funded with and without the new flow, with a similar audience of users creating new accounts as a result of the event.

MaximusHaximus commented 3 years ago

Update: As part of this work, we are updating the amount of NEAR required/displayed on some of the screens to be more consistent.

There are 4 related 'amounts of NEAR':

  1. The amount of tokens required to be in a funded account to unlock the main UI of the wallet (new)
  2. The amount of tokens that implicit accounts prompt the user to send in order to create their named account (currently 1n)
  3. The amount of tokens that the staking and send UIs display as a minimum required balance in the account, to accommodate storage historically (currently 0.35n)
  4. The amount of tokens that we give the user when they create a funded account (currently 0.02n)

A. We're going to start using the same amount of tokens for #1, #2, and #3. Up until now, implicit accounts asked to send at least 1 near, but the staking and send pages showed that a minimum account balance of 0.35n needed to be maintained for storage costs, so this will standardize both to mention the same amount of near. B. We're going to adjust the # of tokens the cases described in (A) above down, from 0.35n to 0.2n, due to the fact that storage is now cheaper.

From the user's perspective: