ethereum / EIPs

The Ethereum Improvement Proposal repository
https://eips.ethereum.org/
Creative Commons Zero v1.0 Universal
12.86k stars 5.27k forks source link

ERC777 Token Standard #777

Closed jbaylina closed 2 years ago

jbaylina commented 6 years ago

Please, see https://eips.ethereum.org/EIPS/eip-777 for further discussion.


tjayrush commented 6 years ago

Was there discussion of adding a Mint/Burn pair of events and/or mint/burn functions to this proposed standard?

If this was discussed and rejected, what are the reasons for rejecting it? If it was not discussed, should it have been?

While not foolproof (because a contract may neglect to call these events), it would make the automated accounting of ICO sales for token contracts that do comply a lot easier. To accurately account for existing ERC 20 token sales, one must read and understand the contract's code.

3esmit commented 6 years ago

What is the use of _to while is obvious that is the TokenFallback reciever itself (the contract address(this)), and why is needed _ref if we can store a _ref data inside _data if application needs it?

I would find better to stick to the needed stuff, such as:

    /**
    * @notice ERC223 and ERC667 Token fallback 
    * @param _from sender of token
    * @param _amount value sent
    * @param _data data sent
    **/    
    function tokenFallback(
        address _from,
        uint _amount,
        bytes _data
    )

Can you describe situations where _ref and _toare important, or crucial?

jbaylina commented 6 years ago

@3esmit The _to is because the proxy that handles the interface for a specific address can be a different contract. Please see EIP https://github.com/ethereum/EIPs/issues/672 .

For the _ref, this should act as a reference, for example a check number, or an invoice number. In general the ref will be set by the operator and the data will be set for the sender and will be the equivalent to the data in an ethereum transaction.

May be a good alternative would be to integrate this 2 parameters in data and define a standard for data This way we would maintain current compatibility with EIP223...

3esmit commented 6 years ago

I suggest also adding a boolean return to tokenFallback, and token contract require a true return to accept transaction, in order to avoid this scenario: https://github.com/axiomzen/cryptokitties-bounty/issues/3

jbaylina commented 6 years ago

@3esmit This is problematic. This function is called after the transfer is done. So returning false would mean to rollback the transfer. This can add a lot of reentrance issues, so I decided that the function ether executes or throws the full transaction. The nice thing of this standard is that if the tokens a sent via send it eans the the receiver must register the interface in EIP672 way. If not, it fails. Of course you can use the old transfer method for backwards compatibility.

izqui commented 6 years ago

I propose renaming operatorData to logData to make more explicit that the purpose of that data is no other than being part of a log. The ability of adding context to token transfers is powerful, and the gas hit is minimal when they are not used.

Really like and support this proposal, exactly the vision that made me excited about ERC223 10 months (!!!) ago. We are considering making ERC777 the base standard for all the tokens issued on @Aragon!

onbjerg commented 6 years ago

This is an interesting proposal, but I worry about the entire ecosystem having to migrate to new multisig wallets in order to be able to receive ERC777 tokens.

It seems like there was an attempt made to create a whitelist of contracts that one can safely transfer to even if they do not implement ITokenReceipient:

The function MUST throw if:

  • to is a contract that is not prepared to receive tokens. That is it is a contract that does not implements ITokensReceived interface and the hash of the sourcecode is not in between the whitilisted codes listed in the appendix of this code.

But there is no such appendix, I would love to see it 😊

jbaylina commented 6 years ago

@onbjerg We are working on it. We are thinking in keeping this list open for a while (centralized) and close the list at some point (make it decentralized).

sohkai commented 6 years ago

Was there any consideration over allowing users to specify how much an operator can control, e.g. changing authorizeOperator() to:

function authorizeOperator(address operator, uint authorizedAmount) public?

One could use 2^256 - 1 (or hypothetically the totalSupply() if that never grows) to simulate the previous true behaviour and 0 for false.


The only difference for new contracts implementing ERC20 is that registration of ITokenRecipient via EIP-672 takes precedence over ERC20. This means that even with on a ERC20 transfer call, the token contract MUST check via EIP-672 if the to address implements tokensReceived and call it if available.

I find this somewhat confusing and unexpected. We'll have a dichotomy of "ERC20" tokens: ones that will never call the tokensReceived() callback, even if ITokenRecipient is registered; and ones that will always check. Even if the ERC20 functions are only supposed to be called via old contracts, I think there'll be lots of confusion about this since the meaning of what an "ERC20" token will have essentially changed depending on if your token also supports EIP777.

It also feels odd because you don't have to support the ERC20 interface with EIP777, but you most likely will to support prior contracts expecting that standard.

What if EIP777 was instead a superset of ERC20's interface but overrided specific parts, e.g. transfer() and transferFrom(), to support the ITokenRecipient interface?


I kind of like and dislike the send() nomenclature. On one hand, it's nice how it parallel's ETH's transfer() and send() nomenclature. On the other, it's confusing because these two terms are now both overloaded with different meanings for ETH and tokens. It's confusing enough that we have both for ETH, but it's going to be even more confusing when there's the same names for tokens. I do like the naming for transferAndCall() because it's really obvious what it's probably going to do.

I guess an alternative could be transferToRecipient().

jbaylina commented 6 years ago

@sohkai: 1.- The idea o authorizeOperator is mainly to authorise a contract. The maximum allowed limitation and many others limitations, like a daily limits, should be implemented in the operator contract and keep this standard as clean as possible.

2.- The idea is that the receiver should have the warranty that the tokensReceived() method is ALWAYS called. Even if it is called via an obsolete ERC20 transfer() or transferFrom() method. This way, for example, allows a recipient to NEVER accept a specific token. or forward some tokens to a specific charity.

3.- The big problem of maintaining transfer() name in the new standard is that if you use transfer() in an ERC20 only token, you will end up locking a lot of tokens. This mistake might become very common in a moment where 50% of the tokens are ERC20Only and 50%ERC777.

MicahZoltu commented 6 years ago

As I have mentioned in other threads, I strongly recommend removing decimals. Here is a cross post of what I have said elsewhere:

Decimals are easily the number one source of confusion for both token authors and users of ERC20. I strongly recommend removing this as a variable and instead asserting that tokens must have a certain "humanizing divisor". Reasonable choices IMO are:

I think the worst option is to continue to allow for variable humanizing divisors. This doesn't actually solve any real problems, since any chosen unit is very likely to be a wrong choice at some point in time (too big or too small). Also, since the token author can pick the token supply, allowing them to also choose the humanizing divisor doesn't give them any more/less power to try to target a "nice human-scale number".

MicahZoltu commented 6 years ago

You mention function send(address to, uint256 value, bytes userData, bytes operatorData) public; in the interface but it doesn't appear in the function descriptions below. Perhaps it was meant to be replaced by operatorSend but you forgot to delete it from the interface?

MicahZoltu commented 6 years ago

I recommend splitting function authorizeOperator(address operator, bool authorized) public; into:

function authorizeOperator(address operator) public;
function revokeOperator(address operator) public;

At the callsite, this will provide a lot more clarity as to what is happening.

bwheeler96 commented 6 years ago

This is rad. Its going to be a long, slow journey to move away from ERC20 but this is a good first step. Couple things:

  1. Why has spender authorization been moved to a boolean? I personally haven't found a use-case for allowing a spender to access a specific amount, but it seems like a nice feature to have since its already part of an existing standard.
  2. Why use the noun operator? I understand this is stupid-picky and certainly hair-splitty, but the work spender is, IMO, a really good descriptor of that particular actor. Operator just sounds like the person has more capability than they do (they aren't really "operating" on the tokens).

Anyways, big 👍. ERC20 needs an upgrade.

nepalbitcoin commented 6 years ago

Public state variable for decimal is string public decimals;? I think that should be uint8 public decimals; based on function decimals() public constant returns (uint8). Prolly a typo.

GoldenDave commented 6 years ago

As I have mentioned in other threads, I strongly recommend removing decimals. Here is a cross post of what I have said elsewhere:

Unfortunately quite a few coins have a very good reason for selecting a different number of decimals. Many of them are in the wild already. Forcing all 10 n decimals would require internal restrictions that would, for example, force rounding of values or revert if an incorrect amount is specified.

Our objective is seldom to expect people to interact directly with the blockchain but, as an example, MEW does a good job of removing the decimal confusion.

alexvandesande commented 6 years ago

Should the ITokenRecipient contract also have a function that always returns true stating it's capable of this? It's a way to allow wallet implementers to know which function to use, and therefore save gas.

function isITokenRecipient() returns (bool) { return true};
lyricalpolymath commented 6 years ago

Great stuff!

1- initially I too thought as @sohkai that authorizeOperator() would need a form of limiting the amount. In the end the ERC20 approve (which is a confusing name) does have a value up to which the spender is allowed.

I understand and share what you say

The idea o authorizeOperator is mainly to authorise a contract. The maximum allowed limitation and many others limitations, like a daily limits, should be implemented in the operator contract and keep this standard as clean as possible

But I also think that it's an interesting addition to remind implementers to include optional limitation logic.


2- operatorSend userData vs operatorData what is the scenario you are imagining for userData? in any case it's a data that the operator has to input when calling the operatorSend function. Why couldn't both data points be contained in one?


3- Backwards Compatibility I also found this a bit confusing

The only difference for new contracts implementing ERC20 is that registration of ITokenRecipient via EIP-672 takes precedence over ERC20. This means that even with on a ERC20 transfer call, the token contract MUST check via EIP-672 if the to address implements tokensReceived and call it if available.

I understand that new smart contracts will detect the right function to call (right?) but what about users interacting directly with the contract? It will be confusing to see 2 functions that supposedly do more or less the same thing but have different names. confusing UX and a potential source of problems if you say that "tokens will probably be locked"

jbaylina commented 6 years ago

@lyricalpolymath
3- New contracts that use new tokens must use send() and not transfer(). transfer() is just for backwards compatibility. mainly old smart contracts, as I expect that UI will be upgraded at some point. Stay tunned for (1 & 2)

jbaylina commented 6 years ago

@alexvandesande To know if a contract implements ITokenRecipient, the reverseENS is used (EIP672) which will never throw and you will know if it implements or not the Interface. The gas cost should be the same as the one you propose.

MicahZoltu commented 6 years ago

@GoldenDave Others have made the same argument in the past but were unable to provide (IMO) a compelling argument as to why forcing the humanizing divisor to the same for all tokens is bad. The most common cited example is "what if I have a token that is pegged to USD (or similar), which only has 2 decimals?" In this case, you can still have 24 decimals (or whatever the standard defines) exposed to the user and the contract can internally store however it likes. In this case, you would simply multiply whatever internal value you have by 10^22 when it is returning to the user. In all cases I have seen people come up with (including the USD peg) nothing is hurt by having a token be more divisible. There is really nothing fundamentally wrong with having 1 attousd.

alexvandesande commented 6 years ago

@jbaylina I support reverse ENS, but I don't see why not also add this to the contract itself. Is simpler to build, will work on any network, including test networks etc. Also, to check ens resolver you need to have multiple calls (see if there's a resolver, then check the resolver etc) AND to have an extra function on the constructor function to set the ens resolver info.

Again, I'm all for ENS, but why not add on the contract simple info like that? Reminds me of the debate on either tokens should have symbol and names on the contract or on a token registry: in contract won by the simplicity of it.


Also: I'd like to propose to add a provable standard to this token. One of the most requested features I get from token creators is how to send tokens without having ether and I think it makes sense that should be a core function of whatever is the next big token version.

DaveAppleton commented 6 years ago

Others have made the same argument in the past but were unable to provide (IMO) a compelling argument as to why forcing the humanizing divisor to the same for all tokens is bad.

During the HelloGold token sale, contributors received HGT which entitled them to a share of a reward token GBT (our gold backed token) which is related to the amount of management fees that we receive for storing clients' gold pro rated to the person's HGT holding.

In order that anybody holding the minimum amount of HGT should receive GBT during a distribution we calculated that GBT would work with 18 decimals but as a result HGT would need to have 8 d.p. Any more precision would be pointless and misleading.

It it rather dictatorial to say that everybody needs to normalise everything to meet a number of decimal points that do not particularly agree with them, especially when we already have a method of handling it.

DaveAppleton commented 6 years ago

Should the ITokenRecipient contract also have a function that always returns true stating it's capable of this? It's a way to allow wallet implementers to know which function to use, and therefore save gas.

It is great idea - but when I ran a quick test on remix, a contract with a simple fallback function would falsely satisfy your requirements.

function(){
}

appears to return true when a non existent function xyz() returns (bool) is called.

https://gist.github.com/DaveAppleton/ef44e9745b1f57c7ae0d6744a15bc5c6

jbaylina commented 6 years ago

@alexvandesande One of the nicest think of this standard is that not only you can have functionality in smart contract recipients, but also in any regular account. You can program for examle that you don't accept tokens sent to your public regular account. Or that you send half of it to a charity. I agree that using EIP672 is a little complicated, and what's the worst, ENS still is centralised in some way. So that is why we plan to use EIP https://github.com/ethereum/EIPs/issues/820 which is equivalent to EIP672 but much more simpler and pure decentralised contract. (It still is a work in progress).

jbaylina commented 6 years ago

@alexvandesande Regarding the provable functionality, the idea is to do that via an operator. The operator can, for example, accept signed checks, which they are very much provable transfers.

This standard should allow for token contract creators to set some default operators to be authorised for everybody.

alexvandesande commented 6 years ago

@DaveAppleton I just tested your code and got

{
    "0": "bool: false"
}

So it seems it should work.

GoldenDave commented 6 years ago

Remix or testnet?

Maybe remix is not the best playground.. image

alexvandesande commented 6 years ago

@jbaylina I like the approach of using the approved operator for that sort of thing.

Regarding EIP672 or 820, I don't like the idea of requiring any registry contract: these will change depending on the network, the wallet must be aware of them and makes the whole code a lot less reusable. I would simply support introspection in the contract itself, it's literally one line function and adding support for registering yourself on the register will certainly be more than that. I like having registry of addresses with more information, just don't like having to rely on them.

If you don't like hasTokenFallback then we can add a more general hasSupportFor() function. But I'd keep it simple.

jbaylina commented 6 years ago

@alexvandesande 1.- How would you associate a piece of code to a regular account? I don't see any other way than a registry contract (ENS or notENS). EIP820 is very interesting because it allows to execute a code every time that tokens are received. Even if the destination is a regular account. For example, you can prevent receiving tokens, or send some of the tokens to a charity. Using EIP-165, which is more or less what you propose, does not allow to define any code for regular accounts. 2.- In the other side, I would like to highlight an incredible way that @Arachnid showed to me on how deploy EIP820Registry like contracts.
The idea is that you create a deployment transaction. you change the signature to a deterministic value, for example 0xAAAAAAAA.... From this signature, you recover the address that would have generated the transaction. Of course you don't know the private key of that address, but you can send Ether to that address and then just broadcast the transaction!! This method, you can create the registry in any blockchain and you know for sure that the address will be the same in all the chains. You can see the implementation of this here: https://github.com/jbaylina/eip820/blob/master/js/deployment.js
It works! This exciting technique is a great way to deploy any "Pure decentralised" contract. An applause to @Arachnid please !!!.

MrTibbles commented 6 years ago

@Arachnid 👏 👏 👏

nagydani commented 6 years ago

Now that we have all those nice cryptographic primitives in EVM that allow for untraceable tokens, it would be reasonable to create a token standard that would actually support untraceable tokens. In order to do so, the transfer of tokens that currently both debits the payer account and credits the beneficiary account in the same transaction needs to be separated into two steps:

This means that the sum of all balances will no longer be equal to totalSupply, but rather less or equal. The difference (that perhaps merits a separate accessor/query function such as inTransition) would be tokens in transition, i.e. ones that have already been withdrawn from payer accounts, but not yet deposited to beneficiary accounts. In practice, if people care about privacy, the majority of funds will be in this state.

The actual amounts that can be withdrawn and deposited should be restricted to a small set of possible values so that transactions cannot be linked by amounts. However, this restriction does not need to be part of the standard, it is up to each token to implement their version.

alexvandesande commented 6 years ago

I agree Daniel, but I feel it could be a separate standard that tokens can also adhere to

On Tue, Jan 9, 2018 at 11:32 AM, Daniel A. Nagy notifications@github.com wrote:

Now that we have all those nice cryptographic primitives in EVM that allow for untraceable tokens, it would be reasonable to create a token standard that would actually support untraceable tokens. In order to do so, the transfer of tokens that currently both debits the payer account and credits the beneficiary account in the same transaction needs to be separated into two steps:

  • withdraw: debiting the payer account and turning some piece of information into a valid off-chain token
  • deposit: crediting the beneficiary account, if a valid off-chain token has been supplied to it.

This means that the sum of all balances will no longer be equal to totalSupply, but rather less or equal. The difference (that perhaps merits a separate accessor/query function such as inTransition) would be tokens in transition, i.e. ones that have already been withdrawn from payer accounts, but not yet deposited to beneficiary accounts. In practice, if people care about privacy, the majority of funds will be in this state.

The actual amounts that can be withdrawn and deposited should be restricted to a small set of possible values so that transactions cannot be linked by amounts. However, this restriction does not need to be part of the standard, it is up to each token to implement their version.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/ethereum/EIPs/issues/777#issuecomment-356284635, or mute the thread https://github.com/notifications/unsubscribe-auth/AAG5AqHi3dICQDFifkJEKJqePyFKdTh2ks5tI2qKgaJpZM4Qk-RG .

-- Alex Van de Sande Lead Designer Ethereum Mist Team

frozeman commented 6 years ago

I really love this standard @jbaylina, as it takes the good of #223 and makes it more clear, also due to the new function names. At the same time it can is backwards compatible.

One note: i would rename isOperatorAuthorizedFor(..) to isOperatorFor(...) to make it more concise, as Operator already implies that its operating in somebodies name.

alexvandesande commented 6 years ago

@nagydani actually a testimony on how flexible is the operator model, this could make so that any ERC777 coin would be automatically untraceable if so desired: you can add a ring signature mixer as an approved operator, and then it will automatically transfer coins to itself and out.

alexvandesande commented 6 years ago

@jbaylina I'm still unsure about using an external registry: I tried to understand how that worked on the Yoga token example but it's rather complex and not very obvious. Do you have a short gist showing an example of a constructor function that self-registers a token on a registry, without requiring the token to have 'owners' and such?

nagydani commented 6 years ago

@alexvandesande could you elaborate a bit on this? The simplest example would involve four participants (Alice, Bob, Carol, Dave), with Alice and Bob each sending a coin and Carol and Dave each receiving a coin, but it should be impossible to tell whether it was A→C, B→D or A→D, B→C. BTW, separating the debit and the credit parts of a transfer transaction might come handy with Ethereum 2 as well: there, if the two addresses are on different fibres, you cannot do anything else anyway.

AnthonyAkentiev commented 6 years ago

+1 to removing 'decimals' (set it to some default value, like 18))

alexvandesande commented 6 years ago

@nagydani Alice authorizes "mixerContract" as an operator for her tokens. Alice signs a message creating some off chain information and sends it (directly or via someone else) to the MixerContract, which then removes all coins from her account. Alice sends some information to Bob, off chain, and Bob provides this to the MixerContract (maybe via Carol), which now credits Bob with the tokens. From the outside, nobody can tell if Bob's coin came from Alice, Carol or Dave. All code was done on the MixerOperator, not the coin itself.

mcdee commented 6 years ago

Any reason that the events have mixed tense? Send is current tense butRevokedOperator is past tense. There would be less mental confusion if only one tense was used for all event names.

mcdee commented 6 years ago

NOTE: The decimals value returned SHOULD be 18.

Not a fan of this, unless you can give a solid reason why it should be 18. Reasons that don't wash include:

devzl commented 6 years ago

+1 to removing 'decimals' (set it to some default value, like 18))

A standard shouldn't be opinionated and lock you in a way of doing things. The decimal value should be up to the user's needs and situation, and be their to decide.

bwheeler96 commented 6 years ago

@mcdee I think there will be more user confusion when someone trades 10 ETH for 0.001 ABC token because an exchange listed the "decimals" value incorrectly and it looked like they were getting 10,000 ABC.

Let's be real, most users aren't checking the difference between 0xde0b6b3a7640000 and 0x38d7ea4c68000 in their transaction data. Standards like this make life easier for users, and for developers (us).

Do you have a valid and general use-case for fewer or greater decimals than 18? I'm open to hearing new arguments, but to me this standard makes sense for 99% of cases, and for the 1% there are plenty of elegant solutions.

mcdee commented 6 years ago

...an exchange listed the "decimals" value incorrectly...

If the exchange bothered to read the decimals value from the chain this wouldn't happen. Suggesting that reading this value is somehow to onerous for the exchange to handle, or too complex for them to handle correctly, doesn't seem particularly realistic.

Let's be real, most users aren't checking the difference between 0xde0b6b3a7640000 and 0x38d7ea4c68000 in their transaction data. Standards like this make life easier for users, and for developers (us).

Saying that a value "should" be a particular figure is the worst of all worlds. It isn't definitely a given value, so no assumptions can be made, but gives the impression that it will be a given value, so assumptions will be made.

Do you have a valid and general use-case for fewer or greater decimals than 18? I'm open to hearing new arguments, but to me this standard makes sense for 99% of cases, and for the 1% there are plenty of elegant solutions.

https://github.com/ethereum/EIPs/issues/724 hashes all of this out and provides examples of situations where decimals other than 18 are in the wild, but the general use case is a token that has a specific divisibility. 0 is the most obvious one i.e. an indivisible token.

What I haven't heard is any good reason for restricting decimals to a fixed value, or giving one value prominence over another (the only one that holds any water is the offline/hardware situation, but given that the symbol of the token is required anyway for the transaction to be contextualised the argument is weak). @MicahZoltu is the strongest proponent for removing decimals entirely but given that the comment in which he proposes this has three options for decimals, each with a valid reason as to why they might be chosen, should show that a single value doesn't fit all use cases.

MicahZoltu commented 6 years ago

To be clear, I would rather "keep decimals" than have decimals be SHOULD. I think specs should take hard-line stances and not be vague whenever possible.

Please remember that decimals is a humanizing multiplier. Since it is not possible to predict the future value of your token, and tokens will fluctuate in value relative to each other, all tokens will at some point need to use SI prefixes in order to display them meaningfully to humans. Believing that you can pick a number in advance such that your token will always render in a human friendly way (for all of time) is naive.

Since we must accept that all tokens will need SI prefixes at some point in time, my argument is to just remove one more piece of complexity from future tokens that doesn't add any meaningful value.

MicahZoltu commented 6 years ago

Also, I do think there is value in being able to render the number of tokens in an offline signer even if you don't have the symbol. Being able to say

Transferring 15.6 gigatokens of 0xabcd token

is significantly better than

Transferring 15600000000000000000000000000000000 indivisible units of 0xabcd token

MicahZoltu commented 6 years ago

Regarding the "indivisible token" argument, there are a few options:

  1. Use SI prefixes like everyone else and people will just buy/sell 1 yoctotoken or 1 attotoken rather than 1 gigatoken like they do with some others.
  2. Make it so your token transfer either rounds or throws when people try to transfer sub-tokens.
  3. Allow for token divisibility for the sake of transferability, but round down to nearest "1 token" when using the token for whatever it is the token is used for that requires "whole" units.

Side note: I'm curious for what the use-case is for indivisible fungible tokens. I'm struggling to come up with a scenario where you want to target your humanizing factor to be around the size of an indivisible token, but you also want them to be fully fungible (meaning tokens don't represent non fungible physical assets or something). In the case of digital gold or USD pegged tokens, divisibility beyond that of the underlying asset is still valuable for trading, it just means that when a user wants to redeem a token for 1 gold bar or 1 USD they must supply tokens in whole increments. However, I see no problem with people trading less than 1 bar of gold or less than 1 USD otherwise (this argues for option 3 above).

mcdee commented 6 years ago

Since we must accept that all tokens will need SI prefixes at some point in time

Must we? What about a token that represents a right to use (for example a software license)? It can be both indivisible and fungible, and its price will naturally float to a reasonable value (in ETH or USD, depending on prevalence) rather than suffer significant speculation (especially if the token has an uncapped total supply).

Note I'm not saying that the above is definite, but it is possible, and the standard should accommodate such situations.

In the case of digital gold or USD pegged tokens, divisibility beyond that of the underlying asset is still valuable for trading

Only if the token creator is happy with divisibility beyond that of the underlying asset. They may be, they may not be, Again, it should be a choice and the standard should allow that choice to be made and easily visible to end users.

I think we are agreed, however, that regardless of where decimals ends up the current use of should is a bad idea.

jbaylina commented 6 years ago

@MicahZoltu, @mcdee, @alexvandesande, @bwheeler96 Every time I am more convinced that the decimals() and SHOULD is not the best idea. (You are all convincing me)

Before going forward, let me just clarify two concepts that I think we are mixing:

We have to distinguish between basicUnitand minimalUnit
basicUnit would be the number of weis that correspond to the basic Unit. (10^18 in the case of Ether). This is equivalent to 10^decimals . minimalUnit would be the number of weis of the smallest divisible part. (1 in the case of Ether).

So here are the options for the standard:

  1. define basicUnit() and minimalUnit() methods and let the token creator chose the values freely. This is the most flexible option.
  2. recommend basicUnit() to 10^18 and do not talk about minimalUnit(). This is the actual implementation as decimals() is equivalent to basicUnit().
  3. force basicUnit() to 10^18 and do not talk about minimalUnit(). This case would be the same that removing the decimals() from the standard and change the SHOULD be 10^18 for a MUST be 10^18 (This is the option propose by @AnthonyAkentiev )
  4. Do not talk about basicUnit() nor minimalUnit() at all in the specification. That is do not talk about decimals and let the token creators do what they want. (The easiest way to reach a consensus is to consensuate that there is no consensus :) )
  5. force basicUnit() to 10^18 and define minimalUnit() letting the token creator to chose the value freely.
  6. force minimalUnit() to 1 and define basicUnit() letting the token creator chose the value freely.

I would like to hear you opinion on a range from 0 to 10 on each point:

Scale: 10->The best option
8 -> A good option 6 -> I would just accept it 4 -> I would not accept it. 0 -> This is an authentic disaster option.

Here is my score: 1-> 8 2-> 6 3-> 7 4-> 5 5-> 9 6-> 6

Of course fill free to add other options if you think they are better.

AnthonyAkentiev commented 6 years ago

@jbaylina We have a real case DApp that we developed: ethlend.io Every time we need to pass token amount from DApp to the LendingRequest contract or from coinmarketcap through the Oraclize -> we have to deal with different decimals value.

Everything becomes more complicated with decimals) However, I think that option 5 above is a good choice.

Thank you for providing awesome list of options.