Skip to content
Denis Bogdanas edited this page Sep 19, 2018 · 8 revisions

This page describes the issues found in ERC777 standard, while developing the ERC777-K, the formal ERC777 semantics in K Framework.

Discrepancies between standard and reference implementation

We found some discrepancies between the current standard and the reference implementation:

Ambiguity in standard

Ambiguous "MAY" behaviors of authorizing (or revoking) an already authorized (or revoked, resp.) operator

The standard says:

A token holder MAY authorize an already authorized operator.

A token holder MAY revoke an already revoked operator.

The term "MAY" is ambiguous. Below is the list of some possible interpretations of the term, which we asked the developers to confirm:

A standard-conforming token implementation can:

  1. always accept when a token holder attempts to authorize an already authorized operator.
  2. always revert when a token holder attempts to authorize an already authorized operator.
  3. randomly choose, either accept or revert, whenever a token holder attempts to re-authorize. (fully non-deterministic)
  4. always revert for some specific token holders attempting to re-authorize, but always allow for another specific token holder attempting to re-authorize.
  5. or more chaotic way of deciding whether to accept or revert. (here "chaotic" means some combination of deterministic and non-deterministic choices, like (3), which is different to the fully non-deterministic choice, like (2).)

Probably, we guess they may intend either:

  • allow the fully non-deterministic decision, or
  • let them choose either (0) or (1), in advance, and keep the same decision throughout the token contract lifetime.

FIXED:

It turned out that the standard authors intend (0), that is, the standard should have said as follows:

A token holder "MUST" authorize an already authorized operator.

A token holder "MUST" revoke an already revoked operator.

(i.e., MUST instead of MAY)

Ambiguous "SHOULD" behavior of sending to a regular address that doesn't register a ERC777TokensRecipient hook

In case of sending to a regular address that doesn't register a ERC777TokensRecipient hook, the table in (the end of) the standard says it "SHOULD accept", but it is not clear what it precisely means.

Below are possible interpretations:

  • It allows each implementation can choose a fixed behavior (either accept or revert) for all such cases.
  • Or, it allows each implementation can have a finer-controlled decision, e.g., accepting for some white-listed addresses, and/or reverting for some bad (or definitely-non-existing) addresses.
  • Or, it allows a even more sophisticated policy, e.g., accepting up to N times for some set of addresses, M times for another set of addresses, etc.
  • Or, extremely, it allows any arbitrary non-deterministic decision (e.g., decision by flipping a coin).

CLARIFIED:

It turned out that the standard authors intend the full non-deterministic behavior.

They answered:

all of those scenario would be acceptable

Ambiguities regarding the operator 0x0

Multiple ambiguous behaviors regarding the operator 0x0.

Q1. What should be isOperatorFor(0x0, 0x0)? true or false? Or, implementation-dependent?

Based on the following statement in the standard, it should be true, but it may not be intuitive to have 0x0 be an operator even for itself.

An address MUST always be an operator for itself.

However, one can still argue that it is OK to allow the operator 0x0 be an operator for some addresses, since there is no case where operatorSend (or operatorBurn/Mint) is called by the address 0x0. The benefit of doing this is that we can have a simpler definition of isOperatorFor and authorize/revokeOperator in the (formal) standard. Another argument for not having the special treat for the operator 0x0 is that there are other non-existing addresses that we may not want to allow to be the operator, and it is not clear why we need to treat 0x0 differently from the other non-existing addresses.

A1. ???

Q2. Is operatorSend(0x0, ...) simply an alias to operatorSend(msg.sender, ...)?

A2. YES

Q3. What's the behavior of authorizeOperator(0x0) and revokeOperator(0x0), among the following?

  • MUST accept
  • MUST revert
  • implementation-dependent

A3. "MUST revert"

Even if there is no case where the operator 0x0 calls the operator* functions, allowing authorize/revoke the operator 0x0 would lead to an usability issue especially when a client passes 0x0 to authorizeOperator or revokeOperator by mistake, for example, he may pass an uninitialized variable, or a null value returned by another function (e.g., signature computation) due to some internal failure.

Inconsistencies

  1. decimals()

Hence for compatibility reasons, decimals MUST be implemented for ERC20 compatible tokens.

vs

The token MAY implement decimals() for backward compatibility with ERC20. If implemented, it MUST always return 18.