Skip to content
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

Proposed ERC20 change: make 18 decimal places compulsory #724

Closed
vbuterin opened this issue Sep 28, 2017 · 55 comments
Closed

Proposed ERC20 change: make 18 decimal places compulsory #724

vbuterin opened this issue Sep 28, 2017 · 55 comments
Labels

Comments

@vbuterin
Copy link
Contributor

Rationale:

  • Reduces the user experience complexity of adding ERC20 tokens
  • Allows ERC20 transfer transactions to be easily detected and have the correct value shown on wallets (incl hardware wallets) without requiring pre-setup
  • Ensures that in any on-chain exchange, the price as expressed in computer units (ie. wei or equivalent) is the same number as the price as expressed in human units (ie. ether or equivalent), reducing the risk of confusion or bugs
@holiman
Copy link
Contributor

holiman commented Sep 28, 2017

I think this is a very good idea, and strongly support it.

@djrtwo
Copy link
Contributor

djrtwo commented Sep 28, 2017 via email

@alexvandesande
Copy link

The main issues, IMHO:

  • Some tokens might not want 18 decimals. Does it make sense to have a "half unicorn" token? But I can see that the advantages of having all standardize into same decimals far outweighs some theoretical tokens that want to limit their division

  • What to do with existing tokens?

My proposal would be:

  1. Set 18 decimals as the standard for any tokens that do not specify decimals(). This should include wallets: Mist for example assumes 0 decimals if no other standard is set
  2. Remove decimals from the standard and most libraries and encourage its deprecation
  3. Encourage all new tokens to coalesce into 18 decimals

@pdaian
Copy link

pdaian commented Sep 28, 2017

ACK @alexvandesande idea of setting this as a default NACK on removing option to set decimals.

Tokens that have real utility may not be arbitrarily divisible to 18 decimal places, and this would create a more confusing user experience for these tokens.

Example: consider an API token where 1 unit gives access to a functionality worth $5. Requiring 18 decimals gives you one of two choices: either allow people to hold "partial API credits", which may be confusing to users, or give your token a very high per-unit valuation, which may also be confusing to users.

To solve the light client issue, perhaps require tokens to issue an event on genesis with their lite-client-pertinent parameters.

@MysticRyuujin
Copy link

Could the standard not be updated to be encouraged to define the decimals within their contract through a standardized variable or return function, which could be read by the wallets, otherwise default to 18 unless otherwise specified? I'd agree that we should maintain the option for != 18 decimals but encourage some default and not break backwards compatibility.

@Souptacular
Copy link
Contributor

ERC-20 is a finalized community standard (#20). Imo if a standard, such as ERC-20, were to be updated after finalization it should either take on a new ERC number, such as #223, or take on a versioning scheme such as "version 2". For this particular case I suggest that this rule be added to another upcoming token standard, such as #223. This prevents already existing ERC-20 tokens from not being considered "ERC-20 compliant".

@MysticRyuujin
Copy link

@Souptacular I absolutely agree with this. The IETF RFC process is exactly the same, once an RFC is finalized it's done. Future RFCs can superseded previous RFCs and building on #223 is the way to go. #20 would simply be "updated" to state that it is updated by #223 and no longer best practice once finalized (if accepted and finalized).

@ligi
Copy link
Member

ligi commented Sep 28, 2017

I strongly support a token standard with a fixed number of decimals! With the words of @prusnak (CTO of @satoshilabs) :

decimals should be killed with fire
( #681 (comment) )

Really good for offline-solutions/hardware wallets!

@MysticRyuujin
Copy link

#223 already defines a decimals() return function so at this point I think the debate is just "Make 18 mandatory?" - My vote is no, too restrictive.

@prusnak
Copy link

prusnak commented Sep 28, 2017

Introducing decimals was a very bad engineering move in the first place. I support having the fixed value.

@MicahZoltu
Copy link
Contributor

Please discuss further in #223. #20 is finalized and therefore immutable at this point aside from typos and
readability. This would be a backward incompatible change to #20 so it can't be implemented as an extension EIP on top of #20. #223 is a proposal for a new token, and while there is some contention around it it currently contains the most discussion, including arguments for and against decimals.

@Arachnid
Copy link
Contributor

Discussion doesn't need to be merged to #223 - that's just one proposal for a new token standard. We could just as easily define a new standard that extends #20 by only adding a restriction on decimals.

@5chdn
Copy link
Contributor

5chdn commented Sep 29, 2017

My support level for this proposal is over 9000! 🔥

@mcdee
Copy link
Contributor

mcdee commented Sep 29, 2017

Over 40% of the tokens listed at http://etherscan.io/tokens do not use 18 for their decimals value. Retrospectively changing the ERC-20 specification would cause far more harm than good.

@holiman
Copy link
Contributor

holiman commented Sep 29, 2017

Example: consider an API token where 1 unit gives access to a functionality worth $5. Requiring 18 decimals gives you one of two choices: either allow people to hold "partial API credits", which may be confusing to users, or give your token a very high per-unit valuation, which may also be confusing to users.

I think the case of non-divisable tokens is a pretty good usecase; where a token represents a non-divisable thing. Such as tokens representing membership or Beertoken (where one wei would be one atto-beer). But I'd rather see the a boolean: isDivisable or something like that, where anything divisable would always use 18 decimals.

And I don't think this necessarily is tied to #223, but I agree not to retroactively change ERC20. This should be a new ERC.

@alexvandesande
Copy link

alexvandesande commented Sep 29, 2017

Can we please focus on the topic itself and not on the format of the ERC? It's clear by now that this is not about ERC20, but a forward looking standard?

@mcdee

Over 40% of the tokens listed at http://etherscan.io/tokens do not use 18 for their decimals value. Retrospectively changing the ERC-20 specification would cause far more harm than good.

Great point, let's go for numbers! Using MyEtherWallet Big list of tokens of 191 popular tokens here are the stats I calculated:

    decimals  Percent of tokens
      0        10% 
      1        0.5% 
      2        3.1% 
      3        1.5% 
      4        1% 
      5        1% 
      6        2.6% 
      7        0.5% 
      8        21% 
      9        3.6% 
      10       0.5% 
      11       0% 
      12       1.5% 
      13       0% 
      14       0% 
      15       0.5% 
      16       1.5% 
      17       0% 
      18       51% 

Over 51% use 18 decimals, followed by 21% that uses 8 decimals, followed by 10% using no decimals at all. (no one uses more). Seems the standard is coalescing for 18.

For me, even if this proposal is not accepted, is already data enough for Mist to guess the default of 18 for any tokens that do not specify it.

@5chdn
Copy link
Contributor

5chdn commented Sep 29, 2017

I believe tokens deployed with the Parity DApp default to 8 decimals. That could explain why so many tokens have 8. But I'm happy to change that to anything that makes sense.

@mcdee
Copy link
Contributor

mcdee commented Sep 29, 2017

@alexvandesande my numbers were to highlight how changing the spec retrospectively would be bad rather than any suggestion about values for the future.

There are good arguments for the divisibility of tokens at the least being 0 (indivisible) or some high value (e.g. 18 near-continuous). This could be enabled with a flag rather than an int, although then it would still require a query of the blockchain to find out its value and so doesn't help the offline use case.

Hard-coding decimals to 18 makes it impossible to have an indivisible token (the token itself can handle indivisibility inside its own contract but what about partial token transfer on exchanges for example?). Losing such functionality seems like a big step.

@Arachnid
Copy link
Contributor

I personally don't think indivisible tokens are a big issue. Every use case I can think of can simply take the floor of the number of tokens when counting, eg, memberships, subscriptions, badges, etc. Token contracts can be written to only transfer whole numbers if desired, too, and exchanges wishing to list that token will have to adapt.

@mcdee
Copy link
Contributor

mcdee commented Sep 29, 2017

@Arachnid but how would an exchange know that a token is meant to be indivisible?

@shrugs
Copy link

shrugs commented Sep 29, 2017

mcdee's point is definitely worth considering; we currently have this extra logic for variable decimals, but if we want to also support indivisible tokens via a boolean, we're just adding a different (and more specific) logic to contracts that interact with these new standardized tokens.

Perhaps a middle ground: say we have an indivisible token contract with exactly 10 total supply. the contract provides some sort of indicator that they are indivisible (aka have 0 decimal places) via an optional public constant. Then any dapp that interacts with these indivisible tokens either

  1. doesn't know they're indivisible, but does know the totalSupply is 10 but represents that as 10 / 10^18,
  2. does know that and represents it as 10

Regardless, the math is the same (the token is indivisible), and only the presentation is affected. It might be weird handling 1e-18 tokens on a frontend that is offline or not updated, but users would ideally be aware of the indivisibility of the token they're interacting with.

Additionally, if an indivisible token wanted to be able to be traded on an exchange divisibly (I'm really surprised autocorrect understands that word), but only used indivisibly, it could do the "only whole numbers accepted" logic in its own contracts, isolating the extra logic.

@Dexaran
Copy link
Contributor

Dexaran commented Oct 2, 2017

If I understand it correctly, the proposal is to remove the decimals variable from the token standard at all AND consider each token has 18 decimals. Right?

@Arachnid
Copy link
Contributor

Arachnid commented Oct 2, 2017

@mcdee That's up to the exchange. They can add a field for it in their database.

Nevertheless, I'd like to hear a use-case for an indivisible token that should actually prohibit part-tokens rather than just round them down when counting them for whatever purpose they exist.

@mcdee
Copy link
Contributor

mcdee commented Oct 2, 2017

That's up to the exchange. They can add a field for it in their database.

But how does the token owner let the exchange know? The only sane method is to add a field to their contract to allow the exchanges to pick up the value, and we're right back where we started.

Nevertheless, I'd like to hear a use-case for an indivisible token that should actually prohibit part-tokens rather than just round them down when counting them for whatever purpose they exist.

As to flooring partial token transfers: let's say that I have a token I want to be indivisible and the code receives a request to transfer 1.510^18 tokens. Rounding it down so that only 110^18 tokens is transferred is bad because the contract hasn't done what was requested of it. Should the contract throw instead? That would confuse users as they could see that their balance was enough to carry out the transfer.

As to a use case for indivisible tokens, how about a token that represents 100g of physical gold? The company needs to be able to exchange tokens for physical gold if required, and doesn't want someone turning up with 0.00876543212345678 tokens expecting them to be changed for a sliver of metal. The general point holds for many items where a single token could represent a physical or logical entity and the token holder doesn't want said entity to be partially owned.

@Arachnid
Copy link
Contributor

Arachnid commented Oct 2, 2017

But how does the token owner let the exchange know? The only sane method is to add a field to their contract to allow the exchanges to pick up the value, and we're right back where we started.

Are you presupposing an exchange that automatically lists tokens? I was thinking of 'traditional' exchanges.

Nevertheless, there are always going to be tokens that have weird transfer conditions, etc. Perhaps such tokens simply won't work with some exchanges.

As to flooring partial token transfers: let's say that I have a token I want to be indivisible and the code receives a request to transfer 1.510^18 tokens. Rounding it down so that only 110^18 tokens is transferred is bad because the contract hasn't done what was requested of it. Should the contract throw instead? That would confuse users as they could see that their balance was enough to carry out the transfer.

No, it would transfer 1.5e18 base tokens. If you previously had 3 tokens and the recipient had 0, you now both have 1.5 tokens - and for the purpose of counting subscriptions / badges / whatever, you each have 1.

As to a use case for indivisible tokens, how about a token that represents 100g of physical gold? The company needs to be able to exchange tokens for physical gold if required, and doesn't want someone turning up with 0.00876543212345678 tokens expecting them to be changed for a sliver of metal. The general point holds for many items where a single token could represent a physical or logical entity and the token holder doesn't want said entity to be partially owned.

Then the store need merely say "we only accept integer numbers of tokens", and reject all offers to exchange fractional amounts.

@mcdee
Copy link
Contributor

mcdee commented Oct 2, 2017

Are you presupposing an exchange that automatically lists tokens? I was thinking of 'traditional' exchanges.

0x (and other distributed exchanges/exchange protocols) allow any ERC-20 token, so yes automatic.

Then the store need merely say "we only accept integer numbers of tokens"...

This and the idea of notifying exchanges of divisibility is moving functionality that currently exists in ERC-20 through use of decimals to manual or otherwise off-chain notifications/enforcement. Doesn't feel very "smart contract" to me.

Hard-coding decimals to 18 is a reduction in the on-chain functionality that exists today, to the benefit of UIs for offline transaction generation. From Alex's post above just under half of existing tokens made a different choice which must suggest that there is utility in having the option available.

@realcodywburns
Copy link
Contributor

realcodywburns commented Oct 2, 2017

The simplest solution would be to subclass tokens. Keep the existing, or substantially similar standard, and allow for sub-classification as: ERC2x.1 atomic units; ERC2x.2 10^8; ERC2x.3 10^18. This would keep things backward compliant with ERC20 while allowing for some degree of predictability for HW wallets. All pre-class tokens should default to ERC20.3for compatibility.

@Arachnid
Copy link
Contributor

Arachnid commented Oct 2, 2017

This and the idea of notifying exchanges of divisibility is moving functionality that currently exists in ERC-20 through use of decimals to manual or otherwise off-chain notifications/enforcement. Doesn't feel very "smart contract" to me.

I agree about divisiblity - but I don't think a store saying they'll only accept integer numbers of tokens is a problem. In fact, the "10g of gold token" you hypothesise seems more useful if it can be subdivided, even if you can only redeem integer quantities.

I'm ambivalent about the proposal to hardcode decimals, but I don't think indivisible tokens are a compelling argument against it.

@alexvandesande
Copy link

I agree. A token can be indivisible and still have 18 decimal points that aren't used, and in the implementation, just fail if someone tries to send less than 1.

An app that isn't aware of the indivisibility, would just present your balance as 1.000000000000000000 (which any reasonable app would just display 1), and it will fail when sending less than 1.

Same things for an exchange: it can allow to sell fractions of the token, it just needs to alert the user that they won't be able to withdrawal floating point amounts.

Personally, I decided to go forward and update the ERC20 example on the homepage to have 18 decimals as the strongly suggested default. No change on the ERC at all.

@DaveAppleton
Copy link

So, we have two tokens, one to 8 d.p. and one to 18 d.p and both were deliberate calculated decisions that actually make sense to us.

It makes no sense for the first to be subdivided to smaller fractions because there is no utility in those smaller numbers - but I would have to add MORE code to ensure that all transfers are rounded to 8 dp? That really makes no sense to me at all.

On the other hand, accepting but disregarding the fractions below the 8 dp range also makes no sense because the remainder bits would be worthless yet charged for in an exchange.

To summarise, the argument for 18 is because we have a standard that

  1. Wallets developers can't get right?
  2. Token programmers can't get right?
  3. ?

I can see no valid justification for either #1 or #2.

@DaveAppleton
Copy link

When thinking about the divisibility of tokens, and the fact that we use only integral numbers, seems to be good to have more decimals then needed, so these precision errors will be irrelevant.

You're talking about decimal places like they're a scarce resource. What's the harm in having more decimal places than you need?

  1. It is a bad idea to change something that is already established and has found significant use cases with non-18 values.
  2. Anybody who has a valid non-18 use case would be forced to implement special logic in approve, transfer, transferFrom and all other functions to truncate to 18 dp. which strikes me as both a waste of gas and a disaster waiting to happen.
  3. If people tried to transfer 0.0000000001 of a unicorn - how do you handle it in a way that the user can understand bearing in mind that the average user does not read logs?

@jrpereira
Copy link

jrpereira commented Dec 27, 2017

A token can be indivisible and still have 18 decimal points that aren't used, and in the implementation, just fail if someone tries to send less than 1.

The point of decimals is not to establish a minimum, it's to establish a minimum increment. A token can represent a unit of something, and that unit can be divisable only down to a certain amount, for a reason.

There seems to be some confusion between unit and precision in this discussion. Depending on what we're measuring, we can have the same SI Unit, but different precision needs. Let's consider the metric weight unit in the SI, for instance:

  1. I sell a product by the kilo, and the smallest unit the scales I use can detect are "grams", so I want my token to have exactly 3 decimals.
  2. I sell a product by the kilo, and the minimum contract is for 1 unit (eg, futures on pistaccio production). The unit is still SI kilogram, so I want 0 decimals.
  3. I sell a product by the ton, and that's the minimum contract (eg, futures on wheat production). The unit is still SI kilogram, but I only want multiples of 1000. Right now I can't do this with ERC20, unless I'm willing to change the token to represent a non-SI unit (ton).
  4. Another example - I am representing a currency that tracks USD amount in a real-world bank account. The balance in said accounts can only vary by a cent, so I need it to have 2 decimals. And yes, the math (eg, calculate % interest) can use any precision I want, but at the end of the day, I can only store increments in 1 cent, and my token should reflect that.

You're talking about decimal places like they're a scarce resource. What's the harm in having more decimal places than you need?

Well, the point is that more decimal places may not mean anything. If I have a token where only 3 decimals make sense, the UI should be able to use the decimals() field to provide a fixed-size display, and there should be no way to store values that don't make sense.

Ultimately, it shouldn't matter much how tokens are stored internally, what matters is how people perceive and interact with value. As we are today, most sane wallets already multiply by 10**decimals(), not by 10**18 - that's a behaviour we should keep.

As a sidenote, I can't help but feel that JS's lack of native support for infinite precision, led us to go back to the stone age. :) We should be able to use 20.0002 rather than 20000200000000000000 - now that would be something.

@nickjuntilla
Copy link

nickjuntilla commented May 8, 2018

As @o0ragman0o put it 18 decimals only makes sense in trying to find a common ground between human readable ETH and gas prices. For tokens this only forces us to have extra complication.

Ideally keeping the bulk of your numbers ahead of the decimal makes things easier to talk about. Look at bitcoin. We are forced to make up units to make talking about 1 hundredth and 1 thousandth easier to talk about. If you can accurately predict the popularity of your token you don't have to make up these units. With USD we have dollars and cents and most things cost more than a penny. What would happen if most things cost less than a penny? What if a pack of gum costs 0.0003 of your token? Now you need a new word. Every popular token will need list of tiny units.

The point is if you don't want to keep making up names for every small amount of every token then you will keep your units ahead of the decimal. Just because 18 decimals is good for Ethereum doesn't mean it's good for every token. In fact it's probably worse in almost every other case.

For display if you have 18 decimals and you want to accurately display how many tokens someone has you must print down to 0.000000000000000001 for legal purposes. You can't say they have 0.000. That would be incorrect. That is a display nightmare. If your token only has 3 decimals for instance you can legally tell someone they have 0.001 and it is accurate.

There are no indivisible tokens such as securities tokens representing 1 stock. This is a very strong case for 0 decimals. It's easy to fit them into the ERC20 standard as-is.

We already have all the tools we need in the current ERC20 to handle most cases. Once you add the code to handle the decimals you never have to deal with it again.

You will also encourage more bugs. If apps start expecting tokens to have 18 decimals and then one comes along that does not there will be a bug. This means that as long as even 1 popular token uses a different amount of decimals you will need to code for it and since that number is currently 49% the day will never come when you can expect 100% at 18 decimals. In fact with the coming representation of more real world assets it will probably become more likely that some tokens will require a specific divisibility.

It seems to me that the status quo is working fine and is very future friendly. I can understand the desire simplify things, but I think if we would have started off at mandatory 18 we would have eventually had to add the optional decimal place as a feature. I think removing it is not progress. I think we will likely have to add more features, not remove them. I think it is very convenient that we have the decimal feature and allows for many use cases while being very explicit in how we handle it in the code. It's mostly for display only so all you have to do is insert the decimal at end for your display. It's a simple modification that handles real world use cases for tokens. Tokens are not the same as Ethereum.

@MicahZoltu
Copy link
Contributor

@nickjuntilla Discussion about decimals should be moved to one of the new token standards, as ERC20 is final and thus immutable aside from grammar/spelling/clarity updates.

If you can accurately predict the popularity of your token

If you decide to continue discussing elsewhere, this is the point you are going to have to argue much more strongly for. Predicting the future value of your token is nearly impossible. Even fiat currency which has a guiding hand trying really hard to keep its value fixed still fluctuates with time (a penny/pence/cent used to be meaningful, but it no longer is).

@meisser
Copy link

meisser commented Aug 10, 2018

There are lots of use-cases that require 0 decimals for legal reasons. For example, it is legally impossible to own 13.2 shares of a company. So if you want to properly implement shares on the blockchain, you must be able to enforce decimals = 0 with ERC-20. Otherwise, you cannot use ERC-20 tokens for shares or bonds and many other established financial constructs.

@MicahZoltu
Copy link
Contributor

That can be implemented in the token by having it throw if a user tries to transfer a non-insignificant number of tokens. See ERC-777 for some thoughts on this.

@meisser
Copy link

meisser commented Aug 10, 2018

@MicahZoltu That would result in a horrible user experience. It should not be the responsibility of the user to get the number of significant digits right in a transaction, this should be automatically done by the wallet. Thus, there must be a way to signal to the wallet what the granularity is, which is done with the decimals field in ERC-20. The approach of ERC-777 is inferior in many regards. Also note that the natural interpretation of an integer including uint256 is to say that 1 means 1, and not that 1 means 0.000000000000000001.

@RafaelCosman
Copy link

Would propose not making it compulsory, could be default. Here at TrustToken we have some real use cases where less than 18 decimals makes sense.

https://github.com/trusttoken/trusttokens

@adrianmcli
Copy link

I'm very sympathetic to this proposal, but I think it's a bit too late to make it compulsory given how some coins already are (like USDC that uses 6 decimals).

However, we really need some kind of name or maybe a separate standard for 18-decimal ERC20 tokens.

Building dapps that are supposed to work with multiple ERC20 coins is getting really annoying when most coins are 18 decimals except for a handful that come up and surprise you during development.

@3sGgpQ8H
Copy link

All ERC-20 token amounts are integers, as well as all Ether amounts. This is quite common practice in financial IT, and crypto-financial IT isn't different.

When large token amount is to be presented to a user, it could be convenient to render it in larger units, rather than in base units. For ether amounts, common larger units are GWei (10^9), Szabo (10^12), Finney (10^15), and Ether (10^18). Less common units are KWei (10^3), MWei (10^6), KEther (10^21), etc. When rendered in any of such units, ether amount could look like a fractional number, but this is only the rendering artifact, and this doesn't make the amount itself fractional.
Just think about file sizes. We all know, that all file sizes are integers and measured in bytes at file system level. However, for a user, file size could be rendered as 1.23 MB, which looks like a fractional number.
Another example is fiat amounts. All USD amounts are actually integer (measured in cents), however they could be rendered as $1.23 or even $1.23M. Of cause, such rendering doesn't make the amounts themselves fractional.

For ERC-20 token, situation is the same. UI may render large token amount using larger units. For token representing backup storage space, such units could be KB (1024), MB (1048576), GB (1073741824), or TB (1099511627776). For token, representing eggs, such unit could be a dozen (12). Of cause, one token may have several different units, suitable for amounts of different scale. For example, tokenized ether may logically inherit units commonly used for ether, such as GWel, Szbao, Finney, and Ether. The idea, that simple “decimals” property could cover all use cases was initially wrong, as it doesn't cover tokens, whose units are not powers of ten, and it doesn't cover tokens that have multiple larger units.

The introduction of “decimals” property, however, led to a great confusion, as people started thinking that ERC-20 token amounts are fractional, which is not the case. Initially, “decimals” property was meant to be used only by off-chain applications, such as wallets, in order to improve user experience. However, smart contracts started using this property for things like exchange rates. Instead of maintaining fractional exchange rate between base units of two tokens, which would be a proper solution, some smart contracts maintain integer exchange rate between “full” token at only side and token base unit at another side. For example, USD/ETH exchange rate is maintained not as 1 Wei = 0.00000000000000024746... cents, but rather as 1 ETH = 24746 cent.

In my understanding, such approach is an abuse of “decimals” property, and leads to a number of problems. The main problem is that the precision of calculations starts depending on the value of token base units. This makes it impossible to use such smart contracts with tokens, whose base units have significant value.

@github-actions
Copy link

github-actions bot commented Jan 2, 2022

There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review.

@github-actions github-actions bot added the stale label Jan 2, 2022
@github-actions
Copy link

This issue was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests