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

NEP: Token Standard #4

Merged
merged 37 commits into from
Oct 9, 2017
Merged

Conversation

lllwvlvwlll
Copy link
Member

No description provided.

Copy link

@M-L-A M-L-A left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, able to execute on the testnet. Fully working NEP5 template.

lllwvlvwlll added 2 commits August 12, 2017 21:02
@erikzhang
Copy link
Member

Do we really need the methods (transferFrom, approve, allowance) from ERC20?

@erikzhang erikzhang mentioned this pull request Aug 13, 2017
@lllwvlvwlll
Copy link
Member Author

lllwvlvwlll commented Aug 13, 2017

They allow you to transfer funds on behalf of someone else which can be pretty valuable.

Use case: Ability for people to set up 'joint' accounts where two users share access to the tokens in the contract while retaining their own distinct accounts.

Use case: It could also be used as an interface mechanism for systems to interact with the tokens on behalf of someone else. A user would 'allow' an application to access their tokens/data.

@Arbio5zt
Copy link

Very pretty document! I have 3 suggestions and you can consider about.

  1. Deploy function.
    I think the deploy function should not be the standard token function, it will depends on the specific business needs. Maybe someone need to set the ico start/end time, maybe need to set exchange rate. etc. so I think we should not control it in the protocol.

  2. methods (transferFrom, approve, allowance)
    As ERC-23(ERC223 token standard ethereum/EIPs#223) has removed these functions, so i also think retaining these methods will seems much complicated and the recent ICO seems have no use of these methods. Should we also remove them?

  3. originator
    I noticed that the ‘originator’ defined as a required parameter of every function, some function such as totalSupplynamesymboldecimalsbalanceOf , i think it should be public and there is no need to verify the sender. if we have neoscan(like etherscan) later, it can be very convenient to query these public methods. so i think where need to verify where to add check of originator is better.

finally, @erikzhang , i think we also need Function signature description file just like ethereum's ABI file ,which will generate when compile the smart contract, with this, the client will be very easy to support Various applications.

@lllwvlvwlll
Copy link
Member Author

@luodanwg

  1. I agree, There are many mechanics by which people will want to deploy the contract so it should not be part of the standard.

  2. As mentioned in the previous comment, I believe we should keep the delegated transfer functions because they allow for some potential user - application interaction that cannot easily exist otherwise.

  3. I agree with this as well.

@Arbio5zt
Copy link

another suggestion.
NEO is support runtime.notify func to notify the client some events. So i think we can also add the notify when Transfer or Approval is completed.

@erikzhang
Copy link
Member

Maybe we can mark some methods as "optional".

@lllwvlvwlll
Copy link
Member Author

Optional method and Runtime.notify() have been added to all 'authenticated' methods.

@erikzhang
Copy link
Member

What is the use of "NotifyOriginator"? Why don't we just add a "transferred" event?

nep-5.mediawiki Outdated

==Motivation==

As the NEO blockchain scales, Smart Contract deployment and invocation will become increasingly important. Without a standard interaction method, systems will be required to maintain a unique API for each contract, regardless of their similarity to other contracts. Tokenized contracts present themselves as a prime example of this need because their basic operating mechanism is the same. A standard method for interacting with these tokens relieves the entire ecosystem from maintaining a definition for basic operations that a required by every Smart Contract that employs a token.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grammar

A standard method for interacting with these tokens relieves the entire ecosystem from maintaining a definition for basic operations that a required by every Smart Contract that employs a token.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you edit it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, PR submitted to lllwvlvwll's repo.

@lllwvlvwlll
Copy link
Member Author

can we approve and Merge this?

@erikzhang
Copy link
Member

We still need more tests for its implementations.

@saltyskip
Copy link
Contributor

I wonder on usage of the wording "account" rather than "address" when referring to transferring funds in this document. Account implies a higher level Object than what is actually being used, and I think is a point of confusion for many developers when they begin to mix the concept of an address with the concept of an account. In blockchain projects I would typically think of an account as the combination of all relevant public and private keys (WIF, pubkey, privkey, address).

In summary think it would be more clear to refer to the byte array parameters in this document as addresses rather than accounts (which I argue is a more true representation of what they actually are). Thoughts?

@erikzhang
Copy link
Member

Token Standard ABI:

{
  "functions": [
    {
      "name": "totalSupply",
      "parameters": [],
      "returntype": "Integer"
    },
    {
      "name": "name",
      "parameters": [],
      "returntype": "String"
    },
    {
      "name": "symbol",
      "parameters": [],
      "returntype": "String"
    },
    {
      "name": "decimals",
      "parameters": [],
      "returntype": "Integer"
    },
    {
      "name": "balanceOf",
      "parameters": [
        {
          "name": "account",
          "type": "Hash160"
        }
      ],
      "returntype": "Integer"
    },
    {
      "name": "transfer",
      "parameters": [
        {
          "name": "from",
          "type": "Hash160"
        },
        {
          "name": "to",
          "type": "Hash160"
        },
        {
          "name": "amount",
          "type": "Integer"
        }
      ],
      "returntype": "Boolean"
    }
  ],
  "events": [
    {
      "name": "transfer",
      "parameters": [
        {
          "name": "from",
          "type": "Hash160"
        },
        {
          "name": "to",
          "type": "Hash160"
        },
        {
          "name": "amount",
          "type": "Integer"
        }
      ]
    }
  ]
}

@neotracker
Copy link

It would be nice if we also had a standard set of functionality for ICOs (at least an ABI). https://github.com/neo-project/examples-csharp/blob/master/ICO_Template/ICO_Template.cs is a good start, but it'd be good if it could expose things like ico_start_time and ico_end_time. Not part of this proposal of course, but this seemed the most relevant so commenting here.

@lllwvlvwlll
Copy link
Member Author

@erikzhang we should also consider a 'listMethods' method which returns the definition for each supported method in the contract.

@erikzhang erikzhang merged commit fb19052 into neo-project:master Oct 9, 2017
@Ejhfast
Copy link

Ejhfast commented Oct 27, 2017

@Dexaran @erikzhang removing approve and transferFrom requires the NEP-5 SC transfer method to call tokenFallback on receiver contract, is that correct? given that NEO requires that all outside SC contract calls be declared in advance for a contract, it does not seem possible for NEP-5 tokens to transfer to arbitrary contracts in NEO? (you would need to declare all possible contracts the NEP-5 token SC would communicate with in advance?)

can you explain more? perhaps I am missing something

either way, the tokenFallback behavior is not specified by the finalized NEP-5 right now. if the goal is to work like ERC223, this needs to be added. or if such behavior is not possible to support with NEO, we should make approve, transferFrom, and allowance required.

@Dexaran
Copy link

Dexaran commented Oct 27, 2017

Alright, I'll try to give a brief explanation.

How it works with Ether. Fallback function and payable modifier.

As for Ethereum contracts and solidity, there is a fallback function that is executed whenever the call transaction does not provide a signature that matches any of the signatures of the functions implemented in this contract. Read solidity docs for more detailed description. There is a special payable modifier that allows a function of a contract to receive funds (Ether). You can not deposit any Ether into contract that is not specially designed to receive Ether. The transaction will always fail if the function that is executed is not marked as payable.

If you want to create an Ethereum contract that will accept Ether deposits, you must explicitly declare a deposit function or a fallback function and use the payable modifier. Example:

contract Receiver_of_Ether
{
    function() payable
    {
        // fallback function allows to deposit Ether to this contract.
        // payable modifier is required.
    }
}

This is specially done to prevent the accidentally sent Ethers being stuck inside contracts. If the contract is not explicitly allowed to receive funds then any attempt of depositing Ether will fail and the funds will not be transferred to the contract (the funds will remain at user's balance).

Rationale. Preventing user mistakes and losses of money.

We should keep in mind that not all users are technically advanced and some of them will try to send Ether into contracts by mistake. This is a reasonable protection from the most common user mistakes that could lead to disasterous consequences and millions of dollars lost.

How it works with ERC223 tokens.

I followed this approach when developing the ERC223 standard. I think the contract should explicitly declare that it is specifically designed to receive tokens if it is going to receive tokens. Otherwise, it must reject token deposits by default. This is analogue of how it works with Ether.

As for Ether, contract must implement a fallback function with payable modifier to receive Ether.
As for tokens, contract must implement a tokenFallback function to receive tokens. If the contract does not implement it, then any attempt to deposit (Ether or tokens) must fail.

contract Receiver_of_Tokens
{
    function tokenFallback(address,uint256,bytes)
    {
        // tokenFallback function allows to deposit tokens to this contract.
        // no payable modifier, we do not allow user to deposit ETH, but only tokens.
    }
}

It must not be possible to transfer tokens to a contract that is not designed to receive them (that does not implement a special tokenFallback function or any other function that you agree to use as token transfer handler. The function name does not seem to be essential here).

Mistakes of ERC-20 standard and why a contract MUST explicitly declare that it is designed to receive funds.

Unlike ERC-223 transfers or Ether transactions, ERC-20 transfer function does not require a receiver to implement a special function for it. A user can just send ERC-20 tokens to any address he wants. As a result, contracts that are not specifically designed to work with tokens (for example, ENS contracts and token contracts themselves) constantly receive tokens that are accidentally sent.

These tokens become stuck inside contracts without any possibility to recover them. In other words, users lose their tokens (money) this way.

Event handling is a common practice in programming. Transaction should be considered an event and it should be properly handled. ERC-20 lacks this transaction handling mechanism at all and this is a known problem of ERC20 standard.

It already results in lost money (you can read about it here, here and here ). The last time I checked it, there were about $400,000 lost in stuck ERC-20 tokens. It was a long time ago, and I believe that we are talking about millions of dollars lost at the moment.

@Ejhfast
Copy link

Ejhfast commented Oct 27, 2017 via email

@Dexaran
Copy link

Dexaran commented Oct 27, 2017

I'm not really familiar with NEO. I can only describe how it works on Ethereum and why.
As for NEO, I can highlight key points of the token standard:

  1. You must disallow token deposits to contracts that are not explicitly designed to receive tokens.

  2. Token deposits to contracts and deposits to addresses should behave differently.

  3. You must implement a mechanism of transaction handling. This will allow to "do something on incoming token transfer".

  4. Designing a couple of different functions to perform transfers to contracts and transfers to addresses is an antipattern. Someone will obviously choose the wrong way (a user will call depositToAddress when depositing into contract hence he will lose money).

As for approve and transferFrom it's the point 4: a couple of two different functions to make deposits. transfer for deposits to addresses. approve + transferFrom for deposits to contracts. If you chose the wrong way, then you lose your money.

@Ejhfast
Copy link

Ejhfast commented Oct 27, 2017

thanks for taking the time @Dexaran! i do agree with your critique of ERC20

my point in raising this comment is that NEP5 is not following ERC223 in its current state, and possibly, can't follow it right now given differences between NEO and ETH. my understanding is that NEO smart contracts require that any calls between SCs to be declared statically within the contract that will do the calling. this has potential scalability benefits but may prevent a direct reimplementation of ERC223.

maybe @erikzhang can look at the above and comment further

@Ejhfast
Copy link

Ejhfast commented Oct 28, 2017

@erikzhang an update on this:

@localhuman has confirmed with me that dynamic SC calls (calls between SCs that are not statically declared) are not allowed on the NEO VM. this means that ERC223 is currently not possible (a token needs to do a dynamic call on the receiver contract)

it is very important that NEP-5 tokens are powerful enough to support the behaviors specified by either ERC20 or ERC223. among the many other applications, decentralized exchanges will not work without these features. as it stands, unless a token implements the optional methods in this NEP-5, it is impossible to send it to another SC and have that SC do meaningful work on your behalf

we would recommend:

(1) enabling dynamic SC calls: this would be a simple change in the VM, there is a lot of other low hanging fruit for performance before we get to sharding VM resources. there could also be something like a dynamic flag that indicates whether dynamic SC calls are used in a contract, to preserve scalability benefits for simpler contracts

(2) more critically, make NEP-5 fully compliant with either ERC20 or ERC223. the tokens are not powerful enough for basic functionality right now

in summary, (1) is important but (2) is absolutely necessary. it will be very bad if the ecosystem grows using the current version of NEP-5

@canesin
Copy link

canesin commented Oct 30, 2017

@luodanwg can you bring this issue to Zhengwen attention ? I think @Ejhfast will do a PR for NEP5 Amendment with (2) making it fully compliant with ERC-20. Rgds.

@erikzhang
Copy link
Member

An important difference between Ethereum and NEO is that: in NEO, you can combine multiple invocations into one transaction, and ensure transaction consistency.
That means, you don't need a trigger to call tokenFallback automatically. You can call everything you want in InvocationTransaction.

@Ejhfast
Copy link

Ejhfast commented Nov 2, 2017

@erikzhang if that is possible, it needs to be specified in the protocol, otherwise for all practical purposes NEP5 tokens are broken and will not be able to interact with SCs in interesting ways (lacking equivalent functionality to ERC223)

also, in terms of whether it is possible, some of this logic needs to be conditional. for example, transfers should happen conditionally on the existence of tokenFallback in the receiver contract, and I am not sure how this happens using the technique you propose. from the ERC223 docs: "If the tokenFallback function is not implemented in _to (receiver contract), then the transaction must fail and the transfer of tokens should not occur."

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

Successfully merging this pull request may close these issues.

10 participants